From a3111e4d9c2719956436b0ebffcdbdf52b6501f6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:14:11 -0400 Subject: [PATCH 001/300] fix(deps): update dependency webpack to v5.88.1 (#11764) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 4460c9aa05..5aa0ba97f4 100644 --- a/install/package.json +++ b/install/package.json @@ -143,7 +143,7 @@ "tinycon": "0.6.8", "toobusy-js": "0.5.1", "validator": "13.9.0", - "webpack": "5.88.0", + "webpack": "5.88.1", "webpack-merge": "5.9.0", "winston": "3.9.0", "xml": "1.0.1", From 2791eb8aac64ef2fa77178cefebc232f86fa1a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 28 Jun 2023 20:55:01 -0400 Subject: [PATCH 002/300] fix: group membership methods for guests/spiders add tests to cover different combinations --- src/groups/membership.js | 13 ++++-- test/groups.js | 96 ++++++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/groups/membership.js b/src/groups/membership.js index f37853d433..66af1c1ed1 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -25,7 +25,7 @@ module.exports = function (Groups) { Groups.isMember = async function (uid, groupName) { if (!uid || parseInt(uid, 10) <= 0 || !groupName) { - return false; + return isMemberOfEphemeralGroup(uid, groupName); } const cacheKey = `${uid}:${groupName}`; @@ -43,8 +43,8 @@ module.exports = function (Groups) { return uids.map(() => false); } - if (groupName === 'guests') { - return uids.map(uid => parseInt(uid, 10) === 0); + if (groupName === 'guests' || groupName === 'spiders') { + return uids.map(uid => isMemberOfEphemeralGroup(uid, groupName)); } const cachedData = {}; @@ -64,7 +64,7 @@ module.exports = function (Groups) { Groups.isMemberOfGroups = async function (uid, groups) { if (!uid || parseInt(uid, 10) <= 0 || !groups.length) { - return groups.map(groupName => groupName === 'guests'); + return groups.map(groupName => isMemberOfEphemeralGroup(uid, groupName)); } const cachedData = {}; const nonCachedGroups = groups.filter(groupName => filterNonCached(cachedData, uid, groupName)); @@ -82,6 +82,11 @@ module.exports = function (Groups) { return groups.map(groupName => cachedData[`${uid}:${groupName}`]); }; + function isMemberOfEphemeralGroup(uid, groupName) { + return (groupName === 'guests' && parseInt(uid, 10) === 0) || + (groupName === 'spiders' && parseInt(uid, 10) === -1); + } + function filterNonCached(cachedData, uid, groupName) { const isMember = Groups.cache.get(`${uid}:${groupName}`); const isInCache = isMember !== undefined; diff --git a/test/groups.js b/test/groups.js index bfc6965c9e..c80313e467 100644 --- a/test/groups.js +++ b/test/groups.js @@ -209,36 +209,54 @@ describe('Groups', () => { }); describe('.isMember()', () => { - it('should return boolean true when a user is in a group', (done) => { - Groups.isMember(1, 'Test', (err, isMember) => { - assert.ifError(err); - assert.strictEqual(isMember, true); - done(); - }); + it('should return boolean true when a user is in a group', async () => { + const isMember = await Groups.isMember(1, 'Test'); + assert.strictEqual(isMember, true); }); - it('should return boolean false when a user is not in a group', (done) => { - Groups.isMember(2, 'Test', (err, isMember) => { - assert.ifError(err); - assert.strictEqual(isMember, false); - done(); - }); + it('should return boolean false when a user is not in a group', async () => { + const isMember = await Groups.isMember(2, 'Test'); + assert.strictEqual(isMember, false); }); - it('should return true for uid 0 and guests group', (done) => { - Groups.isMembers([1, 0], 'guests', (err, isMembers) => { - assert.ifError(err); - assert.deepStrictEqual(isMembers, [false, true]); - done(); - }); + it('should return true for uid 0 and guests group', async () => { + const isMember = await Groups.isMember(0, 'guests'); + assert.strictEqual(isMember, true); }); - it('should return true for uid 0 and guests group', (done) => { - Groups.isMemberOfGroups(0, ['guests', 'registered-users'], (err, isMembers) => { - assert.ifError(err); - assert.deepStrictEqual(isMembers, [true, false]); - done(); - }); + it('should return false for uid 0 and spiders group', async () => { + const isMember = await Groups.isMember(0, 'spiders'); + assert.strictEqual(isMember, false); + }); + + it('should return true for uid -1 and spiders group', async () => { + const isMember = await Groups.isMember(-1, 'spiders'); + assert.strictEqual(isMember, true); + }); + + it('should return false for uid -1 and guests group', async () => { + const isMember = await Groups.isMember(-1, 'guests'); + assert.strictEqual(isMember, false); + }); + + it('should return true for uid 0, false for uid -1 with guests group', async () => { + const isMembers = await Groups.isMembers([1, 0, -1], 'guests'); + assert.deepStrictEqual(isMembers, [false, true, false]); + }); + + it('should return false for uid 0, true for uid -1 with spiders group', async () => { + const isMembers = await Groups.isMembers([1, 0, -1], 'spiders'); + assert.deepStrictEqual(isMembers, [false, false, true]); + }); + + it('should return true for uid 0 and guests group', async () => { + const isMembers = await Groups.isMemberOfGroups(0, ['guests', 'registered-users', 'spiders']); + assert.deepStrictEqual(isMembers, [true, false, false]); + }); + + it('should return true for uid -1 and spiders group', async () => { + const isMembers = await Groups.isMemberOfGroups(-1, ['guests', 'registered-users', 'spiders']); + assert.deepStrictEqual(isMembers, [false, false, true]); }); }); @@ -406,16 +424,12 @@ describe('Groups', () => { }); describe('.hide()', () => { - it('should mark the group as hidden', (done) => { - Groups.hide('foo', (err) => { - assert.ifError(err); - - Groups.get('foo', {}, (err, groupObj) => { - assert.ifError(err); - assert.strictEqual(1, groupObj.hidden); - done(); - }); - }); + it('should mark the group as hidden', async () => { + await Groups.hide('foo'); + const groupObj = await Groups.get('foo', {}); + assert.strictEqual(1, groupObj.hidden); + const isMember = await db.isSortedSetMember('groups:visible:createtime', 'foo'); + assert.strictEqual(isMember, false); }); }); @@ -798,20 +812,6 @@ describe('Groups', () => { }); }); - describe('.hide()', () => { - it('should make a group hidden', (done) => { - Groups.hide('Test', function (err) { - assert.ifError(err); - assert.equal(arguments.length, 1); - db.isSortedSetMember('groups:visible:createtime', 'Test', (err, isMember) => { - assert.ifError(err); - assert.strictEqual(isMember, false); - done(); - }); - }); - }); - }); - describe('socket methods', () => { it('should error if data is null', (done) => { socketGroups.before({ uid: 0 }, 'groups.join', null, (err) => { From 32dd6c498356eb7093c8d33194d9ae096321e26e Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Thu, 29 Jun 2023 09:19:12 +0000 Subject: [PATCH 003/300] Latest translations and fallbacks --- public/language/fr/admin/admin.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/public/language/fr/admin/admin.json b/public/language/fr/admin/admin.json index ac55751183..6ce6f902d2 100644 --- a/public/language/fr/admin/admin.json +++ b/public/language/fr/admin/admin.json @@ -4,13 +4,13 @@ "acp-title": "%1 | Panneau d'administration NodeBB", "settings-header-contents": "Contenus", - "changes-saved": "Changes Saved", - "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", + "changes-saved": "Changements sauvegardés", + "changes-saved-message": "Vos modifications de la configuration NodeBB ont été enregistrées.", "changes-not-saved": "Changements non sauvegardés !", "changes-not-saved-message": "NodeBB a rencontré un problème lors de l'enregistrement de vos modifications ! (%1)", - "save-changes": "Save changes", + "save-changes": "Enregistrer les changements", "min": "Min:", "max": "Max:", - "view": "View", - "edit": "Edit" + "view": "Voir", + "edit": "Éditer " } \ No newline at end of file From f23cda10cf6648995fa2184d403d6b9f1f4f5317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 29 Jun 2023 10:55:38 -0400 Subject: [PATCH 004/300] chore: up markdown --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 5aa0ba97f4..372e55f8cd 100644 --- a/install/package.json +++ b/install/package.json @@ -96,7 +96,7 @@ "nodebb-plugin-dbsearch": "6.1.0", "nodebb-plugin-emoji": "5.1.2", "nodebb-plugin-emoji-android": "4.0.0", - "nodebb-plugin-markdown": "12.1.4", + "nodebb-plugin-markdown": "12.1.5", "nodebb-plugin-mentions": "4.2.0", "nodebb-plugin-ntfy": "1.0.15", "nodebb-plugin-spam-be-gone": "2.1.0", From 311b8b2494e06a7259bec49b18d9daa80d942934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 29 Jun 2023 11:06:54 -0400 Subject: [PATCH 005/300] add new string --- public/language/en-GB/admin/admin.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/language/en-GB/admin/admin.json b/public/language/en-GB/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/en-GB/admin/admin.json +++ b/public/language/en-GB/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file From 58bdedaf8b752244f97285c880e6100ae8e62625 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Thu, 29 Jun 2023 15:07:18 +0000 Subject: [PATCH 006/300] chore(i18n): fallback strings for new resources: nodebb.admin-admin --- public/language/ar/admin/admin.json | 3 ++- public/language/bg/admin/admin.json | 3 ++- public/language/bn/admin/admin.json | 3 ++- public/language/cs/admin/admin.json | 3 ++- public/language/da/admin/admin.json | 3 ++- public/language/de/admin/admin.json | 3 ++- public/language/el/admin/admin.json | 3 ++- public/language/en-US/admin/admin.json | 3 ++- public/language/en-x-pirate/admin/admin.json | 3 ++- public/language/es/admin/admin.json | 3 ++- public/language/et/admin/admin.json | 3 ++- public/language/fa-IR/admin/admin.json | 3 ++- public/language/fi/admin/admin.json | 3 ++- public/language/fr/admin/admin.json | 3 ++- public/language/gl/admin/admin.json | 3 ++- public/language/he/admin/admin.json | 3 ++- public/language/hr/admin/admin.json | 3 ++- public/language/hu/admin/admin.json | 3 ++- public/language/hy/admin/admin.json | 3 ++- public/language/id/admin/admin.json | 3 ++- public/language/it/admin/admin.json | 3 ++- public/language/ja/admin/admin.json | 3 ++- public/language/ko/admin/admin.json | 3 ++- public/language/lt/admin/admin.json | 3 ++- public/language/lv/admin/admin.json | 3 ++- public/language/ms/admin/admin.json | 3 ++- public/language/nb/admin/admin.json | 3 ++- public/language/nl/admin/admin.json | 3 ++- public/language/pl/admin/admin.json | 3 ++- public/language/pt-BR/admin/admin.json | 3 ++- public/language/pt-PT/admin/admin.json | 3 ++- public/language/ro/admin/admin.json | 3 ++- public/language/ru/admin/admin.json | 3 ++- public/language/rw/admin/admin.json | 3 ++- public/language/sc/admin/admin.json | 3 ++- public/language/sk/admin/admin.json | 3 ++- public/language/sl/admin/admin.json | 3 ++- public/language/sq-AL/admin/admin.json | 3 ++- public/language/sr/admin/admin.json | 3 ++- public/language/sv/admin/admin.json | 3 ++- public/language/th/admin/admin.json | 3 ++- public/language/tr/admin/admin.json | 3 ++- public/language/uk/admin/admin.json | 3 ++- public/language/vi/admin/admin.json | 3 ++- public/language/zh-CN/admin/admin.json | 3 ++- public/language/zh-TW/admin/admin.json | 3 ++- 46 files changed, 92 insertions(+), 46 deletions(-) diff --git a/public/language/ar/admin/admin.json b/public/language/ar/admin/admin.json index 28ad0d39d4..3a578f3e95 100644 --- a/public/language/ar/admin/admin.json +++ b/public/language/ar/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/bg/admin/admin.json b/public/language/bg/admin/admin.json index eebf1de05c..30e18ffe2a 100644 --- a/public/language/bg/admin/admin.json +++ b/public/language/bg/admin/admin.json @@ -12,5 +12,6 @@ "min": "Мин.:", "max": "Макс.:", "view": "Преглед", - "edit": "Редактиране" + "edit": "Редактиране", + "add": "Add" } \ No newline at end of file diff --git a/public/language/bn/admin/admin.json b/public/language/bn/admin/admin.json index a909f03faa..478ef4c161 100644 --- a/public/language/bn/admin/admin.json +++ b/public/language/bn/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/cs/admin/admin.json b/public/language/cs/admin/admin.json index 379f1103cf..79e58e40de 100644 --- a/public/language/cs/admin/admin.json +++ b/public/language/cs/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/da/admin/admin.json b/public/language/da/admin/admin.json index 22c8e30f83..3e78aa21f9 100644 --- a/public/language/da/admin/admin.json +++ b/public/language/da/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/de/admin/admin.json b/public/language/de/admin/admin.json index b3b9384c0b..031fa20ece 100644 --- a/public/language/de/admin/admin.json +++ b/public/language/de/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/el/admin/admin.json b/public/language/el/admin/admin.json index d4d20945ba..b8a34c75d1 100644 --- a/public/language/el/admin/admin.json +++ b/public/language/el/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/en-US/admin/admin.json b/public/language/en-US/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/en-US/admin/admin.json +++ b/public/language/en-US/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/en-x-pirate/admin/admin.json b/public/language/en-x-pirate/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/en-x-pirate/admin/admin.json +++ b/public/language/en-x-pirate/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/es/admin/admin.json b/public/language/es/admin/admin.json index d9318a8105..de08b28fc1 100644 --- a/public/language/es/admin/admin.json +++ b/public/language/es/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/et/admin/admin.json b/public/language/et/admin/admin.json index d430b9e319..1bb9683b85 100644 --- a/public/language/et/admin/admin.json +++ b/public/language/et/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/fa-IR/admin/admin.json b/public/language/fa-IR/admin/admin.json index 681ce4a2a1..38b347366b 100644 --- a/public/language/fa-IR/admin/admin.json +++ b/public/language/fa-IR/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/fi/admin/admin.json b/public/language/fi/admin/admin.json index 25faab4d88..7b26ca982e 100644 --- a/public/language/fi/admin/admin.json +++ b/public/language/fi/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/fr/admin/admin.json b/public/language/fr/admin/admin.json index 6ce6f902d2..384e64f55f 100644 --- a/public/language/fr/admin/admin.json +++ b/public/language/fr/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "Voir", - "edit": "Éditer " + "edit": "Éditer ", + "add": "Add" } \ No newline at end of file diff --git a/public/language/gl/admin/admin.json b/public/language/gl/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/gl/admin/admin.json +++ b/public/language/gl/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/he/admin/admin.json b/public/language/he/admin/admin.json index 5fa1d8a035..f1555be6ff 100644 --- a/public/language/he/admin/admin.json +++ b/public/language/he/admin/admin.json @@ -12,5 +12,6 @@ "min": "מינימום:", "max": "מקסימום:", "view": "View", - "edit": "עריכה" + "edit": "עריכה", + "add": "Add" } \ No newline at end of file diff --git a/public/language/hr/admin/admin.json b/public/language/hr/admin/admin.json index 1d7b7d1524..a7c0ff924a 100644 --- a/public/language/hr/admin/admin.json +++ b/public/language/hr/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/hu/admin/admin.json b/public/language/hu/admin/admin.json index 3cf53e2572..c7b0c876a1 100644 --- a/public/language/hu/admin/admin.json +++ b/public/language/hu/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/hy/admin/admin.json b/public/language/hy/admin/admin.json index 066b10b627..6ae4598925 100644 --- a/public/language/hy/admin/admin.json +++ b/public/language/hy/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/id/admin/admin.json b/public/language/id/admin/admin.json index c98a0b8c34..2b282dba78 100644 --- a/public/language/id/admin/admin.json +++ b/public/language/id/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/it/admin/admin.json b/public/language/it/admin/admin.json index 549a8457c6..e205552e9f 100644 --- a/public/language/it/admin/admin.json +++ b/public/language/it/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "Visualizza", - "edit": "Modifica" + "edit": "Modifica", + "add": "Add" } \ No newline at end of file diff --git a/public/language/ja/admin/admin.json b/public/language/ja/admin/admin.json index 73676e27a3..2471f5c3d7 100644 --- a/public/language/ja/admin/admin.json +++ b/public/language/ja/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/ko/admin/admin.json b/public/language/ko/admin/admin.json index eea7e10b16..5257763f6a 100644 --- a/public/language/ko/admin/admin.json +++ b/public/language/ko/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/lt/admin/admin.json b/public/language/lt/admin/admin.json index de86c23c77..fadce9096b 100644 --- a/public/language/lt/admin/admin.json +++ b/public/language/lt/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/lv/admin/admin.json b/public/language/lv/admin/admin.json index 9cd1b5d220..f53a0043f6 100644 --- a/public/language/lv/admin/admin.json +++ b/public/language/lv/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/ms/admin/admin.json b/public/language/ms/admin/admin.json index 413f97994a..4e723fdf3f 100644 --- a/public/language/ms/admin/admin.json +++ b/public/language/ms/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/nb/admin/admin.json b/public/language/nb/admin/admin.json index 8ed4c165a2..dbdee3d930 100644 --- a/public/language/nb/admin/admin.json +++ b/public/language/nb/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/nl/admin/admin.json b/public/language/nl/admin/admin.json index 8ac9574eb6..3d2e0b799d 100644 --- a/public/language/nl/admin/admin.json +++ b/public/language/nl/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/pl/admin/admin.json b/public/language/pl/admin/admin.json index c4b06132ea..36e9d0f559 100644 --- a/public/language/pl/admin/admin.json +++ b/public/language/pl/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/admin.json b/public/language/pt-BR/admin/admin.json index 8af71123c1..df71a99aac 100644 --- a/public/language/pt-BR/admin/admin.json +++ b/public/language/pt-BR/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/admin.json b/public/language/pt-PT/admin/admin.json index 19a58da812..0e8ac0ff26 100644 --- a/public/language/pt-PT/admin/admin.json +++ b/public/language/pt-PT/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/ro/admin/admin.json b/public/language/ro/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/ro/admin/admin.json +++ b/public/language/ro/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/ru/admin/admin.json b/public/language/ru/admin/admin.json index 2369366840..b7e7e6d8a1 100644 --- a/public/language/ru/admin/admin.json +++ b/public/language/ru/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/rw/admin/admin.json b/public/language/rw/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/rw/admin/admin.json +++ b/public/language/rw/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/sc/admin/admin.json b/public/language/sc/admin/admin.json index 89e08402cd..48994c38a7 100644 --- a/public/language/sc/admin/admin.json +++ b/public/language/sc/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/sk/admin/admin.json b/public/language/sk/admin/admin.json index b8c7612a9a..aae9f76473 100644 --- a/public/language/sk/admin/admin.json +++ b/public/language/sk/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/sl/admin/admin.json b/public/language/sl/admin/admin.json index 84f479a2bc..4c0114649f 100644 --- a/public/language/sl/admin/admin.json +++ b/public/language/sl/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/sq-AL/admin/admin.json b/public/language/sq-AL/admin/admin.json index c9430ce3da..1e850fb816 100644 --- a/public/language/sq-AL/admin/admin.json +++ b/public/language/sq-AL/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/sr/admin/admin.json b/public/language/sr/admin/admin.json index f53f9c0f51..74825d8eed 100644 --- a/public/language/sr/admin/admin.json +++ b/public/language/sr/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/sv/admin/admin.json b/public/language/sv/admin/admin.json index 70868783ce..43aa5d4980 100644 --- a/public/language/sv/admin/admin.json +++ b/public/language/sv/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/th/admin/admin.json b/public/language/th/admin/admin.json index eb6d05a175..c87a6b322f 100644 --- a/public/language/th/admin/admin.json +++ b/public/language/th/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/tr/admin/admin.json b/public/language/tr/admin/admin.json index c4718b4700..a3f790684f 100644 --- a/public/language/tr/admin/admin.json +++ b/public/language/tr/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/uk/admin/admin.json b/public/language/uk/admin/admin.json index e5050a475f..89890b5032 100644 --- a/public/language/uk/admin/admin.json +++ b/public/language/uk/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/vi/admin/admin.json b/public/language/vi/admin/admin.json index b9b457dfa9..c9fe017767 100644 --- a/public/language/vi/admin/admin.json +++ b/public/language/vi/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/admin.json b/public/language/zh-CN/admin/admin.json index 554c76b245..5d807714e9 100644 --- a/public/language/zh-CN/admin/admin.json +++ b/public/language/zh-CN/admin/admin.json @@ -12,5 +12,6 @@ "min": "最小:", "max": "最大:", "view": "浏览", - "edit": "编辑" + "edit": "编辑", + "add": "Add" } \ No newline at end of file diff --git a/public/language/zh-TW/admin/admin.json b/public/language/zh-TW/admin/admin.json index f5814c10c4..e8a033114f 100644 --- a/public/language/zh-TW/admin/admin.json +++ b/public/language/zh-TW/admin/admin.json @@ -12,5 +12,6 @@ "min": "Min:", "max": "Max:", "view": "View", - "edit": "Edit" + "edit": "Edit", + "add": "Add" } \ No newline at end of file From 48a006533e7d9e89a070cc4bb63060514d96fbd7 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Fri, 30 Jun 2023 09:18:51 +0000 Subject: [PATCH 007/300] Latest translations and fallbacks --- public/language/bg/admin/admin.json | 2 +- public/language/he/admin/admin.json | 2 +- public/language/he/admin/advanced/errors.json | 2 +- public/language/he/admin/advanced/events.json | 8 ++++---- .../he/admin/appearance/customise.json | 2 +- public/language/he/admin/dashboard.json | 4 ++-- public/language/he/admin/extend/widgets.json | 18 +++++++++--------- public/language/he/admin/menu.json | 10 +++++----- public/language/he/admin/settings/api.json | 2 +- public/language/he/admin/settings/email.json | 2 +- public/language/he/admin/settings/guest.json | 2 +- public/language/he/notifications.json | 4 ++-- public/language/he/themes/harmony.json | 4 ++-- 13 files changed, 31 insertions(+), 31 deletions(-) diff --git a/public/language/bg/admin/admin.json b/public/language/bg/admin/admin.json index 30e18ffe2a..879e8122b7 100644 --- a/public/language/bg/admin/admin.json +++ b/public/language/bg/admin/admin.json @@ -13,5 +13,5 @@ "max": "Макс.:", "view": "Преглед", "edit": "Редактиране", - "add": "Add" + "add": "Добавяне" } \ No newline at end of file diff --git a/public/language/he/admin/admin.json b/public/language/he/admin/admin.json index f1555be6ff..7fe66d9af6 100644 --- a/public/language/he/admin/admin.json +++ b/public/language/he/admin/admin.json @@ -11,7 +11,7 @@ "save-changes": "שמור שינויים", "min": "מינימום:", "max": "מקסימום:", - "view": "View", + "view": "צפייה", "edit": "עריכה", "add": "Add" } \ No newline at end of file diff --git a/public/language/he/admin/advanced/errors.json b/public/language/he/admin/advanced/errors.json index eb5715f142..f756e47ace 100644 --- a/public/language/he/admin/advanced/errors.json +++ b/public/language/he/admin/advanced/errors.json @@ -1,7 +1,7 @@ { "errors": "שגיאות", "figure-x": "דוגמא %1", - "error-events-per-day": "%1 ארועים ביום", + "error-events-per-day": "%1 אירועים ביום", "error.404": "לא נמצא 404", "error.503": "השירות אינו זמין 503", "manage-error-log": "נהל רישום שגיאות", diff --git a/public/language/he/admin/advanced/events.json b/public/language/he/admin/advanced/events.json index 37da405a88..757d5ae8a8 100644 --- a/public/language/he/admin/advanced/events.json +++ b/public/language/he/admin/advanced/events.json @@ -1,8 +1,8 @@ { - "events": "ארועים", - "no-events": "אין ארועים", - "control-panel": "בקרת ארועים\n ", - "delete-events": "מחיקת ארועים", + "events": "אירועים", + "no-events": "אין אירועים", + "control-panel": "בקרת אירועים", + "delete-events": "מחיקת אירועים", "confirm-delete-all-events": "האם אתה בטוח שאתה רוצה למחוק את כל האירועים שנרשמו?", "filters": "מסננים", "filters-apply": "החל מסננים", diff --git a/public/language/he/admin/appearance/customise.json b/public/language/he/admin/appearance/customise.json index f138c80090..fc2c805f5f 100644 --- a/public/language/he/admin/appearance/customise.json +++ b/public/language/he/admin/appearance/customise.json @@ -15,6 +15,6 @@ "custom-css.livereload": "הפעלת טעינה מחדש אוטומטית.", "custom-css.livereload.description": "הפעלה זו נועדה כדי לרענן את כל החיבורים מכל מכשיר, כאשר תשמרו את הדף המותאם אישית.", "bsvariables": "_variables.scss", - "bsvariables.description": "Override bootstrap variables here. You can also use a tool like bootstrap.build and paste the output here.
Changes require a rebuild & restart.", + "bsvariables.description": "ניתן לעקוף משתני Bootstrap כאן. אתה יכול גם להשתמש בכלי כמו bootstrap.build ולהדביק את הפלט כאן.
שינויים דורשים בנייה מחדש והפעלה מחדש.", "bsvariables.enable": "Enable _variables.scss" } \ No newline at end of file diff --git a/public/language/he/admin/dashboard.json b/public/language/he/admin/dashboard.json index 50e58da897..5b1860d8a4 100644 --- a/public/language/he/admin/dashboard.json +++ b/public/language/he/admin/dashboard.json @@ -26,7 +26,7 @@ "updates": "עדכונים", "running-version": "הפורום מעודכן לגרסה %1", "keep-updated": "לעדכוני אבטחה מעודכנים ותיקוני באגים, וודא שהפורום שלך עדכני לגרסה האחרונה.", - "up-to-date": " אתה מעודכן", + "up-to-date": "אתה מעודכן ", "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", "prerelease-upgrade-available": "זוהי גרסת טרום-הפצה מיושנת של NodeBB. גרסה חדשה (v%1) שוחררה. שקול לשדרג את ה-NodeBB שלך.", "prerelease-warning": " זוהי גרסת טרום-הפצה של NodeBB. עלולים להתרחש באגים לא מכוונים.", @@ -43,7 +43,7 @@ "control-panel": "שליטת מערכת", "rebuild-and-restart": "בנייה והפעלה מחדש", - "restart": "הפעל מחדש", + "restart": "הפעלה מחדש", "restart-warning": "הפעלה או בניה מחדש של הפורום תנתק את כל החיבורים הקיימים למספר שניות", "restart-disabled": "הפעלה או בניה מחדש של הפורום בוטלה, נראה שאינך מפעיל את הפורום דרך שרת מתאים.", "maintenance-mode": "מצב תחזוקה", diff --git a/public/language/he/admin/extend/widgets.json b/public/language/he/admin/extend/widgets.json index 6ece7f45ff..949e80ad0c 100644 --- a/public/language/he/admin/extend/widgets.json +++ b/public/language/he/admin/extend/widgets.json @@ -1,11 +1,11 @@ { "widgets": "ווידג'טים", - "available": "וידג'טים זמינים", - "explanation": "בחר וידג'ט מהתפריט הנפתח ואז גרור ושחרר אותו באזור הווידג'ט של התבנית משמאל.", - "none-installed": "לא נמצאו וידג'טים! הפעל את תוספי הוידג'טים ב תוספים בלוח הבקרה.", - "clone-from": "וידג'טים משוכפלים מ", + "available": "ווידג'טים זמינים", + "explanation": "בחר ווידג'ט מהתפריט הנפתח ואז גרור ושחרר אותו באזור הווידג'ט של התבנית משמאל.", + "none-installed": "לא נמצאו ווידג'טים! הפעל את תוספי הווידג'טים ב תוספים בלוח הבקרה.", + "clone-from": "שיבוט ווידג'טים מ", "containers.available": "גורמים מכילים זמינים", - "containers.explanation": "גרור ושחרר מעל כל וידג'ט פעיל", + "containers.explanation": "גרור ושחרר מעל כל ווידג'ט פעיל", "containers.none": "None", "container.well": "Well", "container.jumbotron": "Jumbotron", @@ -14,10 +14,10 @@ "container.card-body": "גוף כרטיס", "container.alert": "התראה", - "alert.confirm-delete": "האם אתה בטוח שאתה רוצה למחוק את הוידג'ט?", - "alert.updated": "העלאת וידג'טים", - "alert.update-success": "הוידג'טים הועלו בהצלחה", - "alert.clone-success": "הוידג'טים שוכפלו בהצלחה", + "alert.confirm-delete": "האם אתה בטוח שאתה רוצה למחוק את הווידג'ט?", + "alert.updated": "העלאת ווידג'טים", + "alert.update-success": "הווידג'טים הועלו בהצלחה", + "alert.clone-success": "הווידג'טים שוכפלו בהצלחה", "error.select-clone": "בחר דף לשכפל ממנו", diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json index a0ec4cfc00..91250141b9 100644 --- a/public/language/he/admin/menu.json +++ b/public/language/he/admin/menu.json @@ -53,7 +53,7 @@ "section-extend": "הרחבות", "extend/plugins": "תוספים", - "extend/widgets": "וידג'טים", + "extend/widgets": "ווידג'טים", "extend/rewards": "תגמולים", "section-social-auth": "אימות חיצוני", @@ -63,7 +63,7 @@ "section-advanced": "מתקדם", "advanced/database": "מסד נתונים", - "advanced/events": "ארועים", + "advanced/events": "אירועים", "advanced/hooks": "Hooks", "advanced/logs": "רישומים", "advanced/errors": "שגיאות", @@ -74,11 +74,11 @@ "rebuild-and-restart-forum": "בנה והפעל מחדש את הפורום", "rebuild-and-restart": "בניה מחדש והפעלה מחדש", "restart-forum": "הפעל מחדש את הפורום", - "restart": "הפעל מחדש", - "logout": "התנתק", + "restart": "הפעלה מחדש", + "logout": "התנתקות", "view-forum": "כניסה לפורום", - "search.placeholder": "הגדרות חיפוש", + "search.placeholder": "חיפוש הגדרות", "search.no-results": "אין תוצאות...", "search.search-forum": "חפש בפורום ", "search.keep-typing": "המשך להקליד על מנת למצוא תוצאות...", diff --git a/public/language/he/admin/settings/api.json b/public/language/he/admin/settings/api.json index 3ae1efca00..57d0010b67 100644 --- a/public/language/he/admin/settings/api.json +++ b/public/language/he/admin/settings/api.json @@ -3,7 +3,7 @@ "settings": "הגדרות", "lead-text": "מעמוד זה תוכלו להגדיר גישת כתיבה ל-API ב- NodeBB.", "intro": "כברירת מחדל, ה- API של כתיבה מאמת משתמשים בהתבסס על קובץ ה-cookie של ההפעלה שלהם, אך NodeBB תומך גם באימות נושא באמצעות טוקנים (אישורי אבטחה) שנוצרו באמצעות דף זה.", - "warning": "שים לב — יש להתייחס לאסימונים כמו אל סיסמאות. אם הם דולפים, יש לראות בחשבונך כנפרץ. ", + "warning": "שים לב — יש להתייחס לאסימונים כמו אל סיסמאות. אם הם דולפים, יש לראות את חשבונך כנפרץ. ", "docs": "לחץ כאן כדי לגשת למפרט ה- API המלא", "require-https": "אפשר שימוש בAPI באמצעות HTTPS בלבד", diff --git a/public/language/he/admin/settings/email.json b/public/language/he/admin/settings/email.json index 30cd68a746..2ff8132b24 100644 --- a/public/language/he/admin/settings/email.json +++ b/public/language/he/admin/settings/email.json @@ -39,7 +39,7 @@ "subscriptions": "תקצירי דואר אלקטרוני", "subscriptions.disable": "הפיכת תקצירי דואר אלקטרוני ללא זמינים", "subscriptions.hour": "שעת תקציר", - "subscriptions.hour-help": "Please enter a number representing the hour to send scheduled email digests (e.g. 0 for midnight, 17 for 5:00pm). Keep in mind that this is the hour according to the server itself, and may not exactly match your system clock.
The approximate server time is:
The next daily digest is scheduled to be sent ", + "subscriptions.hour-help": "אנא הזן מספר המייצג את השעה לשליחת תקצירי אימייל מתוזמנים (למשל 0 לחצות,17 לשעה 17:00). זכור שזו השעה בהתאם לשרת עצמו, וייתכן שלא בדיוק תואם את שעון המערכת שלך.
זמן השרת המשוער הוא:
התקציר היומי הבא מתוכנן להישלח", "notifications.remove-images": "הסר תמונות מהודעות דוא\"ל", "require-email-address": "דרוש ממשתמשים חדשים כתובת אימייל", "require-email-address-warning": "כברירת מחדל, משתמשים יכולים לבטל את הסכמתם להזנת כתובת דוא\"ל על ידי השארת השדה ריק. הפעלת אפשרות זו פירושה שמשתמשים חדשים יצטרכו להזין ולאשר כתובת דואר אלקטרוני על מנת להמשיך ברישום ובגישה לאחר מכן לפורום. זה לא מבטיח שהמשתמש יזין כתובת אימייל אמיתית, ואפילו לא כתובת שבבעלותו.", diff --git a/public/language/he/admin/settings/guest.json b/public/language/he/admin/settings/guest.json index 539d292411..fbdf6f275e 100644 --- a/public/language/he/admin/settings/guest.json +++ b/public/language/he/admin/settings/guest.json @@ -2,7 +2,7 @@ "settings": "הגדרות", "guest-settings": "הגדרות אורחים", "handles.enabled": "אפשר נקודות אחיזה לאורחים", - "handles.enabled-help": "אפשרות זו חושפת שדה חדש המאפשר לאורחים לבחור שם שישויך לכל פוסט שהם מבצעים. אם הם מושבתים, הם פשוט יקראו \"אורח\"", + "handles.enabled-help": "אפשרות זו חושפת שדה חדש המאפשר לאורחים לבחור שם שישויך לכל פוסט שהם מבצעים. אם מושבת, הם פשוט יקראו \"אורח\"", "topic-views.enabled": "הגדל מספר צפיות בנושא על-ידי צפיות של אורחים", "reply-notifications.enabled": "אפשר לאורחים ליצור הודעות תשובה" } \ No newline at end of file diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index 2bcca7dd35..5b60088902 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -71,6 +71,6 @@ "notificationType_group-request-membership": "כשמישהו מבקש להירשם לקבוצה שאתה מנהל", "notificationType_new-register": "כאשר מישהו מתווסף לתור הרישום", "notificationType_post-queue": "כאשר פוסט חדש נכנס לתור", - "notificationType_new-post-flag": "כאשר פוסט מסומן", - "notificationType_new-user-flag": "כאשר משתמש מסומן" + "notificationType_new-post-flag": "כאשר פוסט מדווח", + "notificationType_new-user-flag": "כאשר מדווחים על משתמש" } \ No newline at end of file diff --git a/public/language/he/themes/harmony.json b/public/language/he/themes/harmony.json index 87f56a8343..2f460ac2c7 100644 --- a/public/language/he/themes/harmony.json +++ b/public/language/he/themes/harmony.json @@ -7,8 +7,8 @@ "settings.title": "הגדרות ערכת נושא", "settings.enableQuickReply": "הפעלת תגובה מהירה", "settings.centerHeaderElements": "מרכוז אלמנטים של כותרת", - "settings.mobileTopicTeasers": "הצגת טיזרים של נושאים בסלולרי", - "settings.stickyToolbar": "סרגל כלים מוצמד בעת גלילה", + "settings.mobileTopicTeasers": "הצגת טיזרים של נושאים בנייד", + "settings.stickyToolbar": "הצמד את סרגל הכלים בעת גלילה", "settings.stickyToolbar.help": "סרגל הכלים בדפי נושאים וקטגוריות ייצמד לראש העמוד בעת גלילה", "settings.autohideBottombar": "הסתרה אוטומטית של סרגל תחתון", "settings.autohideBottombar.help": "הסרגל התחתון בתצוגת הנייד יוסתר כאשר הדף ייגלל מטה", From a3520313881805e18730d88c2ac13ecf964337ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 30 Jun 2023 14:48:22 -0400 Subject: [PATCH 008/300] double static:app.load timeout --- src/plugins/hooks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/hooks.js b/src/plugins/hooks.js index 58f8c85f96..68d0ee2768 100644 --- a/src/plugins/hooks.js +++ b/src/plugins/hooks.js @@ -233,7 +233,7 @@ async function fireStaticHook(hook, hookList, params) { try { // eslint-disable-next-line - await timeout(hookFn(params), 5000, 'timeout'); + await timeout(hookFn(params), 10000, 'timeout'); } catch (err) { if (err && err.message === 'timeout') { winston.warn(`[plugins] Callback timed out, hook '${hook}' in plugin '${hookObj.id}'`); From 8b2b4fce37aa69d36b1c900a5feb62633b0f2eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 30 Jun 2023 15:13:30 -0400 Subject: [PATCH 009/300] add no replies class to navigator --- public/src/modules/navigator.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index 1ac9035031..98c0752312 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -440,7 +440,7 @@ define('navigator', [ count = value; navigator.updateTextAndProgressBar(); setThumbToIndex(index); - toggle(count > 1); + toggle(count > 0); }; navigator.show = function () { @@ -464,6 +464,7 @@ define('navigator', [ } paginationBlockEl.toggleClass('ready', flag); + paginationBlockEl.toggleClass('noreplies', count <= 1); } navigator.delayedUpdate = function () { @@ -523,7 +524,7 @@ define('navigator', [ setThumbToIndex(index); } - toggle(count > 1); + toggle(count > 0); }; navigator.getIndex = () => index; From 9df3ccaaa69fc86074408ed0ea55cbcf5ce32295 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sat, 1 Jul 2023 09:18:34 +0000 Subject: [PATCH 010/300] Latest translations and fallbacks --- public/language/vi/admin/manage/tags.json | 4 ++-- public/language/vi/flags.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/vi/admin/manage/tags.json b/public/language/vi/admin/manage/tags.json index 95cd104447..fb6d662a87 100644 --- a/public/language/vi/admin/manage/tags.json +++ b/public/language/vi/admin/manage/tags.json @@ -1,11 +1,11 @@ { - "manage-tags": "Manage Tags", + "manage-tags": "Quản lý thẻ", "none": "Diễn đàn của bạn chưa có bất kỳ chủ đề nào gắn thẻ.", "bg-color": "Màu Nền", "text-color": "Màu Chữ", "description": "Chọn các thẻ bằng cách nhấp hoặc kéo, bấm CTRL để chọn nhiều thẻ.", "create": "Tạo Thẻ", - "add-tag": "Add tag", + "add-tag": "Thêm thẻ", "modify": "Sửa Đổi Thẻ", "rename": "Đổi Tên Thẻ", "delete": "Xóa Các Thẻ Đã Chọn", diff --git a/public/language/vi/flags.json b/public/language/vi/flags.json index af7768df0e..7a45d900f8 100644 --- a/public/language/vi/flags.json +++ b/public/language/vi/flags.json @@ -16,7 +16,7 @@ "filter-active": "Có một hoặc nhiều bộ lọc đang hoạt động trong danh sách cờ này", "filter-reset": "Xóa Bộ Lọc", "filters": "Tùy Chỉnh Bộ Lọc", - "filter-reporterId": "Reporter", + "filter-reporterId": "Người báo cáo", "filter-targetUid": "Reportee", "filter-type": "Loại Cờ", "filter-type-all": "Tất Cả Nội Dung", From 7370d986a4508f57091829a64c9b22408062357b Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 2 Jul 2023 09:18:33 +0000 Subject: [PATCH 011/300] Latest translations and fallbacks --- public/language/zh-CN/admin/admin.json | 2 +- .../zh-CN/admin/appearance/skins.json | 16 +++++++------- public/language/zh-CN/admin/dashboard.json | 22 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/public/language/zh-CN/admin/admin.json b/public/language/zh-CN/admin/admin.json index 5d807714e9..4f722f7144 100644 --- a/public/language/zh-CN/admin/admin.json +++ b/public/language/zh-CN/admin/admin.json @@ -13,5 +13,5 @@ "max": "最大:", "view": "浏览", "edit": "编辑", - "add": "Add" + "add": "添加" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/appearance/skins.json b/public/language/zh-CN/admin/appearance/skins.json index 08168437e6..4a054a0425 100644 --- a/public/language/zh-CN/admin/appearance/skins.json +++ b/public/language/zh-CN/admin/appearance/skins.json @@ -1,12 +1,12 @@ { "skins": "皮肤", - "bootswatch-skins": "Bootswatch Skins", - "custom-skins": "Custom Skins", - "add-skin": "Add Skin", - "save-custom-skins": "Save Custom Skins", - "save-custom-skins-success": "Custom skins saved successfully", - "custom-skin-name": "Custom Skin Name", - "custom-skin-variables": "Custom Skin Variables", + "bootswatch-skins": "基于 Bootswatch的皮肤", + "custom-skins": "自定义皮肤", + "add-skin": "添加皮肤", + "save-custom-skins": "保存自定义皮肤", + "save-custom-skins-success": "自定义皮肤保存成功", + "custom-skin-name": "自定义皮肤名称", + "custom-skin-variables": "自定义皮肤变量", "loading": "正在加载皮肤...", "homepage": "主页", "select-skin": "选择皮肤", @@ -14,5 +14,5 @@ "current-skin": "当前皮肤", "skin-updated": "皮肤已更新", "applied-success": "%1 皮肤已成功应用", - "revert-success": "皮肤已恢复到基础颜色" + "revert-success": "皮肤已恢复到原来的颜色" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/dashboard.json b/public/language/zh-CN/admin/dashboard.json index 93d0ec231b..cc961e5396 100644 --- a/public/language/zh-CN/admin/dashboard.json +++ b/public/language/zh-CN/admin/dashboard.json @@ -13,26 +13,26 @@ "page-views-custom-start": "范围开始", "page-views-custom-end": "范围结束", "page-views-custom-help": "输入您要查看的网页浏览日期范围。 如果没有日期选择器可用,则接受的格式是 YYYY-MM-DD", - "page-views-custom-error": "请输入 YYYY-MM-DD格式的有效日期范围 ", + "page-views-custom-error": "请输入以YYYY-MM-DD格式的有效的日期范围 ", "stats.yesterday": "昨天", "stats.today": "今天", "stats.last-week": "上一周", - "stats.this-week": "本周", + "stats.this-week": "此周", "stats.last-month": "上一月", - "stats.this-month": "本月", + "stats.this-month": "此月", "stats.all": "总计", "updates": "更新", "running-version": "您正在运行 NodeBB v%1 .", "keep-updated": "请确保您已及时更新 NodeBB 以获得最新的安全补丁与 Bug 修复。", "up-to-date": "你处于最新版本", - "upgrade-available": "一个新的版本(v%1)已经发布。建议您升级你的 NodeBB 。", - "prerelease-upgrade-available": "这是一个过时的预发布版本的 NodeBB 。一个新的版本(v%1)已经发布。考虑升级你的 NodeBB 。", - "prerelease-warning": "这是NodeBB的一个预发布版本。可能会出现意想不到的错误。", - "fallback-emailer-not-found": "找不到备用邮箱", - "running-in-development": "论坛正以开发模式运行。该论坛可能存在潜在的漏洞,请联系您的系统管理员。", - "latest-lookup-failed": "查询NodeBB的最新可用版本失败", + "upgrade-available": "新版本(v%1)已发布。建议您升级您的 NodeBB 。", + "prerelease-upgrade-available": "这是一个过时的预发布版本的 NodeBB 。一个新版本(v%1)已经发布。考虑升级您的 NodeBB 。", + "prerelease-warning": "这是NodeBB的一个预发布版本。可能会出现不平衡。", + "fallback-emailer-not-found": "备用邮箱发送器没有找到!", + "running-in-development": "论坛正以开发模式运行。处于该模式的论坛可能存在潜在的漏洞,请联系您的论坛管理员。", + "latest-lookup-failed": "查询NodeBB的最新版本失败", "notices": "提醒", "restart-not-required": "不需要重启", @@ -42,7 +42,7 @@ "search-plugin-tooltip": "在插件页面安装搜索插件来激活搜索功能", "control-panel": "系统控制", - "rebuild-and-restart": "部署 & 重启", + "rebuild-and-restart": "重载 & 重启", "restart": "重启", "restart-warning": "重载或重启 NodeBB 会丢失数秒内全部的连接。", "restart-disabled": "重建和重新启动NodeBB已被禁用,因为您似乎没有通过适当的守护进程运行它。", @@ -60,7 +60,7 @@ "guest": "游客", "registered": "已注册", - "user-presence": "用户光临", + "user-presence": "用户访问", "on-categories": "在版块列表", "reading-posts": "读帖子", "browsing-topics": "浏览话题", From 335a3619206457eca2502a1bab4ea32c646c737a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jul 2023 12:18:27 -0400 Subject: [PATCH 012/300] fix(deps): update dependency esbuild to v0.18.11 (#11772) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 8c479f4a93..15527e06c2 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.10", + "esbuild": "0.18.11", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 63bbb366d79c7285913bab07630475a246ddf51e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jul 2023 12:18:57 -0400 Subject: [PATCH 013/300] fix(deps): update dependency @isaacs/ttlcache to v1.4.1 (#11774) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 15527e06c2..10d99829ee 100644 --- a/install/package.json +++ b/install/package.json @@ -31,7 +31,7 @@ "@adactive/bootstrap-tagsinput": "0.8.2", "@fontsource/inter": "5.0.3", "@fontsource/poppins": "5.0.3", - "@isaacs/ttlcache": "1.4.0", + "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", "ace-builds": "1.23.1", "archiver": "5.3.1", From 0bad85785c45b6832f6158cafd5323a79cd823d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jul 2023 12:19:08 -0400 Subject: [PATCH 014/300] chore(deps): update dependency eslint to v8.44.0 (#11771) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 10d99829ee..0bc8458755 100644 --- a/install/package.json +++ b/install/package.json @@ -156,7 +156,7 @@ "@commitlint/cli": "17.6.6", "@commitlint/config-angular": "17.6.6", "coveralls": "3.1.1", - "eslint": "8.43.0", + "eslint": "8.44.0", "eslint-config-nodebb": "0.2.1", "eslint-plugin-import": "2.27.5", "grunt": "1.6.1", From d2e6062b7a1b562a689f4960f4c1b25c600d4670 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jul 2023 12:19:16 -0400 Subject: [PATCH 015/300] fix(deps): update dependency nodebb-theme-persona to v13.1.7 (#11769) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0bc8458755..bf59b8bcb7 100644 --- a/install/package.json +++ b/install/package.json @@ -104,7 +104,7 @@ "nodebb-theme-harmony": "1.0.65", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.0.32", - "nodebb-theme-persona": "13.1.6", + "nodebb-theme-persona": "13.1.7", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From f367d65a039d95c6ae4e083932817cba16323ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 2 Jul 2023 17:26:58 -0400 Subject: [PATCH 016/300] remove timeagoCutoff=1 --- src/controllers/users.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/users.js b/src/controllers/users.js index 7506a8c8d3..2f697c4b9c 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -61,7 +61,6 @@ usersController.getOnlineUsers = async function (req, res) { } userData.anonymousUserCount = guests + hiddenCount; - userData.timeagoCutoff = 1; await render(req, res, userData); }; From 6e745b882af939a6857dd39d621e08fb1b782206 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 3 Jul 2023 09:19:07 +0000 Subject: [PATCH 017/300] Latest translations and fallbacks --- public/language/de/admin/admin.json | 12 +- public/language/de/admin/advanced/errors.json | 2 +- .../de/admin/appearance/customise.json | 12 +- .../language/de/admin/appearance/skins.json | 14 +- .../language/de/admin/appearance/themes.json | 2 +- public/language/de/admin/dashboard.json | 16 +-- public/language/de/admin/extend/plugins.json | 2 +- public/language/de/admin/extend/rewards.json | 4 +- public/language/de/admin/extend/widgets.json | 10 +- .../language/de/admin/manage/admins-mods.json | 4 +- .../language/de/admin/manage/categories.json | 16 +-- public/language/de/admin/manage/groups.json | 14 +- .../language/de/admin/manage/privileges.json | 4 +- public/language/de/admin/manage/tags.json | 4 +- public/language/de/admin/manage/uploads.json | 2 +- public/language/de/admin/manage/users.json | 10 +- public/language/de/admin/menu.json | 4 +- .../language/de/admin/settings/advanced.json | 6 +- public/language/de/admin/settings/api.json | 24 ++-- public/language/de/admin/settings/email.json | 2 +- .../language/de/admin/settings/general.json | 8 +- public/language/de/admin/settings/guest.json | 2 +- .../de/admin/settings/navigation.json | 2 +- public/language/de/admin/settings/post.json | 8 +- .../de/admin/settings/reputation.json | 2 +- public/language/de/admin/settings/tags.json | 2 +- public/language/de/admin/settings/user.json | 6 +- public/language/de/error.json | 24 ++-- public/language/de/flags.json | 12 +- public/language/de/global.json | 36 +++--- public/language/de/groups.json | 4 +- public/language/de/modules.json | 22 ++-- public/language/de/pages.json | 6 +- public/language/de/post-queue.json | 20 +-- public/language/de/recent.json | 2 +- public/language/de/register.json | 2 +- public/language/de/search.json | 122 +++++++++--------- public/language/de/tags.json | 4 +- public/language/de/themes/harmony.json | 24 ++-- public/language/de/themes/persona.json | 14 +- public/language/de/topic.json | 70 +++++----- public/language/de/user.json | 18 +-- public/language/de/users.json | 4 +- public/language/it/admin/admin.json | 2 +- public/language/it/admin/extend/widgets.json | 6 +- 45 files changed, 293 insertions(+), 293 deletions(-) diff --git a/public/language/de/admin/admin.json b/public/language/de/admin/admin.json index 031fa20ece..4e782d8d2e 100644 --- a/public/language/de/admin/admin.json +++ b/public/language/de/admin/admin.json @@ -4,14 +4,14 @@ "acp-title": "%1 | NodeBB Admin Systemsteuerung", "settings-header-contents": "Inhalte", - "changes-saved": "Changes Saved", - "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", + "changes-saved": "Änderungen gespeichert", + "changes-saved-message": "Deine Änderungen an der NodeBB Konfiguration wurden gespeichert.", "changes-not-saved": "Änderungen verworfen", "changes-not-saved-message": "Beim Speichern der Änderungen ist ein Problem aufgetreten. (%1)", - "save-changes": "Save changes", + "save-changes": "Änderungen speichern", "min": "Min:", "max": "Max:", - "view": "View", - "edit": "Edit", - "add": "Add" + "view": "Anzeigen", + "edit": "Bearbeiten", + "add": "Hinzufügen" } \ No newline at end of file diff --git a/public/language/de/admin/advanced/errors.json b/public/language/de/admin/advanced/errors.json index d7f4995ba4..92143eaabe 100644 --- a/public/language/de/admin/advanced/errors.json +++ b/public/language/de/admin/advanced/errors.json @@ -1,5 +1,5 @@ { - "errors": "Errors", + "errors": "Fehler", "figure-x": "Abbildung %1", "error-events-per-day": "%1 Ereignisse pro Tag", "error.404": "404 Nicht gefunden", diff --git a/public/language/de/admin/appearance/customise.json b/public/language/de/admin/appearance/customise.json index b46fb2c98a..6de993b5cf 100644 --- a/public/language/de/admin/appearance/customise.json +++ b/public/language/de/admin/appearance/customise.json @@ -1,8 +1,8 @@ { - "customise": "Customise", - "custom-css": "Custom CSS/SASS", - "custom-css.description": "Enter your own CSS/SASS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS/SASS", + "customise": "Personalisieren", + "custom-css": "Benutzerdefiniertes CSS/SASS", + "custom-css.description": "Füge deine eigenen CSS/SASS Deklarationen hier ein, die nach allen anderen Styles angewandt werden.", + "custom-css.enable": "Benutzerdefiniertes CSS/SASS aktivieren", "custom-js": "Benutzerdefiniertes Javascript", "custom-js.description": "Füge dein eigenes Javascipt hier ein.\nEs wird ausgeführt nachdem die Seite komplett geladen wurde.", @@ -15,6 +15,6 @@ "custom-css.livereload": "Live-Aktualisierung aktivieren", "custom-css.livereload.description": "Aktiviere diese Einstellung um alle Sitzungen auf allen Geräten mit deinem Konto dazu zu zwingen Neuzuladen sobald du \"Speichern\" drückst", "bsvariables": "_variables.scss", - "bsvariables.description": "Override bootstrap variables here. You can also use a tool like bootstrap.build and paste the output here.
Changes require a rebuild & restart.", - "bsvariables.enable": "Enable _variables.scss" + "bsvariables.description": "Überschreibe Bootstrap-Variablen hier. Du kannst außerdem ein Tool wie bootstrap.build benutzen und das Ergebnis hier hereinkopieren.
Änderungen benötigen einen Rebuild & Neustart.", + "bsvariables.enable": "_variables.scss aktivieren" } \ No newline at end of file diff --git a/public/language/de/admin/appearance/skins.json b/public/language/de/admin/appearance/skins.json index f6ce726fad..47b07a986c 100644 --- a/public/language/de/admin/appearance/skins.json +++ b/public/language/de/admin/appearance/skins.json @@ -1,16 +1,16 @@ { "skins": "Skins", "bootswatch-skins": "Bootswatch Skins", - "custom-skins": "Custom Skins", - "add-skin": "Add Skin", - "save-custom-skins": "Save Custom Skins", - "save-custom-skins-success": "Custom skins saved successfully", - "custom-skin-name": "Custom Skin Name", - "custom-skin-variables": "Custom Skin Variables", + "custom-skins": "Benutzerdefinierte Skins", + "add-skin": "Skin hinzufügen", + "save-custom-skins": "Benutzerdefinierten Skin speichern", + "save-custom-skins-success": "Benutzerdefinierte Skins erfolgreich gespeichert", + "custom-skin-name": "Name des benutzerdefinierten Skins", + "custom-skin-variables": "Variablen des benutzerdefinierten Skins", "loading": "Skins werden geladen...", "homepage": "Startseite", "select-skin": "Skin auswählen", - "revert-skin": "Revert Skin", + "revert-skin": "Skin zurücksetzen", "current-skin": "Aktueller Skin", "skin-updated": "Skin aktualisiert", "applied-success": "Skin %1 wurde erfolgreich angewendet", diff --git a/public/language/de/admin/appearance/themes.json b/public/language/de/admin/appearance/themes.json index 83005bccf5..ebf3facd43 100644 --- a/public/language/de/admin/appearance/themes.json +++ b/public/language/de/admin/appearance/themes.json @@ -3,7 +3,7 @@ "checking-for-installed": "Auf installierte Themes wird geprüft...", "homepage": "Startseite", "select-theme": "Theme wählen", - "revert-theme": "Revert Theme", + "revert-theme": "Theme zurücksetzen", "current-theme": "Aktuelles Theme", "no-themes": "Keine installierten Theme gefunden.", "revert-confirm": "Bist du sicher, dass du das standardmäßige NodeBB-Design wiederherstellen möchten?", diff --git a/public/language/de/admin/dashboard.json b/public/language/de/admin/dashboard.json index 672fcc508d..dca9729f4a 100644 --- a/public/language/de/admin/dashboard.json +++ b/public/language/de/admin/dashboard.json @@ -26,13 +26,13 @@ "updates": "Updates", "running-version": "Es läuft NodeBB v%1.", "keep-updated": "Stelle sicher, dass dein NodeBB immer auf dem neuesten Stand für die neuesten Sicherheits-Patches und Bug-fixes ist.", - "up-to-date": "You are up-to-date ", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-upgrade-available": "This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-warning": "This is a pre-release version of NodeBB. Unintended bugs may occur. ", + "up-to-date": "Die NodeBB Version ist aktuell ", + "upgrade-available": "Eine neuere Version (v%1) ist erschienen. Erwäge, NodeBB zu upgraden.", + "prerelease-upgrade-available": "Dies ist eine veraltete NodeBB-Vorabversion. Eine neuere Version (v%1) ist erschienen. Erwäge, NodeBB zu upgraden.", + "prerelease-warning": "Dies ist eine Vorabversion von NodeBB. Es können ungewollte Fehler auftreten. ", "fallback-emailer-not-found": "Fallback-Emailer nicht gefunden", - "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator", - "latest-lookup-failed": "Failed to look up latest available version of NodeBB", + "running-in-development": "Das Forum wurde im Entwicklermodus gestartet. Das Forum könnte potenziellen Gefahren ausgeliefert sein. Bitte kontaktiere den Systemadministrator.", + "latest-lookup-failed": "Die neueste verfügbare Version von NodeBB konnte nicht abgerufen werden", "notices": "Hinweise", "restart-not-required": "Kein Neustart benötigt", @@ -83,11 +83,11 @@ "back-to-dashboard": "Zurück zur Übersicht", "details.no-users": "Keine Benutzer sind im gewählten Zeitraum beigetreten", "details.no-topics": "Keine Themen wurden im gewählten Zeitraum beigetreten", - "details.no-searches": "No searches have been made within the selected timeframe", + "details.no-searches": "Es wurden im ausgewählten Zeitraum keine Suchen durchgeführt", "details.no-logins": "Keine Logins wurden im gewählten Zeitraum festgestellt", "details.logins-static": "NodeBB speichert Sitzungsdaten nur für %1 Tage, deshalb zeigt die untere Tabelle nur die neuesten, aktiven Sitzungen", "details.logins-login-time": "Anmelde Zeit", "start": "Start", - "end": "End", + "end": "Ende", "filter": "Filter" } diff --git a/public/language/de/admin/extend/plugins.json b/public/language/de/admin/extend/plugins.json index ef2d032d2c..b647be021f 100644 --- a/public/language/de/admin/extend/plugins.json +++ b/public/language/de/admin/extend/plugins.json @@ -1,5 +1,5 @@ { - "plugins": "Plugins", + "plugins": "Erweiterungen", "trending": "Beliebt", "installed": "Installiert", "active": "Aktiv", diff --git a/public/language/de/admin/extend/rewards.json b/public/language/de/admin/extend/rewards.json index 39d7e72818..bcd5099b99 100644 --- a/public/language/de/admin/extend/rewards.json +++ b/public/language/de/admin/extend/rewards.json @@ -1,12 +1,12 @@ { "rewards": "Belohnungen", - "add-reward": "Add reward", + "add-reward": "Belohnung hinzufügen", "condition-if-users": "Wenn Benutzer", "condition-is": "Ist:", "condition-then": "Dann:", "max-claims": "Anzahl der Male von Belohnungen, die beansprucht werden können", "zero-infinite": "0 für unendlich eingeben", - "select-reward": "Select reward", + "select-reward": "Belohnung auswählen", "delete": "Löschen", "enable": "Aktivieren", "disable": "Deaktivieren", diff --git a/public/language/de/admin/extend/widgets.json b/public/language/de/admin/extend/widgets.json index 5d63c1ae1b..7aeab42f52 100644 --- a/public/language/de/admin/extend/widgets.json +++ b/public/language/de/admin/extend/widgets.json @@ -9,9 +9,9 @@ "containers.none": "Nichts", "container.well": "Well", "container.jumbotron": "Jumbotron", - "container.card": "Card", - "container.card-header": "Card Header", - "container.card-body": "Card Body", + "container.card": "Karte", + "container.card-header": "Karten-Kopfzeile", + "container.card-body": "Karten-Körper", "container.alert": "Alarm", "alert.confirm-delete": "Möchtest Du dieses Widget wirklich löschen?", @@ -27,7 +27,7 @@ "container.placeholder": "Ziehe einen Container per Drag-and-Drop oder gebe hier HTML ein.", "show-to-groups": "Gruppen anzeigen", "hide-from-groups": "Vor Gruppen verstecken", - "start-date": "Start date", - "end-date": "End date", + "start-date": "Anfangsdatum", + "end-date": "Enddatum", "hide-on-mobile": "Auf dem Handy verstecken" } \ No newline at end of file diff --git a/public/language/de/admin/manage/admins-mods.json b/public/language/de/admin/manage/admins-mods.json index 5badc78f01..7a1c1532b1 100644 --- a/public/language/de/admin/manage/admins-mods.json +++ b/public/language/de/admin/manage/admins-mods.json @@ -1,11 +1,11 @@ { - "manage-admins-and-mods": "Manage Admins & Mods", + "manage-admins-and-mods": "Admins & Mods verwalten", "administrators": "Administratoren", "global-moderators": "Globale Moderatoren", "moderators": "Moderatoren", "no-global-moderators": "Keine globalen Moderatoren", "no-sub-categories": "Keine Unterkategorien", - "view-children": "View children (%1)", + "view-children": "Aufklappen (%1)", "no-moderators": "Keine Moderatoren", "add-administrator": "Administrator hinzufügen", "add-global-moderator": "Globalen Moderator hinzufügen", diff --git a/public/language/de/admin/manage/categories.json b/public/language/de/admin/manage/categories.json index aad37fd987..21d36ae17a 100644 --- a/public/language/de/admin/manage/categories.json +++ b/public/language/de/admin/manage/categories.json @@ -1,11 +1,11 @@ { - "manage-categories": "Manage Categories", - "add-category": "Add category", - "jump-to": "Jump to...", + "manage-categories": "Kategorien verwalten", + "add-category": "Kategorie hinzufügen", + "jump-to": "Springen zu...", "settings": "Kategorieeinstellungen", - "edit-category": "Edit Category", + "edit-category": "Kategorie bearbeiten", "privileges": "Berechtigungen", - "back-to-categories": "Back to categories", + "back-to-categories": "Zurück zu Kategorien", "name": "Kategoriename", "description": "Kategorie-Beschreibung", "bg-color": "Hintergrundfarbe", @@ -19,11 +19,11 @@ "post-queue": "Warteschlange", "tag-whitelist": "Tag Whitelist", "upload-image": "Bild hochladen", - "upload": "Upload", - "select-icon": "Select Icon", + "upload": "Hochladen", + "select-icon": "Icon auswählen", "delete-image": "Entfernen", "category-image": "Kategoriebild", - "image-and-icon": "Image & Icon", + "image-and-icon": "Bild & Icon", "parent-category": "Übergeordnete Kategorie", "optional-parent-category": "(Optional) Übergeordnete Kategorie", "top-level": "Top Level", diff --git a/public/language/de/admin/manage/groups.json b/public/language/de/admin/manage/groups.json index 49119b854d..927acb195c 100644 --- a/public/language/de/admin/manage/groups.json +++ b/public/language/de/admin/manage/groups.json @@ -1,10 +1,10 @@ { - "manage-groups": "Manage Groups", - "add-group": "Add group", - "edit-group": "Edit Group", - "back-to-groups": "Back to groups", - "view-group": "View group", - "icon-and-title": "Icon & Title", + "manage-groups": "Gruppen verwalten", + "add-group": "Gruppe hinzufügen", + "edit-group": "Gruppe bearbeiten", + "back-to-groups": "Zurück zu Gruppen", + "view-group": "Gruppe anzeigen", + "icon-and-title": "Icon & Titel", "name": "Gruppenname", "badge": "Abzeichen", "properties": "Eigenschaften", @@ -16,7 +16,7 @@ "edit": "Ändern", "delete": "Löschen", "privileges": "Berechtigungen", - "members-csv": "Members (CSV)", + "members-csv": "Benutzer (CSV)", "search-placeholder": "Suchen", "create": "Gruppe erstellen", "description-placeholder": "Eine kurze Beschreibung deiner Gruppe", diff --git a/public/language/de/admin/manage/privileges.json b/public/language/de/admin/manage/privileges.json index 816c5e2d2d..a651c1320d 100644 --- a/public/language/de/admin/manage/privileges.json +++ b/public/language/de/admin/manage/privileges.json @@ -1,6 +1,6 @@ { - "manage-privileges": "Manage Privileges", - "discard-changes": "Discard changes", + "manage-privileges": "Berechtigungen verwalten", + "discard-changes": "Änderungen verwerfen", "global": "Global", "admin": "Administrator", "group-privileges": "Gruppen Rechte", diff --git a/public/language/de/admin/manage/tags.json b/public/language/de/admin/manage/tags.json index 64ec38aaeb..9cc615cfcf 100644 --- a/public/language/de/admin/manage/tags.json +++ b/public/language/de/admin/manage/tags.json @@ -1,11 +1,11 @@ { - "manage-tags": "Manage Tags", + "manage-tags": "Tags verwalten", "none": "Das Forum hat bisher noch keine Themen mit Tags.", "bg-color": "Hintergrundfarbe", "text-color": "Textfarbe", "description": "Wählen Sie Tags durch Klicken oder Ziehen aus, verwenden Sie STRG, um mehrere Tags auszuwählen.", "create": "Tag erstellen", - "add-tag": "Add tag", + "add-tag": "Tag hinzufügen", "modify": "Tag bearbeiten", "rename": "Tags umbenennen", "delete": "Ausgewählte Tags entfernen", diff --git a/public/language/de/admin/manage/uploads.json b/public/language/de/admin/manage/uploads.json index 84989bda5b..dbb3579e42 100644 --- a/public/language/de/admin/manage/uploads.json +++ b/public/language/de/admin/manage/uploads.json @@ -1,5 +1,5 @@ { - "manage-uploads": "Manage Uploads", + "manage-uploads": "Uploads verwalten", "upload-file": "Datei hochladen", "filename": "Dateiname", "usage": "Beitragsnutzung", diff --git a/public/language/de/admin/manage/users.json b/public/language/de/admin/manage/users.json index 73a0abb45e..98847bf3fe 100644 --- a/public/language/de/admin/manage/users.json +++ b/public/language/de/admin/manage/users.json @@ -1,5 +1,5 @@ { - "manage-users": "Manage Users", + "manage-users": "Benutzer verwalten", "users": "Benutzer", "edit": "Aktionen", "make-admin": "Zum Administrator befördern", @@ -50,10 +50,10 @@ "users.username": "Nutzername", "users.email": "E-Mail", "users.no-email": "(keine Email)", - "users.validated": "Validated", - "users.not-validated": "Not Validated", - "users.validation-pending": "Validation Pending", - "users.validation-expired": "Validation Expired", + "users.validated": "Bestätigt", + "users.not-validated": "Nicht bestätigt", + "users.validation-pending": "Bestätigung ausstehend", + "users.validation-expired": "Bestätigung abgelaufen", "users.ip": "IP", "users.postcount": "Anzahl der Beiträge", "users.reputation": "Ansehen", diff --git a/public/language/de/admin/menu.json b/public/language/de/admin/menu.json index e4edd966a8..b8d3f76e5b 100644 --- a/public/language/de/admin/menu.json +++ b/public/language/de/admin/menu.json @@ -72,9 +72,9 @@ "development/info": "Info", "rebuild-and-restart-forum": "Forum regenerieren & neustarten", - "rebuild-and-restart": "Rebuild & Restart", + "rebuild-and-restart": "Rebuild & Neustart", "restart-forum": "Forum neu starten", - "restart": "Restart", + "restart": "Neustarten", "logout": "Abmelden", "view-forum": "Forum anzeigen", diff --git a/public/language/de/admin/settings/advanced.json b/public/language/de/admin/settings/advanced.json index 1f75026bc5..9310b773b2 100644 --- a/public/language/de/admin/settings/advanced.json +++ b/public/language/de/admin/settings/advanced.json @@ -3,7 +3,7 @@ "maintenance-mode.help": "Wenn sich das Forum im Wartungsmodus befindet, werden alle Anfragen auf eine statische Warteseite umgeleitet. Administratoren sind von dieser Umleitung ausgenommen und können normal auf die Site zugreifen.", "maintenance-mode.status": "Statuscode für Wartungsmodus", "maintenance-mode.message": "Wartungsnachricht", - "maintenance-mode.groups-exempt-from-maintenance-mode": "Select groups that should be exempt from maintenance mode", + "maintenance-mode.groups-exempt-from-maintenance-mode": "Wähle Gruppen, welche vom Wartungsmodus ausgenommen werden sollen", "headers": "Headers", "headers.allow-from": "ALLOW-FROM setzen um NodeBB in einem iFrame zu platzieren", "headers.csp-frame-ancestors": "Content-Security-Policy frame-ancestors header setzen, um NodeBB in einem iFrame zu platzieren", @@ -20,8 +20,8 @@ "headers.coep-help": "Wenn aktiviert (Standard), wird der Header auf require-corp gesetzt", "headers.coop": "Cross-Origin-Opener-Policy", "headers.corp": "Cross-Origin-Resource-Policy", - "headers.permissions-policy": "Permissions-Policy", - "headers.permissions-policy-help": "Allows setting permissions policy header, for example \"geolocation=*, camera=()\", see this for more info.", + "headers.permissions-policy": "Berechtigungs-Richtlinie", + "headers.permissions-policy-help": "Erlaubt das Setzen eines Headers für die Berechtigungs-Richtlinie, z. B. \"geolocation=*, camera=()\". Siehe hier für mehr Informationen.", "hsts": "Strict Transport Security", "hsts.enabled": "HSTS Aktivieren (empfohlen)", "hsts.maxAge": "HSTS Maximales Alter", diff --git a/public/language/de/admin/settings/api.json b/public/language/de/admin/settings/api.json index 0248bc09cc..37deb3c67e 100644 --- a/public/language/de/admin/settings/api.json +++ b/public/language/de/admin/settings/api.json @@ -3,7 +3,7 @@ "settings": "Einstellungen", "lead-text": "Auf dieser Seite kanst Du den Zugriff auf die Write-API in NodeBB konfigurieren.", "intro": "Standardmäßig authentifiziert die Write-API Benutzer basierend auf ihrem Sitzungscookie, aber NodeBB unterstützt auch die Bearer-Authentifizierung über Token, die über diese Seite generiert werden.", - "warning": "Be advised — treat tokens like passwords. If they are leaked, your account should be considered compromised.", + "warning": "Hinweis — Behandle Tokens wie Passwörter. Wenn diese geleakt werden, sollte Dein Account als kompromittiert behandelt werden.", "docs": "Klicke hier, um auf die vollständige API-Spezifikation zuzugreifen", "require-https": "API-Nutzung nur über HTTPS möglich", @@ -13,17 +13,17 @@ "token": "Token", "uid-help-text": "Gebe eine Benutzer-ID an, die diesem Token zugeordnet werden soll. Wenn die Benutzer-ID 0 ist, wird sie als Master-Token betrachtet, das basierend auf dem _uid-Parameter die Identität anderer Benutzer annehmen kann", "description": "Beschreibung", - "last-seen": "Last seen", - "created": "Created", - "create-token": "Create Token", - "update-token": "Update Token", - "master-token": "Master token", - "last-seen-never": "This key has never been used.", + "last-seen": "Zuletzt gesehen", + "created": "Erstellt", + "create-token": "Token erstellen", + "update-token": "Token aktualisieren", + "master-token": "Master-Token", + "last-seen-never": "Dieser Schlüssel wurde noch nie benutzt.", "no-description": "Keine Beschreibung angegeben.", - "actions": "Actions", - "edit": "Edit", - "roll": "Roll", + "actions": "Aktionen", + "edit": "Bearbeiten", + "roll": "Würfeln", - "delete-confirm": "Are you sure you wish to delete this token? It will not be recoverable.", - "roll-confirm": "Are you sure you wish to regenerate this token? The old token will be immediately revoked and will not be recoverable." + "delete-confirm": "Bist Du Dir sicher, dass Du diesen Token löschen willst? Dieser kann nicht wiederhergestellt werden.", + "roll-confirm": "Bist Du Dir sicher, dass Du diesen Token neu generieren willst? Der alte Token verliert sofort seine Gültigkeit und kann nicht wiederhergestellt werden." } \ No newline at end of file diff --git a/public/language/de/admin/settings/email.json b/public/language/de/admin/settings/email.json index 9c6e6c9bb0..1eca3b3fe7 100644 --- a/public/language/de/admin/settings/email.json +++ b/public/language/de/admin/settings/email.json @@ -42,7 +42,7 @@ "subscriptions.hour-help": "Bitte geben Sie eine Nummer ein, welche die Stunde repräsentiert zu welcher geplante Emails versandt werden sollen (z.B. 0 für Mitternacht, 17 für 5 Uhr Nachmittags). Beachten Sie, dass die Zeit auf der Serverzeit basiert und daher nicht umbedingt mit ihrer Systemzeit übereinstimmen muss.
Die ungefähre Serverzeit ist:
Die nächste tägliche Sendung ist um geplant", "notifications.remove-images": "Bilder aus E-Mail-Benachrichtigungen entfernen", "require-email-address": "Neue Benutzer auffordern, eine E-Mail-Adresse anzugeben", - "require-email-address-warning": "By default, users can opt-out of entering an email address by leaving the field blank. Enabling this option means new users will have to enter and confirm an email address in order to proceed with registration and subsequent access to the forum. It does not ensure user will enter a real email address, nor even an address they own.", + "require-email-address-warning": "Standardmäßig können Benutzer die Eingabe einer E-Mail-Adresse ablehnen, indem sie das Feld leer lassen. Wenn Du diese Option aktivierst, müssen neue Benutzer eine E-Mail-Adresse eingeben und diese bestätigen, um mit der Registrierung fortzufahren und Zugang zum Forum zu erhalten. Es stellt weder sicher, dass der Benutzer eine echte E-Mail-Adresse eingibt, noch, dass eine Adresse ihm gehört.", "send-validation-email": "Validierungs-E-Mails senden, wenn eine E-Mail hinzugefügt oder geändert wird", "include-unverified-emails": "E-Mails an Empfänger senden, die ihre E-Mails nicht explizit bestätigt haben", "include-unverified-warning": "Standardmäßig wurden Benutzer mit E-Mail-Adressen, die mit ihrem Konto verknüpft sind, bereits verifiziert, aber es existieren Situationen, in denen dies nicht der Fall ist (z. B. SSO-Anmeldungen, Großvater-Benutzer usw.). Aktiviere diese Einstellung auf eigenes Risiko – Das Senden von E-Mails an nicht verifizierte Adressen kann einen Verstoß gegen regionale Anti-Spam-Gesetze darstellen.", diff --git a/public/language/de/admin/settings/general.json b/public/language/de/admin/settings/general.json index 3a0f5e8512..7fd7af5cde 100644 --- a/public/language/de/admin/settings/general.json +++ b/public/language/de/admin/settings/general.json @@ -1,13 +1,13 @@ { - "general-settings": "General Settings", - "on-this-page": "On this page:", + "general-settings": "Allgemeine Einstellungen", + "on-this-page": "Auf dieser Seite:", "site-settings": "Forum Einstellungen", "title": "Forum Titel", "title.short": "Kurzbezeichnung", "title.short-placeholder": "Wenn kein Kurztitel angegeben ist, wird der Forum-Titel verwendet.", "title.url": "Titel Link-URL", "title.url-placeholder": "Die URL des Seitentitels", - "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index. Note: This is not the external URL used in emails, etc. That is set by the url property in config.json", + "title.url-help": "Wenn der Titel angeklickt wird, werden die Benutzer an diese Adresse weitergeleitet. Wenn nichts angegeben wird, werden Benutzer zum Forum-Index weitergeleitet. Hinweis: Dies ist nicht die externe URL, die in E-Mails etc. verwendet wird. Diese wird über die Eigenschaft url in config.json festgelegt.", "title.name": "Name Deiner Community", "title.show-in-header": "Titel im Header anzeigen", "browser-title": "Browser Titel", @@ -18,7 +18,7 @@ "description": "Forum Beschreibung", "keywords": "Forum Schlüsselworte", "keywords-placeholder": "Schlüsselworte, die ihre Community beschreiben, mit Komma getrennt", - "logo-and-icons": "Site Logo & Icons", + "logo-and-icons": "Website-Logo & Icons", "logo.image": "Bild", "logo.image-placeholder": "Pfad zu einem Logo, welches im Header des Forums angezeigt werden soll", "logo.upload": "Hochladen", diff --git a/public/language/de/admin/settings/guest.json b/public/language/de/admin/settings/guest.json index 56dbc50c1c..0007092f0b 100644 --- a/public/language/de/admin/settings/guest.json +++ b/public/language/de/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Einstellungen", - "guest-settings": "Guest settings", + "guest-settings": "Gasteinstellungen", "handles.enabled": "Gastzugänge erlauben", "handles.enabled-help": "Diese Option zeigt ein neues Feld an, in dem Gäste einen Namen auswählen können, der jedem von ihnen erstellten Beitrag zugeordnet werden soll. Wenn sie deaktiviert sind, werden sie einfach „Gast“ genannt.", "topic-views.enabled": "Gästen erlauben, die gezählte Anzahl der Themenaufrufe zu erhöhen", diff --git a/public/language/de/admin/settings/navigation.json b/public/language/de/admin/settings/navigation.json index 8e152b503b..0fe6f19e9c 100644 --- a/public/language/de/admin/settings/navigation.json +++ b/public/language/de/admin/settings/navigation.json @@ -13,7 +13,7 @@ "groups": "Gruppen:", "open-new-window": "In neuem Fenster öffnen", "dropdown": "Dropdown", - "dropdown-placeholder": "Place your dropdown menu items below, ie:
<li><a class="dropdown-item" href="https://myforum.com">Link 1</a></li>", + "dropdown-placeholder": "Platziere deine Dropdown-Menüpunkte unten, d. h.:
<li><a class="dropdown-item" href="https://myforum.com">Link 1</a></li>", "btn.delete": "Löschen", "btn.disable": "Deaktivieren", diff --git a/public/language/de/admin/settings/post.json b/public/language/de/admin/settings/post.json index f5bee5e51d..3e96171244 100644 --- a/public/language/de/admin/settings/post.json +++ b/public/language/de/admin/settings/post.json @@ -1,5 +1,5 @@ { - "general": "General", + "general": "Allgemein", "sorting": "Beitragssortierung", "sorting.post-default": "Standardmäßige sortierung von Beiträgen", "sorting.oldest-to-newest": "Von Alt bis Neu", @@ -24,8 +24,8 @@ "restrictions.seconds-edit-after": "Anzahl der Sekunden, die ein Beitrag bearbeitet werden kann (zum Deaktivieren auf 0 setzen)", "restrictions.seconds-delete-after": "Anzahl der Sekunden, die ein Beitrag löschbar bleibt (zum Deaktivieren auf 0 setzen)", "restrictions.replies-no-delete": "Anzahl der Antworten, nachdem Benutzern das Löschen ihrer eigenen Themen verweigert wurde (zum Deaktivieren auf 0 setzen)", - "restrictions.title-length": "Title Length", - "restrictions.post-length": "Post Length", + "restrictions.title-length": "Titellänge", + "restrictions.post-length": "Beitragslänge", "restrictions.days-until-stale": "Tage bis ein Thema als alt angesehen wird", "restrictions.stale-help": "Wenn ein Thema als \"veraltet\" angesehen wird, wird Nutzern die versuchen diesem Thema zu antworten eine Warnung gezeigt", "timestamp": "Zeitstempel", @@ -40,7 +40,7 @@ "teaser.last-reply": "Letzter - Den neuesten Beitrag oder einen \"Keine Antworten\" Platzhalter, wenn es keine Antworten gibt anzeigen", "teaser.first": "Erster", "showPostPreviewsOnHover": "Eine Vorschau der Beiträge zeigen, wenn Du mit der Maus darüber fährst", - "unread-and-recent": "Unread & Recent Settings", + "unread-and-recent": "Ungelesene & neue Einstellungen", "unread.cutoff": "Ungelesen-Limit (in Tagen)", "unread.min-track-last": "Minimale Anzahl an Beiträgen pro Thema bevor die letzte Sichtung mitgeschrieben wird", "recent.max-topics": "Maximale Themen auf /recent", diff --git a/public/language/de/admin/settings/reputation.json b/public/language/de/admin/settings/reputation.json index 230fa4d142..1f98481e0a 100644 --- a/public/language/de/admin/settings/reputation.json +++ b/public/language/de/admin/settings/reputation.json @@ -27,5 +27,5 @@ "flags.action-on-resolve": "Führe Folgendes aus, wenn eine Flagge aufgelöst wird", "flags.action-on-reject": "Gehe folgendermaßen vor, wenn eine Flagge abgelehnt wird", "flags.action.nothing": "Nichts tun", - "flags.action.rescind": "Rescind the notification sent to moderators/administrators" + "flags.action.rescind": "Zurückziehen der Benachrichtigung an Moderatoren/Administratoren" } \ No newline at end of file diff --git a/public/language/de/admin/settings/tags.json b/public/language/de/admin/settings/tags.json index 4c20332297..adbc0cefaf 100644 --- a/public/language/de/admin/settings/tags.json +++ b/public/language/de/admin/settings/tags.json @@ -3,7 +3,7 @@ "link-to-manage": "Tags managen", "system-tags": "System-Tags", "system-tags-help": "Nur berechtige Benutzer können diese Tags verwenden.", - "tags-per-topic": "Tags per topic", + "tags-per-topic": "Tags pro Thema", "min-per-topic": "Minimale Tags pro Thema", "max-per-topic": "Maximale Tags pro Thema", "min-length": "Minimale Tag Länge", diff --git a/public/language/de/admin/settings/user.json b/public/language/de/admin/settings/user.json index f995ca135f..d5af67d6d1 100644 --- a/public/language/de/admin/settings/user.json +++ b/public/language/de/admin/settings/user.json @@ -29,8 +29,8 @@ "session-time-days": "Tage", "session-time-seconds": "Sekunden", "session-time-help": "Diese Werte legen fest, wie lange ein Benutzer angemeldet bleibt, wenn er die Option "Eingeloggt bleiben" beim Login aktiviert. Beachte, dass nur einer dieser Werte verwendet wird. Wenn Sekunden nicht festgelegt wurden, greifen wir auf Tage zurück. Wenn Tage nicht festlegt wurden, werden standardmäßig 14 Tage verwendet.", - "session-duration": "Session length if \"Remember Me\" is not checked (seconds)", - "session-duration-help": "By default — or if set to 0 — a user will stay logged in for the duration of the session (e.g. however long the browser window/tab remains open). Set this value to explicitly invalidate the session after the specified number of seconds.", + "session-duration": "Sitzungslänge, wenn \"Eingeloggt bleiben\" nicht ausgewählt ist (Sekunden)", + "session-duration-help": "Standardmäßig — oder wenn auf 0 gesetzt — bleibt ein Benutzer für die Dauer seiner Session angemeldet (d. h. solange das Browserfenster/der Tab geöffnet bleibt). Durch das Setzen dieser Einstellung wird die Session nach der angegebenen Anzahl an Sekunden ungültig gesetzt.", "online-cutoff": "Minuten nachdem der Benutzer als inaktiv betrachtet wird", "online-cutoff-help": "Wenn der Benutzer für diese Dauer keine Aktionen ausführt, wird er als inaktiv betrachtet und erhält keine Echtzeit-Updates.", "registration": "Benutzer Registrierung", @@ -59,7 +59,7 @@ "max-about-me-length": "Maximale länge von Über Mich", "terms-of-use": "Forum Nutzungsbedingungen (Leer lassen um es zu deaktivieren)", "user-search": "Benutzersuche", - "user-search-results-per-page": "Number of users to display in search results", + "user-search-results-per-page": "Anzahl Benutzer, die in der Suche angezeigt werden", "default-user-settings": "Standard Benutzer Einstellungen", "show-email": "Zeige E-Mail-Adresse", "show-fullname": "Zeige vollen Namen", diff --git a/public/language/de/error.json b/public/language/de/error.json index 7bef0f0167..ca93bf67d8 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -42,7 +42,7 @@ "user-doesnt-have-email": "Für den Benutzer \"%1\" ist keine E-Mail eingetragen.", "email-confirm-failed": "Wir konnten deine E-Mail-Adresse nicht bestätigen, bitte versuch es später noch einmal", "confirm-email-already-sent": "Die Bestätigungsmail wurde verschickt. Bitte warte %1 Minute(n), um eine weitere zu verschicken.", - "confirm-email-expired": "Confirmation email expired", + "confirm-email-expired": "Bestätigungs-E-Mail abgelaufen", "sendmail-not-found": "Sendmail wurde nicht gefunden. Bitte stelle sicher, dass es installiert ist und durch den Benutzer unter dem NodeBB läuft ausgeführt werden kann.", "digest-not-enabled": "Dieser Benutzer hat Email-Zusammenfassungen deaktiviert oder das Aussenden von Email-Zusammenfassungen is in den Defaulteinstellungen des Systems nicht aktiviert.", "username-too-short": "Benutzername ist zu kurz", @@ -63,7 +63,7 @@ "no-user": "Der Benutzer existiert nicht", "no-teaser": "Zusammenfassung existiert nicht", "no-flag": "Markierung existiert nicht", - "no-chat-room": "Chat room does not exist", + "no-chat-room": "Der Chatroom existiert nicht", "no-privileges": "Du verfügst nicht über ausreichende Berechtigungen, um die Aktion durchzuführen.", "category-disabled": "Kategorie ist deaktiviert", "topic-locked": "Thema ist gesperrt", @@ -90,10 +90,10 @@ "category-not-selected": "Kategorie nicht ausgewählt", "too-many-posts": "Du kannst nur einen Beitrag innerhalb von %1 Sekunden erstellen - Bitte warte bevor Du erneut einen Beitrag erstellst.", "too-many-posts-newbie": "Als neuer Benutzer kannst du nur einmal alle %1 Sekunde(n) posten, bis du %2 Reputation erworben hast - bitte warte, bevor du erneut postest", - "already-posting": "You are already posting", + "already-posting": "Du bist bereits am Posten", "tag-too-short": "Bitte gebe ein längeres Schlagwort ein. Schlagworte sollten mindestens %1 Zeichen enthalten.", "tag-too-long": "Bitte gebe ein kürzeres Schlagwort ein. Schlagworte können nicht länger als %1 Zeichen sein.", - "tag-not-allowed": "Tag not allowed", + "tag-not-allowed": "Tag nicht erlaubt", "not-enough-tags": "Nicht genügend Schlagworte. Themen müssen mindestens %1 Schlagwort(e) enthalten", "too-many-tags": "Zu viele Schlagworte. Themen dürfen nicht mehr als %1 Schlagwort(e) enthalten", "cant-use-system-tag": "Sie können dieses System-Tag nicht verwenden.", @@ -103,7 +103,7 @@ "guest-upload-disabled": "Uploads für Gäste wurden deaktiviert.", "cors-error": "Das Hochladen von Bildern ist aufgrund von falsch konfigurierten CORS nicht möglich.", "upload-ratelimit-reached": "Sie haben zu viele Dateien auf einmal hochgeladen. Bitte versuchen Sie es später noch einmal.", - "upload-error-fallback": "Unable to upload image — %1", + "upload-error-fallback": "Bild konnte nicht hochgeladen werden — %1", "scheduling-to-past": "Wählen Sie bitte ein Datum in der Zukunft.", "invalid-schedule-date": "Geben Sie bitte ein gültiges Datum und eine Uhrzeit ein.", "cant-pin-scheduled": "Geplante Themen können nicht (un)angeheftet werden.", @@ -137,8 +137,8 @@ "group-already-requested": "Deine Mitgliedsanfrage wurde bereits eingereicht", "group-join-disabled": "Du kannst dieser Gruppe zur Zeit nicht beitreten", "group-leave-disabled": "Du kannst diese Gruppe zur Zeit nicht verlassen", - "group-user-not-pending": "User does not have a pending request to join this group.", - "gorup-user-not-invited": "User has not been invited to join this group.", + "group-user-not-pending": "Benutzer hat keine ausstehende Anfrage zum Beitritt dieser Gruppe", + "gorup-user-not-invited": "Benutzer wurde nicht zur Gruppe eingeladen", "post-already-deleted": "Dieser Beitrag ist bereits gelöscht worden", "post-already-restored": "Dieser Beitrag ist bereits wiederhergestellt worden", "topic-already-deleted": "Dieses Thema ist bereits gelöscht worden", @@ -161,10 +161,10 @@ "chat-delete-duration-expired": "Du darfst Chat-Nachrichten nur bis zu %1 Sekunde(n) nach der erstellung löschen", "chat-deleted-already": "Diese Chatnachricht wurde bereits gelöscht.", "chat-restored-already": "Diese Chatnachricht wurde bereits wiederhergestellt.", - "chat-room-does-not-exist": "Der Chatraum existiert nicht.", - "cant-add-users-to-chat-room": "Can't add users to chat room.", - "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-does-not-exist": "Der Chatroom existiert nicht.", + "cant-add-users-to-chat-room": "Kann Benutzer nicht zu Chatroom hinzufügen", + "cant-remove-users-from-chat-room": "Kann Benutzer nicht aus Chatroom entfernen.", + "chat-room-name-too-long": "Name des Chatrooms zu lang.", "already-voting-for-this-post": "Du hast diesen Beitrag bereits bewertet.", "reputation-system-disabled": "Das Reputationssystem ist deaktiviert.", "downvoting-disabled": "Downvotes sind deaktiviert.", @@ -230,5 +230,5 @@ "api.500": "Beim Versuch, Ihre Anfrage zu bearbeiten, ist ein unerwarteter Fehler aufgetreten.", "api.501": "Die Route, die Sie anrufen möchten, ist noch nicht implementiert. Bitte versuchen Sie es morgen erneut", "api.503": "Die Route, die Sie anrufen möchten, ist derzeit aufgrund einer Serverkonfiguration nicht verfügbar", - "api.reauth-required": "The resource you are trying to access requires (re-)authentication." + "api.reauth-required": "Die angeforderte Ressource erfordert eine (Re-)Authentifizierung." } \ No newline at end of file diff --git a/public/language/de/flags.json b/public/language/de/flags.json index 7fb7563221..8c8d5eda3b 100644 --- a/public/language/de/flags.json +++ b/public/language/de/flags.json @@ -3,27 +3,27 @@ "reports": "Reports", "first-reported": "Zuerst gemeldet", "no-flags": "Hurra! Keine Meldungen gefunden.", - "x-flags-found": "%1 flag(s) found.", + "x-flags-found": "%1 Flags gefunden.", "assignee": "Zugeordneter Benutzer", "update": "Aktualisieren", "updated": "Aktualisiert", "resolved": "Gelöst", "target-purged": "Der Inhalt auf den diese Meldung hingewiesen hat, wurde gelöscht und ist nicht mehr verfügbar.", - "target-aboutme-empty": "This user has no "About Me" set.", + "target-aboutme-empty": "Dieser Benutzer hat kein \"Über mich\" gesetzt.", "graph-label": "Tägliche Meldungen", "quick-filters": "Schnell-Filter", "filter-active": "Ein oder mehrere Filter sind in dieser Meldungs-Liste aktiv", "filter-reset": "Filter Entfernen", "filters": "Filter Optionen", - "filter-reporterId": "Reporter", - "filter-targetUid": "Reportee", + "filter-reporterId": "Meldender", + "filter-targetUid": "Gemeldeter", "filter-type": "Meldungstyp", "filter-type-all": "Gesamter Inhalt", "filter-type-post": "Beitrag", "filter-type-user": "Benutzer", "filter-state": "Status", - "filter-assignee": "Assignee", + "filter-assignee": "Zugewiesener Benutzer", "filter-cid": "Kategorie", "filter-quick-mine": "Mir zugewiesen", "filter-cid-all": "Alle Kategorien", @@ -47,7 +47,7 @@ "notes": "Meldungsnotizen", "add-note": "Notiz hinzufügen", - "edit-note": "Edit Note", + "edit-note": "Notiz bearbeiten", "no-notes": "Keine geteilten Notizen", "delete-note-confirm": "Bist du sicher, dass du diese Notiz löschen möchtest?", "delete-flag-confirm": "Möchtest Du diese Markierung wirklich löschen?", diff --git a/public/language/de/global.json b/public/language/de/global.json index aa86f77ece..7c2a8bb749 100644 --- a/public/language/de/global.json +++ b/public/language/de/global.json @@ -4,13 +4,13 @@ "buttons.close": "Schließen", "403.title": "Zugriff verweigert", "403.message": "Du hast keine Zugriffsberechtigung für diese Seite.", - "403.login": "Perhaps you should try logging in?", + "403.login": "Du solltest Dich anmelden.", "404.title": " Nicht Gefunden", - "404.message": "You seem to have stumbled upon a page that does not exist.
Return to the home page.
", + "404.message": "Du bist über eine nicht vorhandene Seite gestolpert.
Zur Startseite zurückkehren.
", "500.title": "Interner Fehler.", "500.message": "Ups! Scheint als wäre etwas schief gelaufen!", "400.title": "Ungültige Anforderung", - "400.message": "It looks like this link is malformed, please double-check and try again.
Return to the home page.
", + "400.message": "Es scheint als wäre dieser Link fehlerhaft, bitte überprüfe ihn und versuche es erneut.
Gehe zurück zur Startseite.
", "register": "Registrieren", "login": "Anmelden", "please_log_in": "Bitte anmelden", @@ -20,8 +20,8 @@ "you_have_successfully_logged_in": "Du hast dich erfolgreich angemeldet", "save_changes": "Änderungen speichern", "save": "Speichern", - "create": "Create", - "cancel": "Cancel", + "create": "Erstellen", + "cancel": "Abbrechen", "close": "Schließen", "pagination": "Seitennummerierung", "pagination.out_of": "%1 von %2", @@ -39,13 +39,13 @@ "header.notifications": "Benachrichtigungen", "header.search": "Suche", "header.profile": "Profil", - "header.account": "Account", + "header.account": "Konto", "header.navigation": "Navigation", - "header.manage": "Manage", - "header.drafts": "Drafts", + "header.manage": "Verwalten", + "header.drafts": "Entwürfe", "notifications.loading": "Benachrichtigungen werden geladen", "chats.loading": "Nachrichten werden geladen", - "drafts.loading": "Loading Drafts", + "drafts.loading": "Entwürfe werden geladen", "motd.welcome": "Willkommen auf NodeBB, der Diskussionsplattform der Zukunft.", "previouspage": "Vorherige Seite", "nextpage": "Nächste Seite", @@ -60,9 +60,9 @@ "users": "Benutzer", "topics": "Themen", "posts": "Beiträge", - "x-posts": "%1 posts", - "x-topics": "%1 topics", - "x-reputation": "%1 reputation", + "x-posts": "%1 Beiträge", + "x-topics": "%1 Themen", + "x-reputation": "%1 Reputation", "best": "Bestbewertet", "controversial": "Umstritten", "votes": "Stimmen", @@ -77,7 +77,7 @@ "reputation": "Ansehen", "lastpost": "Letzter Beitrag", "firstpost": "Erster Beitrag", - "about": "About", + "about": "Über", "read_more": "weiterlesen", "more": "Mehr", "none": "Nichts", @@ -91,7 +91,7 @@ "user_posted_ago": "%1 schrieb %2", "guest_posted_ago": "Gast schrieb %1", "last_edited_by": "zuletzt editiert von %1", - "edited-timestamp": "Edited %1", + "edited-timestamp": "Bearbeitet %1", "norecentposts": "Keine aktuellen Beiträge", "norecenttopics": "Keine aktuellen Themen", "recentposts": "Aktuelle Beiträge", @@ -133,9 +133,9 @@ "edited": "Bearbeitet", "disabled": "Deaktiviert", "select": "Auswählen", - "copied": "Copied", + "copied": "Kopiert", "user-search-prompt": "Gib hier etwas ein um Benutzer zu finden...", - "hidden": "Hidden", - "sort": "Sort", - "actions": "Actions" + "hidden": "Versteckt", + "sort": "Sortieren", + "actions": "Aktionen" } \ No newline at end of file diff --git a/public/language/de/groups.json b/public/language/de/groups.json index 5c192ff8ac..1a0457258a 100644 --- a/public/language/de/groups.json +++ b/public/language/de/groups.json @@ -1,7 +1,7 @@ { - "all-groups": "All groups", + "all-groups": "Alle Gruppen", "groups": "Gruppen", - "members": "Members", + "members": "Mitglieder", "view_group": "Gruppe zeigen", "owner": "Gruppenbesitzer", "new_group": "Neue Gruppe erstellen", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index 741c616cfb..1ee0f6f56b 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -1,11 +1,11 @@ { "chat.chatting_with": "Chatte mit", "chat.placeholder": "Gebe hier eine Chatnachricht ein, ziehe Bilder per Drag & Drop und drücke die Eingabetaste, um sie zu senden", - "chat.placeholder.mobile": "Type chat message here", - "chat.scroll-up-alert": "Go to most recent message", - "chat.usernames-and-x-others": "%1 & %2 others", - "chat.chat-with-usernames": "Chat with %1", - "chat.chat-with-usernames-and-x-others": "Chat with %1 & %2 others", + "chat.placeholder.mobile": "Hier Chatnachricht eingeben", + "chat.scroll-up-alert": "Zur neuesten Nachricht gehen", + "chat.usernames-and-x-others": "%1 & %2 andere", + "chat.chat-with-usernames": "Chatte mit %1", + "chat.chat-with-usernames-and-x-others": "Chatte mit %1 & %2 anderen", "chat.send": "Senden", "chat.no_active": "Du hast keine aktiven Chats.", "chat.user_typing": "%1 tippt gerade ...", @@ -27,7 +27,7 @@ "chat.three_months": "3 Monate", "chat.delete_message_confirm": "Bist du sicher, dass du diese Nachricht löschen möchtest?", "chat.retrieving-users": "Rufe Benutzer ab", - "chat.manage-room": "Chat-Room managen", + "chat.manage-room": "Chatroom managen", "chat.add-user-help": "Suche hier nach Usern. Auswählen fügt den User hinzu. Der neue User wird nicht in der Lage sein Chat Nachrichten zu lesen, die geschrieben wurden bevor er der Konversation hinzugefügt wurde. Ausschließlich Raumbesitzer () können User von Chat Rooms entfernen.", "chat.confirm-chat-with-dnd-user": "Dieser Benutzer hat seinen Status auf DnD (Bitte nicht stören) gesetzt. Möchtest du dennoch mit ihm chatten?", "chat.rename-room": "Raum umbenennen", @@ -46,7 +46,7 @@ "composer.compose": "Verfassen", "composer.show_preview": "Vorschau zeigen", "composer.hide_preview": "Vorschau ausblenden", - "composer.help": "Help", + "composer.help": "Hilfe", "composer.user_said_in": "%1 sagte in %2:", "composer.user_said": "%1 sagte:", "composer.discard": "Bist du sicher, dass du diesen Beitrag verwerfen möchtest?", @@ -69,11 +69,11 @@ "composer.schedule-date": "Datum", "composer.schedule-time": "Zeit", "composer.cancel-scheduling": "Planung abbrechen", - "composer.change-schedule-date": "Change Date", + "composer.change-schedule-date": "Datum ändern", "composer.set-schedule-date": "Datum einstellen", - "composer.discard-all-drafts": "Discard all drafts", - "composer.no-drafts": "You have no drafts", - "composer.discard-draft-confirm": "Do you want to discard this draft?", + "composer.discard-all-drafts": "Alle Entwürfe verwerfen", + "composer.no-drafts": "Keine Entwürfe vorhanden", + "composer.discard-draft-confirm": "Möchtest Du diesen Entwurf verwerfen?", "bootbox.ok": "OK", "bootbox.cancel": "Abbrechen", "bootbox.confirm": "Bestätigen", diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 004efbd804..07d2c7e72c 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -14,7 +14,7 @@ "flagged-content": "Gemeldeter Inhalt", "ip-blacklist": "IP Blacklist", "post-queue": "Beitragswarteschlange", - "registration-queue": "Registration Queue", + "registration-queue": "Warteliste", "users/online": "Benutzer online", "users/latest": "Neuste Benutzer", "users/sort-posts": "Benutzer mit den meisten Beiträgen", @@ -50,7 +50,7 @@ "account/watched_categories": "Beobachtete Kategorien von %1", "account/bookmarks": "Lesezeichen von %1", "account/settings": "Benutzer-Einstellungen", - "account/settings-of": "Changing settings of %1", + "account/settings-of": "Einstellungen von %1 ändern", "account/watched": "Von %1 beobachtete Themen", "account/ignored": "Ignorierte Themen von %1", "account/upvoted": "Von %1 positiv bewertete Beiträge", @@ -61,7 +61,7 @@ "account/uploads": "Uploads von %1", "account/sessions": "Login-Sitzungen", "confirm": "E-Mail bestätigt", - "maintenance.text": "%1 is currently undergoing maintenance.
Please come back another time.", + "maintenance.text": "%1 befindet sich derzeit in der Wartung.
Bitte komme später wieder.", "maintenance.messageIntro": "Zusätzlich hat der Administrator diese Nachricht hinterlassen:", "throttled.text": "%1 ist momentan aufgrund von Überlastung nicht verfügbar. Bitte komm später wieder." } \ No newline at end of file diff --git a/public/language/de/post-queue.json b/public/language/de/post-queue.json index babd93f44a..9afe19ad05 100644 --- a/public/language/de/post-queue.json +++ b/public/language/de/post-queue.json @@ -1,12 +1,12 @@ { "post-queue": "Beitragswarteschlange", - "no-queued-posts": "There are no posts in the post queue.", - "no-single-post": "The topic or post you are looking for is no longer in the queue. It has likely been approved or deleted already.", - "enabling-help": "To enable this feature, go to Settings → Post → Post Queue and enable Post Queue.", - "back-to-list": "Back to Post Queue", + "no-queued-posts": "Es sind keine Beiträge in der Beitragswarteschlange", + "no-single-post": "Dieses Thema oder dieser Beitrag ist nicht mehr in der Warteschlange. Er wurde wahrscheinlich angenommen oder gelöscht.", + "enabling-help": "Um diese Funktion zu aktivieren, gehe zu Einstellungen → Posts → Beitragswarteschlange und aktiviere die Beitragswarteschlange.", + "back-to-list": "Zurück zur Beitragswarteschlange", "user": "Benutzer", - "when": "When", + "when": "Wann", "category": "Kategorie", "title": "Titel", "content": "Inhalt", @@ -23,7 +23,7 @@ "notify": "Benachrichtigen", "notify-user": "Benutzer benachrichtigen", "confirm-reject": "Möchtest Du diesen Beitrag ablehnen?", - "confirm-remove": "Do you want to remove this post?", + "confirm-remove": "Möchtest Du diesen Beitrag entfernen?", "bulk-actions": "Massenaktionen", "accept-all": "Alle akzeptieren", "accept-selected": "Ausgewählte akzeptieren", @@ -31,10 +31,10 @@ "reject-all-confirm": "Möchtest Du alle Beiträge ablehnen?", "reject-selected": "Ausgewählte ablehnen", "reject-selected-confirm": "Möchtest Du %1 ausgewählte Beiträge ablehnen?", - "remove-all": "Remove all", - "remove-all-confirm": "Do you want to remove all posts?", - "remove-selected": "Remove Selected", - "remove-selected-confirm": "Do you want to remove %1 selected posts?", + "remove-all": "Alle entfernen", + "remove-all-confirm": "Möchtest Du alle Beiträge entfernen?", + "remove-selected": "Ausgewählte entfernen", + "remove-selected-confirm": "Möchtest Du %1 ausgewählte Beiträge entfernen?", "bulk-accept-success": "%1 Beiträge akzeptiert", "bulk-reject-success": "%1 Beiträge abgelehnt" } \ No newline at end of file diff --git a/public/language/de/recent.json b/public/language/de/recent.json index 7f007472c0..8305fdd38b 100644 --- a/public/language/de/recent.json +++ b/public/language/de/recent.json @@ -7,5 +7,5 @@ "alltime": "Gesamter Zeitraum", "no_recent_topics": "Es gibt keine aktuellen Themen.", "no_popular_topics": "Es gibt keine beliebten Themen.", - "load-new-posts": "Load new posts" + "load-new-posts": "Neue Beiträge laden" } \ No newline at end of file diff --git a/public/language/de/register.json b/public/language/de/register.json index eb2f6f335b..c82ce59f50 100644 --- a/public/language/de/register.json +++ b/public/language/de/register.json @@ -1,6 +1,6 @@ { "register": "Registrieren", - "already-have-account": "Already have an account?", + "already-have-account": "Du hast bereits ein Konto?", "cancel_registration": "Registrierungsvorgang abbrechen", "help.email": "Deine E-Mail Adresse ist standardmäßig nicht öffentlich sichtbar.", "help.username_restrictions": "Einen einmaligen Benutzernamen. %1-%2 Zeichen. Andere Benutzer können dich mit @Benutzername anschreiben.", diff --git a/public/language/de/search.json b/public/language/de/search.json index 146eadba90..2dc958f823 100644 --- a/public/language/de/search.json +++ b/public/language/de/search.json @@ -1,41 +1,41 @@ { - "type-to-search": "Type to search", + "type-to-search": "Tippen, um zu suchen", "results_matching": "%1 Ergebnis(se) stimmen mit \"%2\" überein, (%3 Sekunden)", "no-matches": "Keine Ergebnisse gefunden", "advanced-search": "Erweiterte Suche", "in": "In", - "in-titles": "In titles", - "in-titles-posts": "In titles and posts", - "in-posts": "In posts", - "in-categories": "In categories", - "in-users": "In users", - "in-tags": "In tags", - "categories": "Categories", - "all-categories": "All categories", - "categories-x": "Categories: %1", - "categories-watched-categories": "Categories: Watched categories", - "type-a-category": "Type a category", + "in-titles": "In Titeln", + "in-titles-posts": "In Titeln und Beiträgen", + "in-posts": "In Beiträgen", + "in-categories": "In Kategorien", + "in-users": "In Benutzern", + "in-tags": "In Tags", + "categories": "Kategorien", + "all-categories": "Alle Kategorien", + "categories-x": "Kategorien: %1", + "categories-watched-categories": "Kategorien: Beobachtete Kategorien", + "type-a-category": "Kategorie eingeben", "tags": "Tags", "tags-x": "Tags: %1", - "type-a-tag": "Type a tag", + "type-a-tag": "Tag eingeben", "match-words": "Übereinstimmende Worte", - "match-all-words": "Match all words", - "match-any-word": "Match any word", + "match-all-words": "Alle Wörter abgleichen", + "match-any-word": "Irgendein Wort abgleichen", "all": "Alle", "any": "Alles", "posted-by": "Geschrieben von", - "posted-by-usernames": "Posted by: %1", - "type-a-username": "Type a username", + "posted-by-usernames": "Verfasst von %1", + "type-a-username": "Benutzernamen eingeben", "search-child-categories": "Suche in Unterkategorien", "has-tags": "Hat Markierungen", "reply-count": "Anzahl Antworten", - "replies": "Replies", - "replies-atleast-count": "Replies: At least %1", - "replies-atmost-count": "Replies: At most %1", + "replies": "Antworten", + "replies-atleast-count": "Antworten: Mindestens %1", + "replies-atmost-count": "Antworten: Maximal %1", "at-least": "Mindestens", "at-most": "Höchstens", "relevance": "Relevanz", - "time": "Time", + "time": "Zeit", "post-time": "Verfaßt am", "votes": "Stimmen", "newer-than": "Neuer als", @@ -48,22 +48,22 @@ "three-months": "Drei Monate", "six-months": "Sechs Monate", "one-year": "Ein Jahr", - "time-newer-than-86400": "Time: Newer than yesterday", - "time-older-than-86400": "Time: Older than yesterday", - "time-newer-than-604800": "Time: Newer than one week", - "time-older-than-604800": "Time: Older than one week", - "time-newer-than-1209600": "Time: Newer than two weeks", - "time-older-than-1209600": "Time: Older than two weeks", - "time-newer-than-2592000": "Time: Newer than one month", - "time-older-than-2592000": "Time: Older than one month", - "time-newer-than-7776000": "Time: Newer than three months", - "time-older-than-7776000": "Time: Older than three months", - "time-newer-than-15552000": "Time: Newer than six months", - "time-older-than-15552000": "Time: Older than six months", - "time-newer-than-31104000": "Time: Newer than one year", - "time-older-than-31104000": "Time: Older than one year", + "time-newer-than-86400": "Zeitraum: Neuer als gestern", + "time-older-than-86400": "Zeitraum: Älter als gestern", + "time-newer-than-604800": "Zeitraum: Neuer als eine Woche", + "time-older-than-604800": "Zeitraum: Älter als eine Woche", + "time-newer-than-1209600": "Zeitraum: Neuer als zwei Wochen", + "time-older-than-1209600": "Zeitraum: Älter als zwei Wochen", + "time-newer-than-2592000": "Zeitraum: Neuer als einen Monat", + "time-older-than-2592000": "Zeitraum: Älter als einen Monat", + "time-newer-than-7776000": "Zeitraum: Neuer als drei Monate", + "time-older-than-7776000": "Zeitraum: Älter als drei Monate", + "time-newer-than-15552000": "Zeitraum: Neuer als sechs Monate", + "time-older-than-15552000": "Zeitraum: Älter als sechs Monate", + "time-newer-than-31104000": "Zeitraum: Neuer als ein Jahr", + "time-older-than-31104000": "Zeitraum: Älter als ein Jahr", "sort-by": "Sortieren nach", - "sort": "Sort", + "sort": "Sortieren", "last-reply-time": "Zeitpunkt der letzten Antwort", "topic-title": "Thementitel", "topic-votes": "Themenstimmen", @@ -74,36 +74,36 @@ "category": "Kategorie", "descending": "In absteigender Reihenfolge", "ascending": "In aufsteigender Reihenfolge", - "sort-by-relevance-desc": "Sort by: Relevance in descending order", - "sort-by-relevance-asc": "Sort by: Relevance in ascending order", - "sort-by-timestamp-desc": "Sort by: Post time in descending order", - "sort-by-timestamp-asc": "Sort by: Post time in ascending order", - "sort-by-votes-desc": "Sort by: Votes in descending order", - "sort-by-votes-asc": "Sort by: Votes in ascending order", - "sort-by-topic.lastposttime-desc": "Sort by: Last reply time in descending order", - "sort-by-topic.lastposttime-asc": "Sort by: Last reply time in ascending order", - "sort-by-topic.title-desc": "Sort by: Topic title in descending order", - "sort-by-topic.title-asc": "Sort by: Topic title in ascending order", - "sort-by-topic.postcount-desc": "Sort by: Number of replies in descending order", - "sort-by-topic.postcount-asc": "Sort by: Number of replies in ascending order", - "sort-by-topic.viewcount-desc": "Sort by: Number of views in descending order", - "sort-by-topic.viewcount-asc": "Sort by: Number of views in ascending order", - "sort-by-topic.votes-desc": "Sort by: Topic votes in descending order", - "sort-by-topic.votes-asc": "Sort by: Topic votes in ascending order", - "sort-by-topic.timestamp-desc": "Sort by: Topic start date in descending order", - "sort-by-topic.timestamp-asc": "Sort by: Topic start date in ascending order", - "sort-by-user.username-desc": "Sort by: Username in descending order", - "sort-by-user.username-asc": "Sort by: Username in ascending order", - "sort-by-category.name-desc": "Sort by: Category in descending order", - "sort-by-category.name-asc": "Sort by: Category in ascending order", - "save": "Save", + "sort-by-relevance-desc": "Sortieren nach: Relevanz (absteigend)", + "sort-by-relevance-asc": "Sortieren nach: Relevanz (aufsteigend)", + "sort-by-timestamp-desc": "Sortieren nach: Beitragszeit (absteigend)", + "sort-by-timestamp-asc": "Sortieren nach: Beitragszeit (aufsteigend)", + "sort-by-votes-desc": "Sortieren nach: Bewertung (absteigend)", + "sort-by-votes-asc": "Sortieren nach: Bewertung (aufsteigend)", + "sort-by-topic.lastposttime-desc": "Sortieren nach: Letzter Beitrag (absteigend)", + "sort-by-topic.lastposttime-asc": "Sortieren nach: Letzter Beitrag (aufsteigend)", + "sort-by-topic.title-desc": "Sortieren nach: Titel (absteigend)", + "sort-by-topic.title-asc": "Sortieren nach: Titel (aufsteigend)", + "sort-by-topic.postcount-desc": "Sortieren nach: Anzahl an Antworten (absteigend)", + "sort-by-topic.postcount-asc": "Sortieren nach: Anzahl an Antworten (aufsteigend)", + "sort-by-topic.viewcount-desc": "Sortieren nach: Anzahl der Aufrufe (absteigend)", + "sort-by-topic.viewcount-asc": "Sortieren nach: Anzahl der Aufrufe (aufsteigend)", + "sort-by-topic.votes-desc": "Sortieren nach: Bewertung (absteigend)", + "sort-by-topic.votes-asc": "Sortieren nach: Bewertung (aufsteigend)", + "sort-by-topic.timestamp-desc": "Sortieren nach: Erstelldatum (absteigend)", + "sort-by-topic.timestamp-asc": "Sortieren nach: Erstelldatum (aufsteigend)", + "sort-by-user.username-desc": "Sortieren nach: Benutzername (absteigend)", + "sort-by-user.username-asc": "Sortieren nach: Benutzername (aufsteigend)", + "sort-by-category.name-desc": "Sortieren nach: Kategorie (absteigend)", + "sort-by-category.name-asc": "Sortieren nach: Kategorie (aufsteigend)", + "save": "Speichern", "save-preferences": "Einstellungen speichern", "clear-preferences": "Einstellungen löschen", "search-preferences-saved": "Sucheinstellungen gespeichert", "search-preferences-cleared": "Sucheinstellungen gelöscht", "show-results-as": "Ergebnisse anzeigen als", - "show-results-as-topics": "Show results as topics", - "show-results-as-posts": "Show results as posts", + "show-results-as-topics": "Ergebnisse anzeigen als Themen", + "show-results-as-posts": "Ergebnisse anzeigen als Beiträge", "see-more-results": "Weitere Ergebnisse anzeigen (%1)", "search-in-category": "Suche in \"%1\"" } \ No newline at end of file diff --git a/public/language/de/tags.json b/public/language/de/tags.json index d7b9423646..2f309b93f3 100644 --- a/public/language/de/tags.json +++ b/public/language/de/tags.json @@ -1,7 +1,7 @@ { - "all-tags": "All tags", + "all-tags": "Alle Tags", "no_tag_topics": "Es gibt keine Themen mit diesem Schlagwort.", - "no-tags-found": "No tags found", + "no-tags-found": "Keine Tags gefunden", "tags": "Schlagworte", "enter_tags_here": "Hier Schlagworte eingeben. Jeweils %1 bis %2 Zeichen.", "enter_tags_here_short": "Schlagworte eingeben...", diff --git a/public/language/de/themes/harmony.json b/public/language/de/themes/harmony.json index f915155306..041c938859 100644 --- a/public/language/de/themes/harmony.json +++ b/public/language/de/themes/harmony.json @@ -1,16 +1,16 @@ { "theme-name": "Harmony Theme", "skins": "Skins", - "collapse": "Collapse", - "expand": "Expand", - "login-register-to-search": "Login or register to search.", - "settings.title": "Theme settings", - "settings.enableQuickReply": "Enable quick reply", - "settings.centerHeaderElements": "Center header elements", - "settings.mobileTopicTeasers": "Show topic teasers on mobile", - "settings.stickyToolbar": "Sticky toolbar", - "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", - "settings.autohideBottombar": "Auto hide bottom bar", - "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", - "settings.chatModals": "Enable chat modals" + "collapse": "Einklappen", + "expand": "Ausklappen", + "login-register-to-search": "Anmelden oder registrieren, um zu suchen", + "settings.title": "Theme-Einstellungen", + "settings.enableQuickReply": "Schnelle Antworten aktivieren", + "settings.centerHeaderElements": "Header-Elemente zentrieren", + "settings.mobileTopicTeasers": "Themen-Vorschau auf Mobilgeräten anzeigen", + "settings.stickyToolbar": "Klebrige Toolbar", + "settings.stickyToolbar.help": "Die Toolbar auf Themen- und Kategorieseiten bleibt oben an der Seite kleben", + "settings.autohideBottombar": "Fußzeile automatisch verbergen", + "settings.autohideBottombar.help": "Die Fußzeile wird auf Mobilgeräten versteckt, sobald nach unten gescrollt wird", + "settings.chatModals": "Chatfenster aktivieren" } \ No newline at end of file diff --git a/public/language/de/themes/persona.json b/public/language/de/themes/persona.json index fdf9070861..93264e1d78 100644 --- a/public/language/de/themes/persona.json +++ b/public/language/de/themes/persona.json @@ -1,10 +1,10 @@ { - "settings.title": "Theme settings", - "settings.intro": "You can customise your theme settings here. Settings are stored on a per-device basis, so you are able to have different settings on different devices (phone, tablet, desktop, etc.)", + "settings.title": "Theme-Einstellungen", + "settings.intro": "Hier kannst Du Deine Theme-Einstellungen anpassen. Die Einstellungen werden auf dem aktuellen Gerät gespeichert, sodass die Einstellungen sich auf unterschiedlichen Geräten (Handy, Tablet, PC etc.) unterscheiden können.", "settings.mobile-menu-side": "Menüposition der mobilen Seiten umschalten", - "settings.autoHidingNavbar": "Automatically hide the navbar on scroll", - "settings.autoHidingNavbar-xs": "Very small screens (e.g. phones in portrait mode)", - "settings.autoHidingNavbar-sm": "Smaller screens (e.g. phones, some tablets)", - "settings.autoHidingNavbar-md": "Medium sized screens (e.g. tablets in landscape mode)", - "settings.autoHidingNavbar-lg": "Larger screens (e.g. desktop computers)" + "settings.autoHidingNavbar": "Navigationsleiste bei Scrollen automatisch verbergen", + "settings.autoHidingNavbar-xs": "Sehr kleine Bildschirme (z. B. Handys in aufrechter Anzeige)", + "settings.autoHidingNavbar-sm": "Kleinere Bildschirme (z. B. Handys, manche Tablets)", + "settings.autoHidingNavbar-md": "Mittelgroße Bildschirme (z. B. Tablets in seitlicher Anzeige)", + "settings.autoHidingNavbar-lg": "Größere Bildschirme (z. B. Computer-Bildschirme)" } \ No newline at end of file diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 03d1539bff..2bd15c587a 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -36,34 +36,34 @@ "scheduled": "Geplant", "moved": "Verschoben", "moved-from": "Verschoben von %1", - "copy-code": "Copy Code", + "copy-code": "Code kopieren", "copy-ip": "IP-Adresse Kopieren", "ban-ip": "IP-Adresse bannen", "view-history": "Verlauf bearbeiten", - "wrote-ago": "wrote ", - "wrote-on": "wrote on ", - "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", - "user-locked-topic-ago": "%1 locked this topic %2", - "user-locked-topic-on": "%1 locked this topic on %2", - "user-unlocked-topic-ago": "%1 unlocked this topic %2", - "user-unlocked-topic-on": "%1 unlocked this topic on %2", - "user-pinned-topic-ago": "%1 pinned this topic %2", - "user-pinned-topic-on": "%1 pinned this topic on %2", - "user-unpinned-topic-ago": "%1 unpinned this topic %2", - "user-unpinned-topic-on": "%1 unpinned this topic on %2", - "user-deleted-topic-ago": "%1 deleted this topic %2", - "user-deleted-topic-on": "%1 deleted this topic on %2", - "user-restored-topic-ago": "%1 restored this topic %2", - "user-restored-topic-on": "%1 restored this topic on %2", - "user-moved-topic-from-ago": "%1 moved this topic from %2 %3", - "user-moved-topic-from-on": "%1 moved this topic from %2 on %3", - "user-queued-post-ago": "%1 queued post for approval %3", - "user-queued-post-on": "%1 queued post for approval on %3", - "user-referenced-topic-ago": "%1 referenced this topic %3", - "user-referenced-topic-on": "%1 referenced this topic on %3", - "user-forked-topic-ago": "%1 forked this topic %3", - "user-forked-topic-on": "%1 forked this topic on %3", + "wrote-ago": "schrieb ", + "wrote-on": "schrieb am ", + "replied-to-user-ago": "antwortete an %3 ", + "replied-to-user-on": "antwortete an %3 am ", + "user-locked-topic-ago": "%1 sperrte dieses Thema %2", + "user-locked-topic-on": "%1 sperrte dieses Thema am %2", + "user-unlocked-topic-ago": "%1 entsperrte dieses Thema %2", + "user-unlocked-topic-on": "%1 entsperrte dieses Thema am %2", + "user-pinned-topic-ago": "%1 hat dieses Thema angepinnt %2", + "user-pinned-topic-on": "%1 hat dieses Thema am %2 angepinnt", + "user-unpinned-topic-ago": "%1 hat dieses Thema abgepinnt %2", + "user-unpinned-topic-on": "%1 hat dieses Thema am %2 abgepinnt", + "user-deleted-topic-ago": "%1 hat dieses Thema gelöscht %2", + "user-deleted-topic-on": "%1 hat dieses Thema am %2 gelöscht", + "user-restored-topic-ago": "%1 stellte dieses Thema wieder her %2", + "user-restored-topic-on": "%1 stellte dieses Thema am %2 wieder her", + "user-moved-topic-from-ago": "%1 verschob dieses Thema von %2 %3", + "user-moved-topic-from-on": "%1 verschob dieses Thema von %2 am %3", + "user-queued-post-ago": "%1 hat Beitrag für Überprüfung markiert %3", + "user-queued-post-on": "%1 hat Beitrag am %3 für Überprüfung markiert", + "user-referenced-topic-ago": "%1 hat auf dieses Thema verwiesen %3", + "user-referenced-topic-on": "%1 hat am %3 auf dieses Thema verwiesen", + "user-forked-topic-ago": "%1 hat dieses Thema aufgespalten %3", + "user-forked-topic-on": "%1 hat dieses Thema am %3 aufgespalten", "bookmark_instructions": "Klicke hier, um zum letzten gelesenen Beitrag des Themas zurückzukehren.", "flag-post": "Diesen Post melden", "flag-user": "Diesen Benutzer melden", @@ -102,7 +102,7 @@ "thread_tools.change_owner": "Besitzer ändern", "thread_tools.select_category": "Kategorie auswählen", "thread_tools.fork": "Thema aufspalten", - "thread_tools.tag": "Tag Topic", + "thread_tools.tag": "Thema taggen", "thread_tools.delete": "Thema löschen", "thread_tools.delete-posts": "Beiträge entfernen", "thread_tools.delete_confirm": "Bist du sicher, dass du dieses Thema löschen möchtest?", @@ -111,7 +111,7 @@ "thread_tools.purge": "Thema endgültig löschen", "thread_tools.purge_confirm": "Bist du sicher, dass du dieses Thema endgültig löschen möchtest?", "thread_tools.merge_topics": "Themen vereinen", - "thread_tools.merge": "Merge Topic", + "thread_tools.merge": "Themen zusammenführen", "topic_move_success": "Dieses Thema wird in Kürze nach \"%1\" verschoben. Klicken Sie hier, um den Vorgang rückgängig zu machen.", "topic_move_multiple_success": "Diese Themen werden in Kürze nach \"%1\" verschoben. Klicken Sie hier, um den Vorgang rückgängig zu machen.", "topic_move_all_success": "Alle Themen werden in Kürze nach \"%1\" verschoben. Klicken Sie hier, um den Vorgang rückgängig zu machen.", @@ -137,7 +137,7 @@ "post_moved": "Beitrag wurde verschoben!", "fork_topic": "Thema aufspalten", "enter-new-topic-title": "Neuen Thementitel eingeben", - "fork_topic_instruction": "Click the posts you want to fork, enter a title for the new topic and click fork topic", + "fork_topic_instruction": "Klicke auf die Beiträge, die aufgespalten werden sollen, gib einen Namen für das neue Thema an und klicke auf \"Thema aufspalten\"", "fork_no_pids": "Keine Beiträge ausgewählt!", "no-posts-selected": "Keine Beiträge ausgewählt!", "x-posts-selected": "%1 Beitrag(Beiträge) ausgewählt", @@ -152,19 +152,19 @@ "merge-new-title-for-topic": "Neuer Titel für das Thema", "topic-id": "Themen-ID", "move_posts_instruction": "Klicken Sie auf die Beiträge, die Sie verschieben möchten, und geben Sie dann eine Themen-ID ein oder gehen Sie zum Zielthema", - "move_topic_instruction": "Select the target category and then click move", + "move_topic_instruction": "Wähle die Ziel-Kategorie und klicke \"Verschieben\"", "change_owner_instruction": "Klicke auf die Beiträge, die einem anderen Benutzer zugeordnet werden sollen", "composer.title_placeholder": "Hier den Titel des Themas eingeben...", "composer.handle_placeholder": "Gib deinen Namen/Nick hier ein", - "composer.hide": "Hide", + "composer.hide": "Verstecken", "composer.discard": "Verwerfen", "composer.submit": "Absenden", "composer.additional-options": "Zusätzliche Optionen", - "composer.post-later": "Post Later", + "composer.post-later": "Später posten", "composer.schedule": "Zeitplan", "composer.replying_to": "Antworte auf %1", "composer.new_topic": "Neues Thema", - "composer.editing-in": "Editing post in %1", + "composer.editing-in": "Bearbeite Beitrag in %1", "composer.uploading": "Lade hoch...", "composer.thumb_url_label": "Vorschaubild-URL hier einfügen", "composer.thumb_title": "Vorschaubild zu diesem Thema hinzufügen", @@ -203,7 +203,7 @@ "last-post": "Letzter Beitrag", "go-to-my-next-post": "Zu meinem nächsten Beitrag gehen", "no-more-next-post": "Du hast keine weiteren Beiträge zu diesem Thema", - "post-quick-reply": "Quick reply", - "navigator.index": "Post %1 of %2", - "navigator.unread": "%1 unread" + "post-quick-reply": "Schnell antworten", + "navigator.index": "Beitrag %1 von %2", + "navigator.unread": "%1 ungelesen" } \ No newline at end of file diff --git a/public/language/de/user.json b/public/language/de/user.json index 3b3ae57418..8b3dc41545 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -43,7 +43,7 @@ "followers": "Follower", "following": "Folge ich", "blocks": "Blockiert", - "blocked-users": "Blocked users", + "blocked-users": "Blockierte Benutzer", "block_toggle": "Ent-/Blocken", "block_user": "User blockieren", "unblock_user": "User entblocken", @@ -69,7 +69,7 @@ "upload_new_picture": "Neues Bild hochladen", "upload_new_picture_from_url": "Neues Bild von URL hochladen", "current_password": "Aktuelles Passwort", - "new_password": "New Password", + "new_password": "Neues Passwort", "change_password": "Passwort ändern", "change_password_error": "Ungültiges Passwort!", "change_password_error_wrong_current": "Ihr derzeitiges Passwort ist ungültig!", @@ -117,8 +117,8 @@ "paginate_description": "Themen und Beiträge in Seiten aufteilen, anstatt unendlich zu scrollen", "topics_per_page": "Themen pro Seite", "posts_per_page": "Beiträge pro Seite", - "category-topic-sort": "Category topic sort", - "topic-post-sort": "Topic post sort", + "category-topic-sort": "Sortierung nach Kategorie", + "topic-post-sort": "Sortierung nach Thema", "max_items_per_page": "Maximal %1", "acp_language": "Sprache der Admin Seiten", "notifications": "Benachrichtigungen", @@ -141,8 +141,8 @@ "group-order-help": "Wähle eine Gruppe und ordne die Titel mit den Pfeiltasten", "no-group-title": "Kein Gruppentitel", "select-skin": "Einen Skin auswählen", - "default": "Default (%1)", - "no-skin": "No Skin", + "default": "Standard: (%1)", + "no-skin": "Kein Skin", "select-homepage": "Startseite", "homepage": "Startseite", "homepage_description": "Wähle eine Seite, die als Forumstartseite verwendet werden soll, aus oder 'Keine' um die Standardstartseite zu verwenden.", @@ -174,8 +174,8 @@ "info.moderation-note.success": "Moderationsnotiz gespeichert", "info.moderation-note.add": "Notitz hinzufügen", "sessions.description": "Auf dieser Seite kannst du alle aktiven Sitzungen in diesem Forum einsehen und bei Bedarf widerrufen. Du kannst deine eigene Sitzung widerrufen, indem du dich von deinem Konto abmeldest.", - "revoke-session": "Revoke Session", - "browser-version-on-platform": "%1 %2 on %3", + "revoke-session": "Widerrufen der Session", + "browser-version-on-platform": "%1 %2 auf %3", "consent.title": "Deine Rechte & Zustimmungen", "consent.lead": "Dieses Community-Forum sammelt und verarbeitet deine persönlichen Daten.", "consent.intro": "Wir verwenden diese Informationen ausschließlich, um Deine Erfahrungen in dieser Community zu personalisieren und Deine Beiträge dem Benutzerkonto zuzuordnen.

Wir bewahren diese Informationen für die Dauer Deines Benutzerkontos auf. Du kannst die Einwilligung jederzeit widerrufen, indem Du Dein Konto löschst.

Wenn Du Fragen oder Bedenken hast, empfehlen wir, dich an das Adminteam dieses Forums zu wenden.", @@ -204,5 +204,5 @@ "emailUpdate.required": "Dieses Feld ist erforderlich.", "emailUpdate.change-instructions": "An die eingegebene E-Mail-Adresse wird eine Bestätigungs-E-Mail mit einem eindeutigen Link gesendet. Durch den Zugriff auf diesen Link wird dein Eigentum an der E-Mail-Adresse bestätigt und diese wird in deinem Konto aktiv. Du kannst deine E-Mail-Adresse jederzeit auf deiner Kontoseite aktualisieren.", "emailUpdate.password-challenge": "Bitte gib dein Passwort ein, um dein Konto zu verifizieren.", - "emailUpdate.pending": "Your email address has not yet been confirmed, but an email has been sent out requesting confirmation. If you wish to invalidate that request and send a new confirmation request, please fill in the form below." + "emailUpdate.pending": "Deine E-Mailadresse wurde noch nicht bestätigt, aber eine E-Mail zur Bestätigung wurde versendet. Wenn Du diese Anfrage abbrechen und eine neue Bestätigung anfordern möchtest, fülle bitte das untenstehende Formular aus." } \ No newline at end of file diff --git a/public/language/de/users.json b/public/language/de/users.json index 1dc934af76..d88f941a9b 100644 --- a/public/language/de/users.json +++ b/public/language/de/users.json @@ -1,12 +1,12 @@ { - "all-users": "All Users", + "all-users": "Alle Benutzer", "latest_users": "Neuste Benutzer", "top_posters": "Meiste Beiträge", "most_reputation": "Höchstes Ansehen", "most_flags": "Meiste Meldungen", "search": "Suchen", "enter_username": "Benutzer durchsuchen", - "search-user-for-chat": "Search for a user to start chat", + "search-user-for-chat": "Suche nach einem Benutzer, um den Chat zu starten", "load_more": "Mehr laden", "users-found-search-took": "%1 Benutzer gefunden! Die Suche dauerte %2 s.", "filter-by": "Filtern nach", diff --git a/public/language/it/admin/admin.json b/public/language/it/admin/admin.json index e205552e9f..b5c0225c03 100644 --- a/public/language/it/admin/admin.json +++ b/public/language/it/admin/admin.json @@ -13,5 +13,5 @@ "max": "Max:", "view": "Visualizza", "edit": "Modifica", - "add": "Add" + "add": "Aggiungi" } \ No newline at end of file diff --git a/public/language/it/admin/extend/widgets.json b/public/language/it/admin/extend/widgets.json index 9b69cc35f4..02bfd45aa5 100644 --- a/public/language/it/admin/extend/widgets.json +++ b/public/language/it/admin/extend/widgets.json @@ -9,9 +9,9 @@ "containers.none": "Nessuno", "container.well": "Bene", "container.jumbotron": "Jumbotron", - "container.card": "Card", - "container.card-header": "Card Header", - "container.card-body": "Card Body", + "container.card": "Scheda", + "container.card-header": "Intestazione della scheda", + "container.card-body": "Corpo della scheda", "container.alert": "Avviso", "alert.confirm-delete": "Sei sicuro di voler eliminare questo widget?", From 6fd444eefde925a9171a5d7a48c7defb048c0a49 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 4 Jul 2023 09:18:57 +0000 Subject: [PATCH 018/300] Latest translations and fallbacks --- public/language/he/admin/settings/user.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/language/he/admin/settings/user.json b/public/language/he/admin/settings/user.json index 3f3942e2b1..419f1ebbe8 100644 --- a/public/language/he/admin/settings/user.json +++ b/public/language/he/admin/settings/user.json @@ -16,7 +16,7 @@ "hide-email": "החבא כתובת מייל ממשתמשים", "show-fullname-as-displayname": "הצג את השם המלא של המשתמש כשם התצוגה שלו אם הוא זמין", "themes": "ערכות נושא", - "disable-user-skins": "אל תאפשר למשתמשים לבחור ערכת נושא", + "disable-user-skins": "אל תאפשר למשתמשים לבחור עיצוב", "account-protection": "הגנת חשבון", "admin-relogin-duration": "משך חיבור של מנהל מערכת (דקות)", "admin-relogin-duration-help": "לאחר פרק זמן מוגדר של גישה למקטע הניהול ידרוש כניסה מחדש, הגדר ל- 0 על-מנת להפוך ללא זמין", From 8fc1744232ff0f20db2bce6868d1d74071d81e33 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 5 Jul 2023 09:19:03 +0000 Subject: [PATCH 019/300] Latest translations and fallbacks --- public/language/de/admin/dashboard.json | 14 +++++++------- public/language/de/admin/manage/users.json | 2 +- public/language/de/admin/settings/group.json | 2 +- public/language/de/admin/settings/user.json | 12 ++++++------ public/language/de/user.json | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/public/language/de/admin/dashboard.json b/public/language/de/admin/dashboard.json index dca9729f4a..5329992be7 100644 --- a/public/language/de/admin/dashboard.json +++ b/public/language/de/admin/dashboard.json @@ -3,15 +3,15 @@ "page-views": "Seitenaufrufe", "unique-visitors": "Individuelle Besucher", "logins": "Anmeldungen", - "new-users": "Neue nutzende Person", + "new-users": "Neue Benutzer", "posts": "Beiträge", "topics": "Themen", "page-views-seven": "Letzte 7 Tage", "page-views-thirty": "Letzte 30 Tage", "page-views-last-day": "Letzte 24 Stunden", - "page-views-custom": "Benutzerdefinierte Tagesspanne", - "page-views-custom-start": "Spannen-Anfang", - "page-views-custom-end": "Spannen-Ende", + "page-views-custom": "Benutzerdefinierter Zeitraum", + "page-views-custom-start": "Anfang Zeitraum", + "page-views-custom-end": "Ende Zeitraum", "page-views-custom-help": "Gebe einen Datumsbereich für Seitenaufrufe ein, die du anzeigen möchtest. Wenn keine Datumsauswahl verfügbar ist, ist das akzeptierte Format YYYY-MM-DD", "page-views-custom-error": "Bitte gib eine gültige Zeitspanne im Format YYYY-MM-DD an", @@ -82,11 +82,11 @@ "back-to-dashboard": "Zurück zur Übersicht", "details.no-users": "Keine Benutzer sind im gewählten Zeitraum beigetreten", - "details.no-topics": "Keine Themen wurden im gewählten Zeitraum beigetreten", + "details.no-topics": "Im ausgewählten Zeitraum wurden keine Themen erstellt", "details.no-searches": "Es wurden im ausgewählten Zeitraum keine Suchen durchgeführt", - "details.no-logins": "Keine Logins wurden im gewählten Zeitraum festgestellt", + "details.no-logins": "Im ausgewählten Zeitraum wurden keine Logins getätigt", "details.logins-static": "NodeBB speichert Sitzungsdaten nur für %1 Tage, deshalb zeigt die untere Tabelle nur die neuesten, aktiven Sitzungen", - "details.logins-login-time": "Anmelde Zeit", + "details.logins-login-time": "Anmeldezeit", "start": "Start", "end": "Ende", "filter": "Filter" diff --git a/public/language/de/admin/manage/users.json b/public/language/de/admin/manage/users.json index 98847bf3fe..e1c944af5d 100644 --- a/public/language/de/admin/manage/users.json +++ b/public/language/de/admin/manage/users.json @@ -59,7 +59,7 @@ "users.reputation": "Ansehen", "users.flags": "Meldungen", "users.joined": "Beigetreten am", - "users.last-online": "Letztes mal online", + "users.last-online": "Zuletzt online", "users.banned": "Gebannt", "create.username": "Benutzername", diff --git a/public/language/de/admin/settings/group.json b/public/language/de/admin/settings/group.json index df50632f6b..7100499aba 100644 --- a/public/language/de/admin/settings/group.json +++ b/public/language/de/admin/settings/group.json @@ -2,7 +2,7 @@ "general": "Allgemein", "private-groups": "Private Gruppen", "private-groups.help": "Wenn aktiviert, erfordert das Beitreten einer Gruppe die Bestätigung des jeweiligen Besitzers(Standard: aktiviert)", - "private-groups.warning": "Vorsicht! Wenn diese Option deaktiviert ist, und es private Gruppen gibt, werden diese automatisch öffentlich.", + "private-groups.warning": "Vorsicht! Wenn diese Option deaktiviert ist, werden private Gruppen automatisch öffentlich.", "allow-multiple-badges": "Mehrere Abzeichen erlauben", "allow-multiple-badges-help": "Diese Eintellung kann verwendet werden um Benutzern zu erlauben mehrere Gruppen abzeichen auszuwählen, benötigt Theme unterstützung.", "max-name-length": "Maximale Länge von Gruppennamen", diff --git a/public/language/de/admin/settings/user.json b/public/language/de/admin/settings/user.json index d5af67d6d1..fe6e9590c1 100644 --- a/public/language/de/admin/settings/user.json +++ b/public/language/de/admin/settings/user.json @@ -49,14 +49,14 @@ "registration-queue-show-average-time": "Zeigen Sie Benutzern die durchschnittliche Zeit, die es dauert, einen neuen Benutzer zu genehmigen", "registration.max-invites": "Maximale Einladungen pro Benutzer", "max-invites": "Maximale Einladungen pro Benutzer", - "max-invites-help": "0 für keine Beschränkung. Admins haben keine beschränkung.
Nur praktikabel für \"Nur Einladungen\".", + "max-invites-help": "0 für keine Beschränkung. Admins haben keine Beschränkung.
Nur angewendet für \"Nur Einladungen\".", "invite-expiration": "Einladungsfrist", "invite-expiration-help": "# der Tage nachdem Einladungen auslaufen.", - "min-username-length": "Minimale länge des Benutzernamens", - "max-username-length": "Maximale länge des Benutzernamens", - "min-password-length": "Minimale länge des Passwortes", - "min-password-strength": "Minimale Passwort stärke", - "max-about-me-length": "Maximale länge von Über Mich", + "min-username-length": "Minimale Länge des Benutzernamens", + "max-username-length": "Maximale Länge des Benutzernamens", + "min-password-length": "Minimale Länge des Passwortes", + "min-password-strength": "Minimale Passwortstärke", + "max-about-me-length": "Maximale Länge von \"Über Mich\"", "terms-of-use": "Forum Nutzungsbedingungen (Leer lassen um es zu deaktivieren)", "user-search": "Benutzersuche", "user-search-results-per-page": "Anzahl Benutzer, die in der Suche angezeigt werden", diff --git a/public/language/de/user.json b/public/language/de/user.json index 8b3dc41545..a570dded91 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -19,8 +19,8 @@ "delete_account_as_admin": "Konto löschen", "delete_content": "Konto-Inhalt löschen", "delete_all": "Konto und Inhalt löschen", - "delete_account_confirm": "Bist du sicher, dass du diesen Account löschen und deine Beiträge anonymisieren mnöchtest?
Diese Aktion kann nicht rückgängig gemacht werden und die Daten können nicht wiederhergestellt werden.

Gib dein Passwort ein um das Löschen des Accounts zu bestätigen.", - "delete_this_account_confirm": "Bist du sicher, dass du diesen Account löschen und seine Inhalte beibehalten möchstes?
Diese Aktion kann nicht rückgängig gemacht werden. Beiträge werden anonymisiert und können nicht wieder mit dem gelöschten Account verknüpft werden.

", + "delete_account_confirm": "Bist du sicher, dass du Deinen Account löschen und Deine Beiträge anonymisieren möchtest?
Diese Aktion kann nicht rückgängig gemacht werden und die Daten können nicht wiederhergestellt werden.

Gib dein Passwort ein, um das Löschen des Accounts zu bestätigen.", + "delete_this_account_confirm": "Bist du sicher, dass du diesen Account löschen und seine Inhalte beibehalten möchstest?
Diese Aktion kann nicht rückgängig gemacht werden. Beiträge werden anonymisiert und können nicht wieder mit dem gelöschten Account verknüpft werden.

", "delete_account_content_confirm": "Bist du sicher, dass du die Inhalte dieses Accounts (Beiträge/Themen/Uploads) löschen möchtest?
Diese Aktion ist irreversibel und die Daten können nicht wiederhergestellt werden.

", "delete_all_confirm": "Bist du sicher, dass du diesen Account und seinen gesamten Inhalt (Beiträge/Themen/Uploads) löschen möchtest?
Diese Aktion ist irreversibel und die Daten können nicht wiederhergestellt werden.

", "account-deleted": "Konto gelöscht", From 1932a31df5124b9e1a90f37f3e08d3306d9e1902 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 09:08:39 -0400 Subject: [PATCH 020/300] fix(deps): update dependency nodebb-plugin-emoji to v5.1.3 (#11777) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index bf59b8bcb7..91f11341d2 100644 --- a/install/package.json +++ b/install/package.json @@ -94,7 +94,7 @@ "nodebb-plugin-2factor": "7.1.3", "nodebb-plugin-composer-default": "10.2.4", "nodebb-plugin-dbsearch": "6.1.0", - "nodebb-plugin-emoji": "5.1.2", + "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.5", "nodebb-plugin-mentions": "4.2.0", From 5eedd8eba23a32544cfbea087a0292d822cd71b9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 09:08:58 -0400 Subject: [PATCH 021/300] fix(deps): update fontsource monorepo to v5.0.4 (#11776) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 91f11341d2..fc9766d750 100644 --- a/install/package.json +++ b/install/package.json @@ -29,8 +29,8 @@ }, "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", - "@fontsource/inter": "5.0.3", - "@fontsource/poppins": "5.0.3", + "@fontsource/inter": "5.0.4", + "@fontsource/poppins": "5.0.4", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", "ace-builds": "1.23.1", From 9044e10e64fdef7f7314eb6b3b1a094a6ffe5857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 7 Jul 2023 00:38:30 -0400 Subject: [PATCH 022/300] change description length to 160 --- src/controllers/topics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 58ca059502..442799e56a 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -209,8 +209,8 @@ async function addTags(topicData, req, res, currentPage) { description = utils.stripHTMLTags(utils.decodeHTMLEntities(postAtIndex.content)); } - if (description.length > 255) { - description = `${description.slice(0, 255)}...`; + if (description.length > 160) { + description = `${description.slice(0, 160)}...`; } description = description.replace(/\n/g, ' '); From 5a42d37e0fea4765a49f268eff21cf81b63885bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 7 Jul 2023 23:58:12 -0400 Subject: [PATCH 023/300] fix reconnect logic --- public/src/sockets.js | 4 +- src/socket.io/admin/rooms.js | 96 ++++++++++++++---------------------- 2 files changed, 38 insertions(+), 62 deletions(-) diff --git a/public/src/sockets.js b/public/src/sockets.js index acd3ba3dbe..6ffe0878c3 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -191,7 +191,6 @@ app = window.app || {}; } function onReconnecting() { - reconnecting = true; const reconnectEl = $('#reconnect'); const reconnectAlert = $('#reconnect-alert'); @@ -207,8 +206,9 @@ app = window.app || {}; } function onDisconnect() { + reconnecting = true; setTimeout(function () { - if (socket.disconnected) { + if (!socket.connected) { onReconnecting(); } }, 2000); diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index 4aafe9fbf6..f34f9b2c13 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -1,61 +1,27 @@ 'use strict'; -const os = require('os'); -const nconf = require('nconf'); - const topics = require('../../topics'); -const pubsub = require('../../pubsub'); -const utils = require('../../utils'); +const io = require('..'); -const stats = {}; const totals = {}; const SocketRooms = module.exports; -SocketRooms.stats = stats; SocketRooms.totals = totals; -pubsub.on('sync:stats:start', () => { - const stats = SocketRooms.getLocalStats(); - pubsub.publish('sync:stats:end', { - stats: stats, - id: `${os.hostname()}:${nconf.get('port')}`, - }); -}); - -pubsub.on('sync:stats:end', (data) => { - stats[data.id] = data.stats; -}); - -pubsub.on('sync:stats:guests', (eventId) => { - const Sockets = require('../index'); - const guestCount = Sockets.getCountInRoom('online_guests'); - pubsub.publish(eventId, guestCount); -}); - -SocketRooms.getTotalGuestCount = function (callback) { - let count = 0; - const eventId = `sync:stats:guests:end:${utils.generateUUID()}`; - pubsub.on(eventId, (guestCount) => { - count += guestCount; - }); - - pubsub.publish('sync:stats:guests', eventId); - - setTimeout(() => { - pubsub.removeAllListeners(eventId); - callback(null, count); - }, 100); +SocketRooms.getTotalGuestCount = async function () { + const s = await io.in('online_guests').fetchSockets(); + return s.length; }; - SocketRooms.getAll = async function () { - pubsub.publish('sync:stats:start'); + const sockets = await io.server.fetchSockets(); totals.onlineGuestCount = 0; totals.onlineRegisteredCount = 0; - totals.socketCount = 0; + totals.socketCount = sockets.length; totals.topics = {}; + totals.topTenTopics = []; totals.users = { categories: 0, recent: 0, @@ -63,30 +29,39 @@ SocketRooms.getAll = async function () { topics: 0, category: 0, }; - - for (const instance of Object.values(stats)) { - totals.onlineGuestCount += instance.onlineGuestCount; - totals.onlineRegisteredCount += instance.onlineRegisteredCount; - totals.socketCount += instance.socketCount; - totals.users.categories += instance.users.categories; - totals.users.recent += instance.users.recent; - totals.users.unread += instance.users.unread; - totals.users.topics += instance.users.topics; - totals.users.category += instance.users.category; - - instance.topics.forEach((topic) => { - totals.topics[topic.tid] = totals.topics[topic.tid] || { count: 0, tid: topic.tid }; - totals.topics[topic.tid].count += topic.count; - }); + const userRooms = {}; + const topicData = {}; + for (const s of sockets) { + for (const key of s.rooms) { + if (key === 'online_guests') { + totals.onlineGuestCount += 1; + } else if (key === 'categories') { + totals.users.categories += 1; + } else if (key === 'recent_topics') { + totals.users.recent += 1; + } else if (key === 'unread_topics') { + totals.users.unread += 1; + } else if (key.startsWith('uid_')) { + userRooms[key] = 1; + } else if (key.startsWith('category_')) { + totals.users.category += 1; + } else { + const tid = key.match(/^topic_(\d+)/); + if (tid) { + totals.users.topics += 1; + topicData[tid[1]] = topicData[tid[1]] || { count: 0 }; + topicData[tid[1]].count += 1; + } + } + } } + totals.onlineRegisteredCount = Object.keys(userRooms).length; let topTenTopics = []; - Object.keys(totals.topics).forEach((tid) => { - topTenTopics.push({ tid: tid, count: totals.topics[tid].count || 0 }); + Object.keys(topicData).forEach((tid) => { + topTenTopics.push({ tid: tid, count: topicData[tid].count }); }); - topTenTopics = topTenTopics.sort((a, b) => b.count - a.count).slice(0, 10); - const topTenTids = topTenTopics.map(topic => topic.tid); const titles = await topics.getTopicsFields(topTenTids, ['title']); @@ -94,6 +69,7 @@ SocketRooms.getAll = async function () { topic.title = titles[index].title; return topic; }); + return totals; }; From e31f5c42ee5b4f034aecd00c0be43ce521528cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 8 Jul 2023 00:37:04 -0400 Subject: [PATCH 024/300] test: fix --- test/socket.io.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/socket.io.js b/test/socket.io.js index b7fcaff935..54568b47e0 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -371,7 +371,7 @@ describe('socket.io', () => { assert(data.hasOwnProperty('onlineGuestCount')); assert(data.hasOwnProperty('onlineRegisteredCount')); assert(data.hasOwnProperty('socketCount')); - assert(data.hasOwnProperty('topics')); + assert(data.hasOwnProperty('topTenTopics')); assert(data.hasOwnProperty('users')); done(); }); From 0a7f52475ec54e144fc1a905d3953f1edf8b2d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 8 Jul 2023 03:02:51 -0400 Subject: [PATCH 025/300] fix member IS --- public/src/client/groups/memberlist.js | 2 +- src/views/admin/partials/groups/memberlist.tpl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js index 2b8bce8107..986257bf9a 100644 --- a/public/src/client/groups/memberlist.js +++ b/public/src/client/groups/memberlist.js @@ -108,7 +108,7 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b } function handleMemberInfiniteScroll() { - $('[component="groups/members"] tbody').on('scroll', function () { + $('[component="groups/members"]').on('scroll', function () { const $this = $(this); const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9; diff --git a/src/views/admin/partials/groups/memberlist.tpl b/src/views/admin/partials/groups/memberlist.tpl index e2807ac2d2..6881b3667c 100644 --- a/src/views/admin/partials/groups/memberlist.tpl +++ b/src/views/admin/partials/groups/memberlist.tpl @@ -10,8 +10,8 @@ -
- +
+
{{{ each group.members }}} From 0ff1f82b5c1321c62f732af1f8a0cab54bec97fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 8 Jul 2023 14:55:29 -0400 Subject: [PATCH 026/300] make meta desc 160 chars --- src/controllers/topics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 442799e56a..7e6ff393a2 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -210,7 +210,7 @@ async function addTags(topicData, req, res, currentPage) { } if (description.length > 160) { - description = `${description.slice(0, 160)}...`; + description = `${description.slice(0, 157)}...`; } description = description.replace(/\n/g, ' '); From 0fe7e831f41f0cfa97f1f0cf9c879b2dc3999efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 8 Jul 2023 20:24:05 -0400 Subject: [PATCH 027/300] dont show pid --- src/views/admin/development/info.tpl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/views/admin/development/info.tpl b/src/views/admin/development/info.tpl index aec2347985..7440729fab 100644 --- a/src/views/admin/development/info.tpl +++ b/src/views/admin/development/info.tpl @@ -12,7 +12,6 @@ - @@ -31,7 +30,6 @@ {{{if info.nodebb.isPrimary}}}{{{else}}}{{{end}}} / {{{if info.nodebb.runJobs}}}{{{else}}}{{{end}}} - {{{ end }}} + {{{ if publicRooms.length }}} + + + + {{{ end }}} {{{ if topTopics.length }}} - - + + diff --git a/src/views/admin/partials/dashboard/stats.tpl b/src/views/admin/partials/dashboard/stats.tpl index b28e0ee9f6..abd4f9cd31 100644 --- a/src/views/admin/partials/dashboard/stats.tpl +++ b/src/views/admin/partials/dashboard/stats.tpl @@ -27,19 +27,19 @@ {{{ end }}} - - + + - - + + - - + + - + {{{ end }}} From 3dcaa745db9481203aa71a628570ed8a59267477 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 19 Jul 2023 09:19:01 +0000 Subject: [PATCH 121/300] Latest translations and fallbacks --- public/language/bg/email.json | 4 ++-- public/language/bg/topic.json | 2 +- public/language/it/email.json | 4 ++-- public/language/it/groups.json | 2 +- public/language/it/modules.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/public/language/bg/email.json b/public/language/bg/email.json index 8bf5ee7c1d..5a62e0594f 100644 --- a/public/language/bg/email.json +++ b/public/language/bg/email.json @@ -22,8 +22,8 @@ "reset.notify.subject": "Паролата беше променена успешно", "reset.notify.text1": "Известяваме Ви, че на %1, Вашата парола беше променена успешно.", "reset.notify.text2": "Ако не сте поискали това, моля, свържете се незабавно с администратор.", - "digest.unread-rooms": "Unread rooms", - "digest.room-name-unreadcount": "%1 (%2 unread)", + "digest.unread-rooms": "Непрочетени стаи", + "digest.room-name-unreadcount": "%1 (%2 непрочетени)", "digest.latest_topics": "Последни теми от %1", "digest.top-topics": "Най-интересните теми от %1", "digest.popular-topics": "Популярни теми от %1", diff --git a/public/language/bg/topic.json b/public/language/bg/topic.json index b5fc93e4cc..156670b1aa 100644 --- a/public/language/bg/topic.json +++ b/public/language/bg/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "писа ", "wrote-on": "писа на ", "replied-to-user-ago": "отговори на %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "отговори на %3 на ", "user-locked-topic-ago": "%1 заключи тази тема %2", "user-locked-topic-on": "%1 заключи тази тема на %2", "user-unlocked-topic-ago": "%1 отключи тази тема %2", diff --git a/public/language/it/email.json b/public/language/it/email.json index 6064f59210..8d94bae9db 100644 --- a/public/language/it/email.json +++ b/public/language/it/email.json @@ -22,8 +22,8 @@ "reset.notify.subject": "Password modificata con successo.", "reset.notify.text1": "Ti informiamo che il %1, la password è stata cambiata con successo.", "reset.notify.text2": "Se non hai autorizzato questo, per favore informa immediatamente l'amministratore.", - "digest.unread-rooms": "Unread rooms", - "digest.room-name-unreadcount": "%1 (%2 unread)", + "digest.unread-rooms": "Stanze non lette", + "digest.room-name-unreadcount": "%1 (%2 non letto)", "digest.latest_topics": "Ultime discussioni da %1", "digest.top-topics": "Argomenti principali da %1", "digest.popular-topics": "Argomenti popolari da %1", diff --git a/public/language/it/groups.json b/public/language/it/groups.json index 3df61dcaf0..e8f9c478a0 100644 --- a/public/language/it/groups.json +++ b/public/language/it/groups.json @@ -28,7 +28,7 @@ "details.private": "Privato", "details.disableJoinRequests": "Disabilita le richieste d'iscrizione", "details.disableLeave": "Impedisce agli utenti di lasciare il gruppo", - "details.grant": "Concedi/Revoca la Proprietà", + "details.grant": "Concedi/Revoca Proprietà", "details.kick": "Espelli", "details.kick_confirm": "Sei sicuro di voler rimuovere questo membro dal gruppo?", "details.add-member": "Aggiungi Membro", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 80d49dd462..bc0fa558fe 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -54,7 +54,7 @@ "chat.kick": "Butta fuori", "chat.show-ip": "Mostra indirizzo IP", "chat.owner": "Propietario stanza", - "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.grant-rescind-ownership": "Concedi/Revoca Proprietà", "chat.system.user-join": "%1 si è iscritto alla stanza", "chat.system.user-leave": "%1 ha lasciato la stanza", "chat.system.room-rename": "%2 ha rinominato questa stanza: %1", From 9e574e076568ac83bbda8fd10b283f7aedea0531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 19 Jul 2023 08:05:22 -0400 Subject: [PATCH 122/300] test: fix test --- test/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils.js b/test/utils.js index b0a6afcfb9..b47ff80224 100644 --- a/test/utils.js +++ b/test/utils.js @@ -238,7 +238,7 @@ describe('Utility Methods', () => { }); it('should make number human readable', (done) => { - assert.equal(utils.makeNumberHumanReadable(null), null); + assert.equal(utils.makeNumberHumanReadable(null), 'null'); done(); }); From 3fcbc138ac19a675b1af29ee0e7c00303055f2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 19 Jul 2023 08:05:34 -0400 Subject: [PATCH 123/300] add deprecation message --- public/src/utils.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/public/src/utils.js b/public/src/utils.js index 863b8f0c40..0c7f106fa5 100644 --- a/public/src/utils.js +++ b/public/src/utils.js @@ -16,18 +16,21 @@ utils.getLanguage = function () { utils.makeNumbersHumanReadable = function (elements) { + console.warn('[deprecated] utils.makeNumbersHumanReadable is deprecated! Use {humanReadableNumber(value)} helper directly in the template'); elements.each(function () { const $this = $(this); const toFixed = $this.attr('data-toFixed') || 1; - $this.html(utils.makeNumberHumanReadable($(this).attr('title'), toFixed)) + $this.html(utils.makeNumberHumanReadable($this.attr('title'), toFixed)) .removeClass('hidden'); }); }; utils.addCommasToNumbers = function (elements) { + console.warn('[deprecated] utils.addCommasToNumbers is deprecated! Use {formattedNumber(value)} helper directly in the template'); elements.each(function (index, element) { - $(element) - .html(utils.addCommas($(element).html())) + const $element = $(element); + $element + .html(utils.addCommas($element.html())) .removeClass('hidden'); }); }; From 465b3e09e2c4389616300c1f89e48ce681f9fc73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 08:10:34 -0400 Subject: [PATCH 124/300] fix(deps): update dependency nodebb-plugin-ntfy to v1.1.0 (#11815) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 8b9260f4df..ec6f95fe50 100644 --- a/install/package.json +++ b/install/package.json @@ -98,7 +98,7 @@ "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", "nodebb-plugin-mentions": "4.3.2", - "nodebb-plugin-ntfy": "1.0.16", + "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.1.8", From f1bd7cd238ee11f5884364dc2513f3fea2620fa3 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 19 Jul 2023 16:08:16 +0000 Subject: [PATCH 125/300] chore: incrementing version number - v3.2.3 --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 8040ee1f13..6c3983fc66 100644 --- a/install/package.json +++ b/install/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "3.2.2", + "version": "3.2.3", "homepage": "https://www.nodebb.org", "repository": { "type": "git", From afb38c7158525ad649f9e0a8e3066463715eab95 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 19 Jul 2023 16:08:17 +0000 Subject: [PATCH 126/300] chore: update changelog for v3.2.3 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe73393c69..5fe54cca1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +#### v3.2.3 (2023-07-19) + +##### Chores + +* downgrade harmony to correct version (7c94506b) +* incrementing version number - v3.2.2 (758ecfcd) +* update changelog for v3.2.2 (91a432ad) +* incrementing version number - v3.2.1 (20145074) +* incrementing version number - v3.2.0 (9ecac38e) +* incrementing version number - v3.1.7 (0b4e81ab) +* incrementing version number - v3.1.6 (b3a3b130) +* incrementing version number - v3.1.5 (ec19343a) +* incrementing version number - v3.1.4 (2452783c) +* incrementing version number - v3.1.3 (3b4e9d3f) +* incrementing version number - v3.1.2 (40fa3489) +* incrementing version number - v3.1.1 (40250733) +* incrementing version number - v3.1.0 (0cb386bd) +* incrementing version number - v3.0.1 (26f6ea49) +* incrementing version number - v3.0.0 (224e08cd) + +##### Bug Fixes + +* typo in replied to link (3024dac1) +* logs page whitespace (2a3d6d5c) +* version alert in acp (05c9cca7) +* #11804, fix direction of dropdown on rtl (a4dba8d3) +* #11802, fix anchor ids in acp settings (562e4d6e) +* #11803, fix rtl in acp (a0478c70) + #### v3.2.2 (2023-07-12) ##### Chores From f7ae8963cef16be5dd93052c4a5e15377546e7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 19 Jul 2023 19:50:41 -0400 Subject: [PATCH 127/300] https://github.com/NodeBB/NodeBB/issues/11818 --- public/src/admin/dashboard.js | 9 +++------ public/src/admin/manage/tags.js | 1 - public/src/app.js | 2 -- public/src/client/account/posts.js | 1 - public/src/client/account/topics.js | 1 - public/src/client/category.js | 1 - public/src/client/tags.js | 1 - public/src/client/topic/postTools.js | 7 ++++--- public/src/client/topic/posts.js | 8 +++----- public/src/modules/topicList.js | 1 - 10 files changed, 10 insertions(+), 22 deletions(-) diff --git a/public/src/admin/dashboard.js b/public/src/admin/dashboard.js index afead1ff13..ef80204127 100644 --- a/public/src/admin/dashboard.js +++ b/public/src/admin/dashboard.js @@ -436,12 +436,9 @@ define('admin/dashboard', [ } else { graphs.traffic.data.xLabels = utils.getHoursArray(); - $('#pageViewsThirty').html(data.summary.thirty); - $('#pageViewsSeven').html(data.summary.seven); - $('#pageViewsPastDay').html(data.pastDay); - utils.addCommasToNumbers($('#pageViewsThirty')); - utils.addCommasToNumbers($('#pageViewsSeven')); - utils.addCommasToNumbers($('#pageViewsPastDay')); + $('#pageViewsThirty').html(helpers.formattedNumber(data.summary.thirty)); + $('#pageViewsSeven').html(helpers.formattedNumber(data.summary.seven)); + $('#pageViewsPastDay').html(helpers.formattedNumber(data.pastDay)); } graphs.traffic.data.datasets[0].data = data.pageviews; diff --git a/public/src/admin/manage/tags.js b/public/src/admin/manage/tags.js index ea6ab15c59..aba143ddf7 100644 --- a/public/src/admin/manage/tags.js +++ b/public/src/admin/manage/tags.js @@ -59,7 +59,6 @@ define('admin/manage/tags', [ tags: tags, }, function (html) { $('.tag-list').html(html); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); selectable.enable('.tag-management', '.tag-row'); }); } diff --git a/public/src/app.js b/public/src/app.js index c457ae89f6..599792838f 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -253,8 +253,6 @@ if (document.readyState === 'loading') { highlightNavigationLink(); overrides.overrideTimeagoCutoff(); $('.timeago').timeago(); - utils.makeNumbersHumanReadable($('.human-readable-number')); - utils.addCommasToNumbers($('.formatted-number')); app.createUserTooltips($('#content')); app.createStatusTooltips(); }; diff --git a/public/src/client/account/posts.js b/public/src/client/account/posts.js index fbd7f555c7..deea51d851 100644 --- a/public/src/client/account/posts.js +++ b/public/src/client/account/posts.js @@ -45,7 +45,6 @@ define('forum/account/posts', ['forum/account/header', 'forum/infinitescroll', ' $('[component="posts"]').append(html); html.find('img:not(.not-responsive)').addClass('img-fluid'); html.find('.timeago').timeago(); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); hooks.fire('action:posts.loaded', { posts: posts }); callback(); }); diff --git a/public/src/client/account/topics.js b/public/src/client/account/topics.js index 565bb9b170..7a95d01ceb 100644 --- a/public/src/client/account/topics.js +++ b/public/src/client/account/topics.js @@ -46,7 +46,6 @@ define('forum/account/topics', [ app.parseAndTranslate(template, 'topics', { topics: topics }, function (html) { $('[component="category"]').append(html); html.find('.timeago').timeago(); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); hooks.fire('action:topics.loaded', { topics: topics }); callback(); }); diff --git a/public/src/client/category.js b/public/src/client/category.js index 86f76381ab..a69ef64616 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -104,7 +104,6 @@ define('forum/category', [ app.parseAndTranslate('category', 'children', { children: data }, function (html) { html.find('.timeago').timeago(); $('[component="category/subcategory/container"]').append(html); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); ajaxify.data.nextSubCategoryStart += ajaxify.data.subCategoriesPerPage; ajaxify.data.subCategoriesLeft -= data.length; btn.toggleClass('hidden', ajaxify.data.subCategoriesLeft <= 0) diff --git a/public/src/client/tags.js b/public/src/client/tags.js index ca8036ee76..c754e7bbb9 100644 --- a/public/src/client/tags.js +++ b/public/src/client/tags.js @@ -54,7 +54,6 @@ define('forum/tags', ['forum/infinitescroll', 'alerts'], function (infinitescrol callback = callback || function () {}; app.parseAndTranslate('tags', 'tags', { tags: tags }, function (html) { $('.tag-list')[replace ? 'html' : 'append'](html); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); callback(); }); } diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 72de7164b3..5cf95d9374 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -11,7 +11,8 @@ define('forum/topic/postTools', [ 'bootbox', 'alerts', 'hooks', -], function (share, navigator, components, translator, votes, api, bootbox, alerts, hooks) { + 'helpers', +], function (share, navigator, components, translator, votes, api, bootbox, alerts, hooks, helpers) { const PostTools = {}; let staleReplyAnyway = false; @@ -85,8 +86,8 @@ define('forum/topic/postTools', [ PostTools.updatePostCount = function (postCount) { const postCountEl = components.get('topic/post-count'); - postCountEl.html(postCount).attr('title', postCount); - utils.makeNumbersHumanReadable(postCountEl); + postCountEl.attr('title', postCount) + .html(helpers.humanReadableNumber(postCount)); navigator.setCount(postCount); }; diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index e0c09cb96e..d9ce0c613b 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -10,7 +10,8 @@ define('forum/topic/posts', [ 'components', 'translator', 'hooks', -], function (pagination, infinitescroll, postTools, images, navigator, components, translator, hooks) { + 'helpers', +], function (pagination, infinitescroll, postTools, images, navigator, components, translator, hooks, helpers) { const Posts = { }; Posts.signaturesShown = {}; @@ -76,8 +77,7 @@ define('forum/topic/posts', [ function updatePostCounts(posts) { for (let i = 0; i < posts.length; i += 1) { const cmp = components.get('user/postcount', posts[i].uid); - cmp.html(parseInt(cmp.attr('data-postcount'), 10) + 1); - utils.addCommasToNumbers(cmp); + cmp.html(helpers.formattedNumber(parseInt(cmp.attr('data-postcount'), 10) + 1)); } } @@ -410,8 +410,6 @@ define('forum/topic/posts', [ Posts.onNewPostsAddedToDom = async function (posts) { await Posts.onTopicPageLoad(posts); - utils.addCommasToNumbers(posts.find('.formatted-number')); - utils.makeNumbersHumanReadable(posts.find('.human-readable-number')); posts.find('.timeago').timeago(); }; diff --git a/public/src/modules/topicList.js b/public/src/modules/topicList.js index 5d1ea52a62..f771eca47c 100644 --- a/public/src/modules/topicList.js +++ b/public/src/modules/topicList.js @@ -242,7 +242,6 @@ define('topicList', [ } html.find('.timeago').timeago(); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); hooks.fire('action:topics.loaded', { topics: topics, template: templateName }); callback(); }); From 6fc80f9f185ca417e558a280a630be9ed46f1ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 19 Jul 2023 20:00:19 -0400 Subject: [PATCH 128/300] chore: up themes --- install/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/install/package.json b/install/package.json index ec6f95fe50..2001abf0aa 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.8", - "nodebb-theme-lavender": "7.1.2", - "nodebb-theme-peace": "2.1.2", - "nodebb-theme-persona": "13.2.5", + "nodebb-theme-harmony": "1.1.9", + "nodebb-theme-lavender": "7.1.3", + "nodebb-theme-peace": "2.1.3", + "nodebb-theme-persona": "13.2.6", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From e7626d90e9b4dc24c1283820e07ce07adb4c7eac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 02:38:40 -0400 Subject: [PATCH 129/300] fix(deps): update dependency sass to v1.64.0 (#11822) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 2001abf0aa..c5b4cbd5ae 100644 --- a/install/package.json +++ b/install/package.json @@ -124,7 +124,7 @@ "rss": "1.2.2", "rtlcss": "4.1.0", "sanitize-html": "2.11.0", - "sass": "1.63.6", + "sass": "1.64.0", "semver": "7.5.4", "serve-favicon": "2.5.0", "sharp": "0.32.3", From 560bb29c6d375563b76f7d19eacc44da8ff50152 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 02:38:55 -0400 Subject: [PATCH 130/300] chore(deps): update dependency sass-embedded to v1.64.0 (#11821) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index c5b4cbd5ae..4fede3ddad 100644 --- a/install/package.json +++ b/install/package.json @@ -171,7 +171,7 @@ "smtp-server": "3.12.0" }, "optionalDependencies": { - "sass-embedded": "1.63.6" + "sass-embedded": "1.64.0" }, "resolutions": { "*/jquery": "3.7.0" From ac65ab42440ba0cf2dbdae46ddeac4f26d6d1201 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 02:39:02 -0400 Subject: [PATCH 131/300] chore(deps): update commitlint monorepo to v17.6.7 (#11817) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 4fede3ddad..a74d3f3810 100644 --- a/install/package.json +++ b/install/package.json @@ -153,8 +153,8 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", - "@commitlint/cli": "17.6.6", - "@commitlint/config-angular": "17.6.6", + "@commitlint/cli": "17.6.7", + "@commitlint/config-angular": "17.6.7", "coveralls": "3.1.1", "eslint": "8.45.0", "eslint-config-nodebb": "0.2.1", From fcb99af1c60f2c4df02864f2317d9e50f16707e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 02:39:11 -0400 Subject: [PATCH 132/300] fix(deps): update dependency nodemailer to v6.9.4 (#11819) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a74d3f3810..1bda4e43ee 100644 --- a/install/package.json +++ b/install/package.json @@ -106,7 +106,7 @@ "nodebb-theme-peace": "2.1.3", "nodebb-theme-persona": "13.2.6", "nodebb-widget-essentials": "7.0.13", - "nodemailer": "6.9.3", + "nodemailer": "6.9.4", "nprogress": "0.2.0", "passport": "0.6.0", "passport-http-bearer": "1.0.1", From 6e95fc69863421e3380dd819d6723d364dbea161 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Thu, 20 Jul 2023 09:18:57 +0000 Subject: [PATCH 133/300] Latest translations and fallbacks --- public/language/he/email.json | 4 ++-- public/language/he/modules.json | 2 +- public/language/it/topic.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/language/he/email.json b/public/language/he/email.json index d3d46db336..9ac51b3bbd 100644 --- a/public/language/he/email.json +++ b/public/language/he/email.json @@ -22,8 +22,8 @@ "reset.notify.subject": "הסיסמה שונתה בהצלחה.", "reset.notify.text1": "אנו מודיעים לך שב%1, סיסמתך שונתה בהצלחה.", "reset.notify.text2": "אם לא אישרת בקשה זו, אנא הודע למנהל מיד.", - "digest.unread-rooms": "Unread rooms", - "digest.room-name-unreadcount": "%1 (%2 unread)", + "digest.unread-rooms": "חדרים שלא נקראו", + "digest.room-name-unreadcount": "%1 (%2 לא נקראו)", "digest.latest_topics": "נושאים אחרונים מ%1", "digest.top-topics": "נושאים עם הכי הרבה הצבעות מ-%1", "digest.popular-topics": "הנושאים הכי פופולריים מ-%1", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 69904ed684..884f89bb32 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -54,7 +54,7 @@ "chat.kick": "הוצא", "chat.show-ip": "הצג IP", "chat.owner": "מנהלי החדר", - "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.grant-rescind-ownership": "הענק/בטל בעלות", "chat.system.user-join": "%1 הצטרף לחדר", "chat.system.user-leave": "%1 יצא מהחדר", "chat.system.room-rename": "%2 שינה את שם החדר: %1", diff --git a/public/language/it/topic.json b/public/language/it/topic.json index 9f0e587a9c..9786279944 100644 --- a/public/language/it/topic.json +++ b/public/language/it/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "scritto ", "wrote-on": "scritto su ", "replied-to-user-ago": "risposto a %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "risposto a %3 su ", "user-locked-topic-ago": "%1 ha bloccato questa discussione %2", "user-locked-topic-on": "%1 ha bloccato questa discussione su %2", "user-unlocked-topic-ago": "%1 ha sbloccato questa discussione %2", From c1361ee580f5c5acb1c58ce195f3e9b601c18e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 20 Jul 2023 15:31:12 -0400 Subject: [PATCH 134/300] add: new filter to filter skins --- src/meta/css.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/meta/css.js b/src/meta/css.js index 6298cfc44a..8b19edbc92 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -256,13 +256,12 @@ CSS.getSkinSwitcherOptions = async function (uid) { }); return skins; } - - return { + return await plugins.hooks.fire('filter:meta.css.getSkinSwitcherOptions', { default: defaultSkins, custom: customSkins.map(s => ({ ...s, selected: s.value === userSettings.bootswatchSkin })), light: parseSkins(lightSkins), dark: parseSkins(darkSkins), - }; + }); }; CSS.getCustomSkins = async function (opts = {}) { From dae4f9f7b604cb23d3f0181f1d37282fa00f52d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 20 Jul 2023 16:02:51 -0400 Subject: [PATCH 135/300] fix: closes #11825, user icons in global privileges --- public/scss/admin/manage/privileges.scss | 2 +- src/views/admin/partials/privileges/global.tpl | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/public/scss/admin/manage/privileges.scss b/public/scss/admin/manage/privileges.scss index e411bd94e6..f2d11eed4e 100644 --- a/public/scss/admin/manage/privileges.scss +++ b/public/scss/admin/manage/privileges.scss @@ -4,7 +4,7 @@ 100% {background-color: white;} } - [data-group-name].selected, [data-uid].selected { + tr[data-group-name].selected, tr[data-uid].selected { animation-name: fadeOut; animation-duration: 5s; animation-fill-mode: both; diff --git a/src/views/admin/partials/privileges/global.tpl b/src/views/admin/partials/privileges/global.tpl index 614b3635a8..37953ba2dc 100644 --- a/src/views/admin/partials/privileges/global.tpl +++ b/src/views/admin/partials/privileges/global.tpl @@ -94,18 +94,15 @@ {{{ each privileges.users }}} - + {function.spawnPrivilegeStates, privileges.users.username, ../privileges} From ba03e22317c8cd717a35a27dc68d32f9126e1554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 20 Jul 2023 16:38:44 -0400 Subject: [PATCH 136/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 1aea96d3f2..9644aa608e 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.9", + "nodebb-theme-harmony": "1.1.10", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.3", "nodebb-theme-persona": "13.2.6", From ee0128d7939d7f1f18dc71e99a386cfc5562c7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 20 Jul 2023 16:48:04 -0400 Subject: [PATCH 137/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 9644aa608e..ae69dc11f1 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.10", + "nodebb-theme-harmony": "1.1.11", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.3", "nodebb-theme-persona": "13.2.6", From 05c1e1f166d2559fccafd5e5b6447a30ff86d74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 20 Jul 2023 19:13:16 -0400 Subject: [PATCH 138/300] chore: up theme --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ae69dc11f1..f2c682f0f5 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.11", + "nodebb-theme-harmony": "1.1.12", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.3", "nodebb-theme-persona": "13.2.6", From 8ab9c72c6b29a5c59524208324e24cc467a143ac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 20:30:21 -0400 Subject: [PATCH 139/300] fix(deps): update dependency esbuild to v0.18.15 (#11823) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f2c682f0f5..4d8999f81e 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.14", + "esbuild": "0.18.15", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 9b1cc576049383cddbdb44d04e816ceb77d75a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 20 Jul 2023 22:26:55 -0400 Subject: [PATCH 140/300] add reverse support to db.processSortedSet (#11826) --- src/batch.js | 5 +++-- src/database/mongo/sorted.js | 4 ++-- src/database/postgres/sorted.js | 3 ++- src/messaging/notifications.js | 1 + 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/batch.js b/src/batch.js index 8442def721..4fb6c9a8e4 100644 --- a/src/batch.js +++ b/src/batch.js @@ -23,6 +23,7 @@ exports.processSortedSet = async function (setKey, process, options) { } options.batch = options.batch || DEFAULT_BATCH_SIZE; + options.reverse = options.reverse || false; // use the fast path if possible if (db.processSortedSet && typeof options.doneIf !== 'function' && !utils.isNumber(options.alwaysStartAt)) { @@ -38,10 +39,10 @@ exports.processSortedSet = async function (setKey, process, options) { if (process && process.constructor && process.constructor.name !== 'AsyncFunction') { process = util.promisify(process); } - + const method = options.reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'; while (true) { /* eslint-disable no-await-in-loop */ - const ids = await db[`getSortedSetRange${options.withScores ? 'WithScores' : ''}`](setKey, start, stop); + const ids = await db[`${method}${options.withScores ? 'WithScores' : ''}`](setKey, start, stop); if (!ids.length || options.doneIf(start, stop, ids)) { return; } diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 4e03a93509..9dbf947b1a 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -563,12 +563,12 @@ module.exports = function (module) { let done = false; const ids = []; const project = { _id: 0, _key: 0 }; - + const sort = options.reverse ? -1 : 1; if (!options.withScores) { project.score = 0; } const cursor = await module.client.collection('objects').find({ _key: setKey }, { projection: project }) - .sort({ score: 1 }) + .sort({ score: sort }) .batchSize(options.batch); if (processFn && processFn.constructor && processFn.constructor.name !== 'AsyncFunction') { diff --git a/src/database/postgres/sorted.js b/src/database/postgres/sorted.js index 2ed679b683..70e66af314 100644 --- a/src/database/postgres/sorted.js +++ b/src/database/postgres/sorted.js @@ -664,6 +664,7 @@ SELECT z."value", module.processSortedSet = async function (setKey, process, options) { const client = await module.pool.connect(); const batchSize = (options || {}).batch || 100; + const sort = options.reverse ? 'DESC' : 'ASC'; const cursor = client.query(new Cursor(` SELECT z."value", z."score" FROM "legacy_object_live" o @@ -671,7 +672,7 @@ SELECT z."value", z."score" ON o."_key" = z."_key" AND o."type" = z."type" WHERE o."_key" = $1::TEXT - ORDER BY z."score" ASC, z."value" ASC`, [setKey])); + ORDER BY z."score" ${sort}, z."value" ${sort}`, [setKey])); if (process && process.constructor && process.constructor.name !== 'AsyncFunction') { process = util.promisify(process); diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 0ef05c5acd..ccde83e3f4 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -83,6 +83,7 @@ module.exports = function (Messaging) { notifications.push(notification, uids); }, { + reverse: true, batch: 500, interval: 1000, }); From f377650161ee73f6f859fc1a386afde1b03ba3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 21 Jul 2023 09:09:35 -0400 Subject: [PATCH 141/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 4d8999f81e..e641a68e5a 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.12", + "nodebb-theme-harmony": "1.1.13", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.3", "nodebb-theme-persona": "13.2.6", From 61f036ce1d860fcd58055fcbc8bef6f1244f08ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 21 Jul 2023 15:31:34 -0400 Subject: [PATCH 142/300] Chat notifs (#11832) * first part of chat notifs * moved default notif to manage page * spec * notifs * delete settings on room delete --- install/package.json | 6 +- public/language/en-GB/modules.json | 6 ++ public/openapi/components/schemas/Chats.yaml | 2 + .../read/user/userslug/chats/roomid.yaml | 8 +++ public/src/client/chats.js | 33 +++++++++ public/src/client/chats/manage.js | 24 +++++-- src/api/chats.js | 24 +++++-- src/messaging/index.js | 5 ++ src/messaging/notifications.js | 69 ++++++++++++++----- src/messaging/rooms.js | 54 +++++++++++++-- src/messaging/unread.js | 19 +++++ src/notifications.js | 2 +- src/socket.io/modules.js | 13 ++++ src/views/modals/create-room.tpl | 9 +-- src/views/modals/manage-room.tpl | 21 ++++-- 15 files changed, 249 insertions(+), 46 deletions(-) diff --git a/install/package.json b/install/package.json index e641a68e5a..7d561f8e31 100644 --- a/install/package.json +++ b/install/package.json @@ -97,14 +97,14 @@ "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", - "nodebb-plugin-mentions": "4.3.2", + "nodebb-plugin-mentions": "4.3.3", "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.13", + "nodebb-theme-harmony": "1.1.14", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.3", - "nodebb-theme-persona": "13.2.6", + "nodebb-theme-persona": "13.2.7", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index 9d114b3fbc..46ea48a225 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 3b7383c774..3af68f754a 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -22,6 +22,8 @@ RoomObject: timestamp: type: number description: Timestamp of when room was created + notificationSetting: + type: number MessageObject: type: object properties: diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index a9a6ae9faf..d3eaee8e67 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -39,6 +39,12 @@ get: timestamp: type: number description: Timestamp of when room was created + notificationSetting: + type: number + notificationOptions: + type: array + notificationOptionsIcon: + type: string messages: type: array items: @@ -318,6 +324,8 @@ get: type: string chatWithMessage: type: string + notificationSetting: + type: number publicRooms: type: array items: diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 7307ae97bc..b329310bd8 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -99,6 +99,8 @@ define('forum/chats', [ }); userList.init(roomId, mainWrapper); Chats.addPublicRoomSortHandler(); + Chats.addTooltipHandler(); + Chats.addNotificationSettingHandler(); }; Chats.addPublicRoomSortHandler = function () { @@ -122,6 +124,37 @@ define('forum/chats', [ } }; + Chats.addTooltipHandler = function () { + $('[data-manual-tooltip]').tooltip({ + trigger: 'manual', + animation: false, + placement: 'bottom', + }).on('mouseenter', function (ev) { + const target = $(ev.target); + const isDropdown = target.hasClass('dropdown-menu') || !!target.parents('.dropdown-menu').length; + if (!isDropdown) { + $(this).tooltip('show'); + } + }).on('click mouseleave', function () { + $(this).tooltip('hide'); + }); + }; + + Chats.addNotificationSettingHandler = function () { + const notifSettingEl = $('[component="chat/notification/setting"]'); + + notifSettingEl.find('[data-value]').on('click', async function () { + notifSettingEl.find('i.fa-check').addClass('hidden'); + const $this = $(this); + $this.find('i.fa-check').removeClass('hidden'); + $('[component="chat/notification/setting/icon"]').attr('class', `fa ${$this.attr('data-icon')}`); + await socket.emit('modules.chats.setNotificationSetting', { + roomId: ajaxify.data.roomId, + value: $this.attr('data-value'), + }); + }); + }; + Chats.addUploadHandler = function (options) { uploadHelpers.init({ dragDropAreaEl: options.dragDropAreaEl, diff --git a/public/src/client/chats/manage.js b/public/src/client/chats/manage.js index 065a970606..73f33c53d3 100644 --- a/public/src/client/chats/manage.js +++ b/public/src/client/chats/manage.js @@ -23,7 +23,7 @@ define('forum/chats/manage', [ const html = await app.parseAndTranslate('modals/manage-room', { groups, user: app.user, - group: ajaxify.data, + room: ajaxify.data, }); modal = bootbox.dialog({ title: '[[modules:chat.manage-room]]', @@ -67,14 +67,28 @@ define('forum/chats/manage', [ }); }); - modal.find('[component="chat/manage/save/groups"]').on('click', (ev) => { - const btn = $(ev.target); + modal.find('[component="chat/manage/save"]').on('click', () => { + const notifSettingEl = modal.find('[component="chat/room/notification/setting"]'); api.put(`/chats/${roomId}`, { groups: modal.find('[component="chat/room/groups"]').val(), + notificationSetting: notifSettingEl.val(), }).then((payload) => { ajaxify.data.groups = payload.groups; - btn.addClass('btn-success'); - setTimeout(() => btn.removeClass('btn-success'), 1000); + ajaxify.data.notificationSetting = payload.notificationSetting; + const roomDefaultOption = payload.notificationOptions[0]; + $('[component="chat/notification/setting"] [data-icon]').first().attr( + 'data-icon', roomDefaultOption.icon + ); + $('[component="chat/notification/setting/sub-label"]').translateText( + roomDefaultOption.subLabel + ); + if (roomDefaultOption.selected) { + $('[component="chat/notification/setting/icon"]').attr( + 'class', `fa ${roomDefaultOption.icon}` + ); + } + + modal.modal('hide'); }).catch(alerts.error); }); }); diff --git a/src/api/chats.js b/src/api/chats.js index 029841648a..976c380679 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -40,11 +40,13 @@ chatsAPI.create = async function (caller, data) { if (!data) { throw new Error('[[error:invalid-data]]'); } + const isPublic = data.type === 'public'; const isAdmin = await user.isAdministrator(caller.uid); if (isPublic && !isAdmin) { throw new Error('[[error:no-privileges]]'); } + if (!data.uids || !Array.isArray(data.uids)) { throw new Error(`[[error:wrong-parameter-type, uids, ${typeof data.uids}, Array]]`); } @@ -55,6 +57,11 @@ chatsAPI.create = async function (caller, data) { if (isPublic && (!Array.isArray(data.groups) || !data.groups.length)) { throw new Error('[[error:no-groups-selected]]'); } + + data.notificationSetting = isPublic ? + messaging.notificationSettings.ATMENTION : + messaging.notificationSettings.ALLMESSAGES; + await Promise.all(data.uids.map(async uid => messaging.canMessageUser(caller.uid, uid))); const roomId = await messaging.newRoom(caller.uid, data); @@ -108,18 +115,21 @@ chatsAPI.update = async (caller, data) => { }); } } + const [roomData, isAdmin] = await Promise.all([ + messaging.getRoomData(data.roomId), + user.isAdministrator(caller.uid), + ]); + if (!roomData) { + throw new Error('[[error:invalid-data]]'); + } if (data.hasOwnProperty('groups')) { - const [roomData, isAdmin] = await Promise.all([ - messaging.getRoomData(data.roomId), - user.isAdministrator(caller.uid), - ]); - if (!roomData) { - throw new Error('[[error:invalid-data]]'); - } if (roomData.public && isAdmin) { await db.setObjectField(`chat:room:${data.roomId}`, 'groups', JSON.stringify(data.groups)); } } + if (data.hasOwnProperty('notificationSetting') && isAdmin) { + await db.setObjectField(`chat:room:${data.roomId}`, 'notificationSetting', data.notificationSetting); + } return messaging.loadRoom(caller.uid, { roomId: data.roomId, }); diff --git a/src/messaging/index.js b/src/messaging/index.js index ec41f84cae..42cf331278 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -25,6 +25,11 @@ require('./rooms')(Messaging); require('./unread')(Messaging); require('./notifications')(Messaging); +Messaging.notificationSettings = Object.create(null); +Messaging.notificationSettings.NONE = 1; +Messaging.notificationSettings.ATMENTION = 2; +Messaging.notificationSettings.ALLMESSAGES = 3; + Messaging.messageExists = async mid => db.exists(`message:${mid}`); Messaging.getMessages = async (params) => { diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index ccde83e3f4..11a1ebd16f 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -12,6 +12,23 @@ const meta = require('../meta'); module.exports = function (Messaging) { // Only used to notify a user of a new chat message Messaging.notifyQueue = {}; + + Messaging.setUserNotificationSetting = async (uid, roomId, value) => { + if (parseInt(value, 10) === -1) { + // go back to default + return await db.deleteObjectField(`chat:room:${roomId}:notification:settings`, uid); + } + await db.setObjectField(`chat:room:${roomId}:notification:settings`, uid, parseInt(value, 10)); + }; + + Messaging.getUidsNotificationSetting = async (uids, roomId) => { + const [settings, roomData] = await Promise.all([ + db.getObjectFields(`chat:room:${roomId}:notification:settings`, uids), + Messaging.getRoomData(roomId, ['notificationSetting']), + ]); + return uids.map(uid => parseInt(settings[uid] || roomData.notificationSetting, 10)); + }; + Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => { const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; @@ -34,13 +51,15 @@ module.exports = function (Messaging) { // delivers unread public msg to all online users on the chats page io.in(`chat_room_public_${roomId}`).emit('event:chats.public.unread', unreadData); } - if (messageObj.system || isPublic) { + if (messageObj.system) { return; } // push unread count only for private rooms - const uids = await Messaging.getAllUidsInRoomFromSet(`chat:room:${roomId}:uids:online`); - Messaging.pushUnreadCount(uids, unreadData); + if (!isPublic) { + const uids = await Messaging.getAllUidsInRoomFromSet(`chat:room:${roomId}:uids:online`); + Messaging.pushUnreadCount(uids, unreadData); + } // Delayed notifications let queueObj = Messaging.notifyQueue[`${fromUid}:${roomId}`]; @@ -65,27 +84,41 @@ module.exports = function (Messaging) { }; async function sendNotification(fromUid, roomId, messageObj) { - const { displayname } = messageObj.fromUser; - const isGroupChat = await Messaging.isGroupChat(roomId); - const notification = await notifications.create({ - type: isGroupChat ? 'new-group-chat' : 'new-chat', - subject: `[[email:notif.chat.subject, ${displayname}]]`, - bodyShort: `[[notifications:new_message_from, ${displayname}]]`, - bodyLong: messageObj.content, - nid: `chat_${fromUid}_${roomId}`, - from: fromUid, - path: `/chats/${messageObj.roomId}`, - }); + fromUid = parseInt(fromUid, 10); + const [settings, roomData] = await Promise.all([ + db.getObject(`chat:room:${roomId}:notification:settings`), + Messaging.getRoomData(roomId, ['notificationSetting']), + ]); + const roomDefault = roomData.notificationSetting; + const uidsToNotify = []; + const { ALLMESSAGES } = Messaging.notificationSettings; await batch.processSortedSet(`chat:room:${roomId}:uids:online`, async (uids) => { + uids = uids.filter( + uid => (parseInt((settings && settings[uid]) || roomDefault, 10) === ALLMESSAGES) && + fromUid !== parseInt(uid, 10) + ); const hasRead = await Messaging.hasRead(uids, roomId); - uids = uids.filter((uid, index) => !hasRead[index] && parseInt(fromUid, 10) !== parseInt(uid, 10)); - - notifications.push(notification, uids); + uidsToNotify.push(...uids.filter((uid, index) => !hasRead[index])); }, { reverse: true, batch: 500, - interval: 1000, + interval: 100, }); + + if (uidsToNotify.length) { + const { displayname } = messageObj.fromUser; + const isGroupChat = await Messaging.isGroupChat(roomId); + const notification = await notifications.create({ + type: isGroupChat ? 'new-group-chat' : 'new-chat', + subject: `[[email:notif.chat.subject, ${displayname}]]`, + bodyShort: `[[notifications:new_message_from, ${displayname}]]`, + bodyLong: messageObj.content, + nid: `chat_${fromUid}_${roomId}`, + from: fromUid, + path: `/chats/${messageObj.roomId}`, + }); + await notifications.push(notification, uidsToNotify); + } } }; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 2b212b7b74..c5698185ac 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -54,6 +54,15 @@ module.exports = function (Messaging) { data.groupChat = parseInt(data.groupChat, 10) === 1; } + if (!fields.length || fields.includes('notificationSetting')) { + data.notificationSetting = data.notificationSetting || + ( + data.public ? + Messaging.notificationSettings.ATMENTION : + Messaging.notificationSettings.ALLMESSAGES + ); + } + if (data.hasOwnProperty('groups') || !fields.length || fields.includes('groups')) { try { data.groups = JSON.parse(data.groups || '[]'); @@ -76,6 +85,7 @@ module.exports = function (Messaging) { const room = { roomId: roomId, timestamp: now, + notificationSetting: data.notificationSetting, }; if (data.hasOwnProperty('roomName') && data.roomName) { @@ -145,10 +155,14 @@ module.exports = function (Messaging) { ...roomIds.map(id => `chat:room:${id}:uids`), ...roomIds.map(id => `chat:room:${id}:owners`), ...roomIds.map(id => `chat:room:${id}:uids:online`), + ...roomIds.map(id => `chat:room:${id}:notification:settings`), ]), - db.sortedSetRemove('chat:rooms', roomIds), - db.sortedSetRemove('chat:rooms:public', roomIds), - db.sortedSetRemove('chat:rooms:public:order', roomIds), + db.sortedSetRemove([ + 'chat:rooms', + 'chat:rooms:public', + 'chat:rooms:public:order', + 'chat:rooms:public:lastpost', + ], roomIds), ]); cache.del([ 'chat:rooms:public:all', @@ -448,7 +462,36 @@ module.exports = function (Messaging) { await db.sortedSetAdd(`chat:room:${roomId}:uids:online`, Date.now(), uid); } - const [canReply, users, messages, settings, isOwner, onlineUids] = await Promise.all([ + async function getNotificationOptions() { + const userSetting = await db.getObjectField(`chat:room:${roomId}:notification:settings`, uid); + const roomDefault = room.notificationSetting; + const currentSetting = userSetting || roomDefault; + const labels = { + [Messaging.notificationSettings.NONE]: { label: '[[modules:chat.notification-setting-none]]', icon: 'fa-ban' }, + [Messaging.notificationSettings.ATMENTION]: { label: '[[modules:chat.notification-setting-at-mention-only]]', icon: 'fa-at' }, + [Messaging.notificationSettings.ALLMESSAGES]: { label: '[[modules:chat.notification-setting-all-messages]]', icon: 'fa-comment-o' }, + }; + const options = [ + { + label: '[[modules:chat.notification-setting-room-default]]', + subLabel: labels[roomDefault].label || '', + icon: labels[roomDefault].icon, + value: -1, + selected: userSetting === null, + }, + ]; + Object.keys(labels).forEach((key) => { + options.push({ + label: labels[key].label, + icon: labels[key].icon, + value: key, + selected: parseInt(userSetting, 10) === parseInt(key, 10), + }); + }); + return { options, selectedIcon: labels[currentSetting].icon }; + } + + const [canReply, users, messages, settings, isOwner, onlineUids, notifOptions] = await Promise.all([ Messaging.canReply(roomId, uid), Messaging.getUsersInRoomFromSet(`chat:room:${roomId}:uids:online`, roomId, 0, 39, true), Messaging.getMessages({ @@ -460,6 +503,7 @@ module.exports = function (Messaging) { user.getSettings(uid), Messaging.isRoomOwner(uid, roomId), io.getUidsInRoom(`chat_room_${roomId}`), + getNotificationOptions(), ]); users.forEach((user) => { @@ -481,6 +525,8 @@ module.exports = function (Messaging) { room.showUserInput = !room.maximumUsersInChatRoom || room.maximumUsersInChatRoom > 2; room.isAdminOrGlobalMod = isAdmin || isGlobalMod; room.isAdmin = isAdmin; + room.notificationOptions = notifOptions.options; + room.notificationOptionsIcon = notifOptions.selectedIcon; const payload = await plugins.hooks.fire('filter:messaging.loadRoom', { uid, data, room }); return payload.room; diff --git a/src/messaging/unread.js b/src/messaging/unread.js index 8b98ec279d..6144def618 100644 --- a/src/messaging/unread.js +++ b/src/messaging/unread.js @@ -33,6 +33,25 @@ module.exports = function (Messaging) { }; Messaging.hasRead = async (uids, roomId) => { + if (!uids.length) { + return []; + } + const roomData = await Messaging.getRoomData(roomId); + if (!roomData) { + return uids.map(() => false); + } + if (roomData.public) { + const [userTimestamps, mids] = await Promise.all([ + db.getObjectsFields(uids.map(uid => `uid:${uid}:chat:rooms:read`), [roomId]), + db.getSortedSetRevRangeWithScores(`chat:room:${roomId}:mids`, 0, 0), + ]); + const lastMsgTimestamp = mids[0] ? mids[0].score : 0; + return uids.map( + (uid, index) => !userTimestamps[index] || + !userTimestamps[index][roomId] || + parseInt(userTimestamps[index][roomId], 10) > lastMsgTimestamp + ); + } const isMembers = await db.isMemberOfSortedSets( uids.map(uid => `uid:${uid}:chat:rooms:unread`), roomId diff --git a/src/notifications.js b/src/notifications.js index b484129d5c..b4a8aeff63 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -159,7 +159,7 @@ Notifications.push = async function (notification, uids) { winston.error(err.stack); } }); - }, 1000); + }, 500); }; async function pushToUids(uids, notification) { diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index e244892d01..7b233d7d35 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -200,4 +200,17 @@ SocketModules.chats.toggleOwner = async (socket, data) => { await Messaging.toggleOwner(data.uid, data.roomId); }; +SocketModules.chats.setNotificationSetting = async (socket, data) => { + if (!data || !utils.isNumber(data.value) || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + + const inRoom = await Messaging.isUserInRoom(socket.uid, data.roomId); + if (!inRoom) { + throw new Error('[[error:no-privileges]]'); + } + + await Messaging.setUserNotificationSetting(socket.uid, data.roomId, data.value); +}; + require('../promisify')(SocketModules); diff --git a/src/views/modals/create-room.tpl b/src/views/modals/create-room.tpl index 4df85c294d..a4b47c85a0 100644 --- a/src/views/modals/create-room.tpl +++ b/src/views/modals/create-room.tpl @@ -1,10 +1,11 @@
- - + +
+
- \ No newline at end of file From 4ed0ed454c574082bab4d1eb08641a67caa95a6f Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Fri, 21 Jul 2023 19:31:58 +0000 Subject: [PATCH 143/300] chore(i18n): fallback strings for new resources: nodebb.modules --- public/language/ar/modules.json | 6 ++++++ public/language/bg/modules.json | 6 ++++++ public/language/bn/modules.json | 6 ++++++ public/language/cs/modules.json | 6 ++++++ public/language/da/modules.json | 6 ++++++ public/language/de/modules.json | 6 ++++++ public/language/el/modules.json | 6 ++++++ public/language/en-US/modules.json | 6 ++++++ public/language/en-x-pirate/modules.json | 6 ++++++ public/language/es/modules.json | 6 ++++++ public/language/et/modules.json | 6 ++++++ public/language/fa-IR/modules.json | 6 ++++++ public/language/fi/modules.json | 6 ++++++ public/language/fr/modules.json | 6 ++++++ public/language/gl/modules.json | 6 ++++++ public/language/he/modules.json | 6 ++++++ public/language/hr/modules.json | 6 ++++++ public/language/hu/modules.json | 6 ++++++ public/language/hy/modules.json | 6 ++++++ public/language/id/modules.json | 6 ++++++ public/language/it/modules.json | 6 ++++++ public/language/ja/modules.json | 6 ++++++ public/language/ko/modules.json | 6 ++++++ public/language/lt/modules.json | 6 ++++++ public/language/lv/modules.json | 6 ++++++ public/language/ms/modules.json | 6 ++++++ public/language/nb/modules.json | 6 ++++++ public/language/nl/modules.json | 6 ++++++ public/language/pl/modules.json | 6 ++++++ public/language/pt-BR/modules.json | 6 ++++++ public/language/pt-PT/modules.json | 6 ++++++ public/language/ro/modules.json | 6 ++++++ public/language/ru/modules.json | 6 ++++++ public/language/rw/modules.json | 6 ++++++ public/language/sc/modules.json | 6 ++++++ public/language/sk/modules.json | 6 ++++++ public/language/sl/modules.json | 6 ++++++ public/language/sq-AL/modules.json | 6 ++++++ public/language/sr/modules.json | 6 ++++++ public/language/sv/modules.json | 6 ++++++ public/language/th/modules.json | 6 ++++++ public/language/tr/modules.json | 6 ++++++ public/language/uk/modules.json | 6 ++++++ public/language/vi/modules.json | 6 ++++++ public/language/zh-CN/modules.json | 6 ++++++ public/language/zh-TW/modules.json | 6 ++++++ 46 files changed, 276 insertions(+) diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 14fb8d7a39..181b234279 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 9b6d3bd35f..b38f092017 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "За да създадете стая за разговор видима за всички потребители изберете групата с регистрирани потребители от списъка.", "chat.manage-room": "Управление на стаята за разговори", "chat.add-user": "Добавяне на потребител", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Избиране на групи", "chat.add-user-help": "Тук можете да потърсите потребители. Когато някой потребител бъде избран, той ще бъде добавен в разговора. Новият потребител няма да може да вижда съобщенията, написани преди включването му в разговора. Само собствениците на стаята () могат да премахват потребители от нея.", "chat.confirm-chat-with-dnd-user": "Този потребител е в състояние „не ме безпокойте“. Наистина ли искате да разговаряте с него?", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index 6088d96ae3..52c9a4105a 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index 0b750313bb..eb5cb5e3de 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Spravovat konverzační místnosti", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Zde můžete vyhledávat uživatele. Jakmile si ho vyberete, uživatel bude přidán do konverzace. Nový uživatel nebude mít zobrazeny zprávy konverzace napsané dříve, než byl do konverzace přidán. Jen majitelé místnosti () mohou odebrat uživatele z konverzační místnosti.", "chat.confirm-chat-with-dnd-user": "Tento uživatel nastavil svůj stav na NERUŠIT. Opravdu chcete začít s ním konverzaci.", diff --git a/public/language/da/modules.json b/public/language/da/modules.json index d448c6d6fe..fecc99f04e 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index 90c8e23fb6..522254fd7a 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Chatroom managen", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Suche hier nach Usern. Auswählen fügt den User hinzu. Der neue User wird nicht in der Lage sein Chat Nachrichten zu lesen, die geschrieben wurden bevor er der Konversation hinzugefügt wurde. Ausschließlich Raumbesitzer () können User von Chat Rooms entfernen.", "chat.confirm-chat-with-dnd-user": "Dieser Benutzer hat seinen Status auf DnD (Bitte nicht stören) gesetzt. Möchtest du dennoch mit ihm chatten?", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index d6917f1c81..aecc617128 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/en-US/modules.json b/public/language/en-US/modules.json index d6917f1c81..aecc617128 100644 --- a/public/language/en-US/modules.json +++ b/public/language/en-US/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/en-x-pirate/modules.json b/public/language/en-x-pirate/modules.json index 3116610a92..f338462a53 100644 --- a/public/language/en-x-pirate/modules.json +++ b/public/language/en-x-pirate/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index 634041c012..a389cd7609 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Administrar Sala de Chat", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "Este usuario está en modo No molestar. ¿ Estás seguro de que quieres chatear con él ?", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index eb17f01921..37b20c6d42 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/fa-IR/modules.json b/public/language/fa-IR/modules.json index 2e4bb47b09..a46b518f34 100644 --- a/public/language/fa-IR/modules.json +++ b/public/language/fa-IR/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "مدیریت چت روم", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "کاربران را در اینجا جستجو کنید. پس از انتخاب، کاربر به چت اضافه می شود. کاربر جدید نمی‌تواند پیام‌های چت نوشته شده قبل از اضافه شدن به مکالمه را ببیند. فقط مالک اتاق () می توانند کاربران را از اتاق های گفتگو حذف کنند.", "chat.confirm-chat-with-dnd-user": "این کاربر وضعیت خود را روی حالت مزاحم نشوید قرار داده است. آیا همچنان می خواهید با او چت کنید؟", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index 55f86dce0b..6dd7931adf 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 1886f0361a..ba8ce2afef 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gérer l'espace de discussion", "chat.add-user": "Ajouter un utilisateur", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Sélectionner des groupes", "chat.add-user-help": "Rechercher des utilisateurs ici. Lorsque cette option est sélectionnée, l'utilisateur sera ajouté à l'espace de discussion. Le nouvel utilisateur ne pourra pas visualiser les échanges avant d'être ajoutés à la conversation. Seuls les propriétaires de l'espace de discussion () peuvent supprimer des utilisateurs.", "chat.confirm-chat-with-dnd-user": "Cet utilisateur a son statut en mode \"Ne pas déranger\". Voulez-vous quand même discuter avec lui ?", diff --git a/public/language/gl/modules.json b/public/language/gl/modules.json index 56232ccd1c..fc8ddc4481 100644 --- a/public/language/gl/modules.json +++ b/public/language/gl/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 884f89bb32..f3944b2c87 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "כדי ליצור חדר צ'אט הגלוי לכל המשתמשים בחר \"משתמשים רשומים\" מרשימת הקבוצות.", "chat.manage-room": "ניהול חדר צ'אט", "chat.add-user": "הוסף משתמש", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "בחר קבוצות", "chat.add-user-help": "חפשו משתמשים כאן. כאשר משתמש נבחר, הוא יצורף לצ'אט. המשתמש החדש לא יוכל לראות הודעות שנכתבו לפני הצטרפותו. רק מנהלי החדר () יכולים להסיר משתמשים מהצ'אט.", "chat.confirm-chat-with-dnd-user": "משתמש זה שינה את הסטטוס שלו ל'לא להפריע'. אתם עדיין מעוניין לשוחח איתו?", diff --git a/public/language/hr/modules.json b/public/language/hr/modules.json index ab17f9929f..d44499d5e2 100644 --- a/public/language/hr/modules.json +++ b/public/language/hr/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "Korisnik ne želi biti ometan. Jeste li sigurno da mu želite poslati poruku?", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index 63db09d574..b814f6efcd 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Csevegő szoba kezelése", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Itt keress felhasználókat. Kiválasztás után a felhasználó hozzá lesz adva a chathez. Az új felhasználó nem fogja látni az üzenet előzményeket az előttről, hogy hozzá lett adva a beszélgetéshez. Csak a szoba tulajdonosai () távolíthatnak el felhasználókat a beszélgetésből.", "chat.confirm-chat-with-dnd-user": "A felhasználó \"ne zavarj\"-ra állította az állapotukat. Még így is csevegni akarsz velük?", diff --git a/public/language/hy/modules.json b/public/language/hy/modules.json index a30fea4b4a..40cbb76d75 100644 --- a/public/language/hy/modules.json +++ b/public/language/hy/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Կարգավորել Զրուցասենյակը", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Որոնել օգտերերին այստեղ: Ընտրվելուց հետո օգտատերը կավելացվի զրուցարանում: Նոր օգտատերը չի կարողանա տեսնել զրույցի հաղորդագրությունները, որոնք գրված են նախքան դրանք ավելացվելը խոսակցությանը: Միայն սենյակների սեփականատերերը կարող են օգտատերերին հեռացնել զրուցարաններից:", "chat.confirm-chat-with-dnd-user": "Այս օգտվողը դրել է իր կարգավիճակը DnD (Մի խանգարեք): Դեռ ցանկանու՞մ եք զրուցել նրանց հետ:", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index fbd944f1ca..89ccc3bf5c 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index bc0fa558fe..2dbebd013e 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "Per creare una stanza chat visibile a tutti gli utenti, seleziona gli utenti registrati dall'elenco dei gruppi.", "chat.manage-room": "Gestisci stanza chat", "chat.add-user": "Aggiungi utente", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Seleziona gruppi", "chat.add-user-help": "Cerca qui gli utenti. Quando selezionato, l'utente sarà aggiunto alla chat.\nIl nuovo utente non sarà in grado di vedere i messaggi della chat scritti prima della sua partecipazione alla conversazione.\nSolo i proprietari della stanza () possono rimuovere gli utenti dalla stanza della chat.", "chat.confirm-chat-with-dnd-user": "Questo utente ha impostato il suo stato su Non Disturbare. Sei sicuro di voler iniziare una conversazione?", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index 7ba8596be1..18dd1bf21b 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "チャット部屋を管理", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "このユーザーのステータスはDnD(Do not disturb:取り込み中)に設定されています。あなたはまだチャットしたいですか?", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index aaf66e705a..40d3a33dd7 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "채팅 관리", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "여기에서 사용자를 검색하세요. 선택한 사용자를 채팅에 초대합니다. 새로운 사용자는 이전에 주고받은 채팅을 확인할 수 없습니다. 채팅 관리자들()만 사용자를 채팅방에서 추방할 수 있습니다.", "chat.confirm-chat-with-dnd-user": "이 사용자는 자신의 상태를 방해 금지로 설정했습니다. 그래도 대화를 요청하시겠습니까?", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index aefebd4237..459a2a9b17 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/lv/modules.json b/public/language/lv/modules.json index b1c8c70e84..87fc215797 100644 --- a/public/language/lv/modules.json +++ b/public/language/lv/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Pārvaldīt tērzētavu", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Meklē lietotājus šeit. Izvēlētais lietotājs tiks pievienots sarunai. Jaunais lietotājs neredzēs sarunas, kas rakstītas pirms viņu pievienoja sarunai. Tikai tērzētavas īpašnieks(-i) var noņemt lietotājus no tērzētavām.", "chat.confirm-chat-with-dnd-user": "Lietotājs ir iestatījis savu statusu uz DnD (netraucējams). Vai Tu joprojām vēlies sarunāties ar viņu?", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index 7f811f93c1..c730b8c1ff 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 2d8cac650c..0be7553875 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Søk etter brukere her. Når dette er valgt, blir brukeren lagt til i chatten. Den nye brukeren vil ikke kunne se chatmeldinger skrevet før de ble lagt til i samtalen. Bare romeiere () kan fjerne brukere fra chatterom.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index b86f3c50be..26c542dca1 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Chat Room beheren", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Zoek hier naar gebruikers. Indien geselecteerd word de gebruiker toegevoegd aan de chat. De nieuwe gebruiker kan geen chatberichten zien die geschreven zijn voordat de gebruiker was toegevoegd aan de conversatie. Alleen chatroom-eigenaren () kunnen gebruikers verwijderen uit een chatroom.", "chat.confirm-chat-with-dnd-user": "Deze gebruiker heeft de status op Niet Storen (DnD, Do not disturb) gezet. Wil je nog steeds een chat starten met deze persoon?", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index ef69f1a3d3..1717f2a916 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Zarządzaj pokojami czatu", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Tu można wyszukiwać użytkowników. Wybrany użytkownik zostanie dodany do czatu. Nowy użytkownik nie zobaczy wiadomości sprzed dołączenia do konwersacji. Tylko właściciele pokoi () mogą usuwać użytkowników z pokoi czatu.", "chat.confirm-chat-with-dnd-user": "Ten użytkownik ustawił status „nie przeszkadzać”. Czy chcesz z nim rozmawiać mimo to?", diff --git a/public/language/pt-BR/modules.json b/public/language/pt-BR/modules.json index 91bb7f21c3..16bc2f74a4 100644 --- a/public/language/pt-BR/modules.json +++ b/public/language/pt-BR/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Administrar Salas de Conversa", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Pesquise usuários aqui. Quando selecionado, o usuário será adicionado ao chat. O novo usuário não poderá ver as mensagens de chat que foram enviadas antes de ele ser adicionado à conversa. Somente os donos de salas () podem remover usuários de salas de conversa.", "chat.confirm-chat-with-dnd-user": "Este usuário definiu seu estado como DnD(Do not disturb - Não perturbe). Você ainda assim quer conversar com ele?", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index 3a897738b4..d842bbda62 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gerir sala de conversa", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Encontra utilizadores aqui. Quando selecionado, o utilizador vai ser adicionado à conversa. O novo utilizador não conseguirá ver mensagens que foram enviadas antes de ele entrar na sala. Apenas os donos das salas () poderão remover participantes das salas de conversa", "chat.confirm-chat-with-dnd-user": "Este utilizador definiu o seu estado como \"não perturbar\". Pretendes mesmo assim conversar com ele?", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index 33b4c9d2b1..3127065391 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 3f5a26ba5b..0eb1e78d70 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управлять комнатой чата", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Поиск пользователей здесь. Когда выбрали пользователя, он будет добавлен в чат. Новый пользователь не сможет видеть сообщения чата, написанные до его добавления в беседу. Только владельцы комнат () могут удалить пользователей из чатов.", "chat.confirm-chat-with-dnd-user": "Этот пользователь установил статус \"Не беспокоить\". Вы всё еще хотите написать ему?", diff --git a/public/language/rw/modules.json b/public/language/rw/modules.json index c4ce295bfa..775280fee3 100644 --- a/public/language/rw/modules.json +++ b/public/language/rw/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index 65dd4fa80c..32d867babb 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index cd3f3833d2..d7826260cd 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Spravovať konverzačné miestnosti", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Tu môžete vyhľadávať používateľov. Akonáhle si ho vyberiete, užívateľ bude pridaný do konverzácie. Nový používateľ nebude mať možnosť čítať správy, ktoré boli napísané skôr, ako bol pridaný do konverzácie. Iba majitelia miestnosti () môžu odobrať používateľov z konverzačných miestností.", "chat.confirm-chat-with-dnd-user": "Tento používateľ nastavil svoj stav na NERUŠIŤ. Naozaj chcete s ním začať konverzáciu?", diff --git a/public/language/sl/modules.json b/public/language/sl/modules.json index 1500e8b5bc..84bb172316 100644 --- a/public/language/sl/modules.json +++ b/public/language/sl/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Upravljaj sobo klepeta", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", diff --git a/public/language/sq-AL/modules.json b/public/language/sq-AL/modules.json index d04fc96198..83012f9373 100644 --- a/public/language/sq-AL/modules.json +++ b/public/language/sq-AL/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Menaxho hapësirën e bisedave", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Kërkoni për përdoruesit këtu. Kur zgjidhet, përdoruesi do të shtohet në bisedë. Përdoruesi i ri nuk do të jetë në gjendje të shohë mesazhet e bisedës të shkruara përpara se të shtoheshin në bisedë. Vetëm krijuesit e bisedes () mund të heqin përdoruesit nga hapesirat e bisedës.", "chat.confirm-chat-with-dnd-user": "Ky përdorues ka vendosur statusin e tij në (Mos shqetëso). Dëshiron ende të bisedosh me ta?", diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index 45f4402bb0..f992ff3143 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "За креирање собе за ћаскање која је видљива свим корисницима, изаберите регистроване кориснике са листе група.", "chat.manage-room": "Управљај собом за ћаскање", "chat.add-user": "Додај корисника", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Изаберите групе", "chat.add-user-help": "Потражите кориснике овде. Када буде изабран, корисник ће бити додан у ћаскање. Нови корисник неће бити у могућности да види поруке написане пре него што је додан у преписку. Само власници соба () могу уклонити кориснике из соба за ћаскање.", "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на „Не узнемиравај”. Да ли и даље желите да ћаскате са њим?", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 42274d2f02..6bc128d3e2 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Hantera chattrum", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Sök efter användare här. Vid markering läggs användaren till i chatten. Den nya användaren kommer inte kunna se chattmeddelanden som skrevs innan de lades till i konversationen. Endast chattrumsägare () kan avlägsna användare från chattrum.", "chat.confirm-chat-with-dnd-user": "Denna användare har satt sin status till Stör Ej. Vill du fortfarande chatta med dem?", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index 421ac4d22c..16bfea1ecb 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "จัดการห้องแชท", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "ผู้ใช้นี้ได้ตั้งค่าสถานะเป็น (ห้ามรบกวน) คุณยังอยากจะคุยกับเขาอยู่ไหม?", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 113c91d5f4..9bfbdb71f2 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Sohbet Odasını Yönet", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Burada kullanıcılar için arama yapın. Kullanıcı seçildiğinde sohbete eklenecektir. Yeni kullanıcı sohbete eklenmeden önce yazılmış olan sohbet mesajlarını göremeyecektir. Yalnızca oda sahipleri () kullanıcıları sohbet odalarından kaldırabilir.", "chat.confirm-chat-with-dnd-user": "Bu kullanıcı durumunu rahatsız etmeyin olarak ayarladı. Hala onunla sohbet etmek istiyor musunuz?", diff --git a/public/language/uk/modules.json b/public/language/uk/modules.json index 8d755a5fc9..55a8c2fa05 100644 --- a/public/language/uk/modules.json +++ b/public/language/uk/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управління чат кімнатами", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Шукайте користувачів тут. Користувача можна додати до чату, обравши його. Нові користувачі не можуть бачити повідомлення, написані до того, як їх додали до розмови. Тільки власники кімнат можуть видаляти користувачів з кімнат.", "chat.confirm-chat-with-dnd-user": "Користувач змінив свій статус на DnD (Не турбувати). Ви дійсно бажаєте надіслати йому повідомлення в чат?", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 808e7b0315..e8f686c2cc 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Quản Lý Phòng Trò Chuyện", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "Tìm người dùng ở đây. Người dùng được chọn sẽ được thêm vào trò chuyện. Người dùng mới sẽ không thấy tin nhắn trò chuyện được đăng trước khi họ được thêm vào. Chỉ chủ phòng () được xóa người dùng khỏi phòng trò chuyện.", "chat.confirm-chat-with-dnd-user": "Người dùng này đã đặt trạng thái của họ thành DnD (Không làm phiền). Bạn vẫn muốn trò chuyện với họ?", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index 93135173ff..28c3195a75 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "管理聊天室", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "在这里查找更多用户。被选中的用户会被添加到聊天中。新用户不能他们被加入对话前的聊天消息。只有聊天室所有者()可以从聊天室中移除用户。", "chat.confirm-chat-with-dnd-user": "该用户已将其状态设置为 DnD(请勿打扰)。 您仍希望与其聊天吗?", diff --git a/public/language/zh-TW/modules.json b/public/language/zh-TW/modules.json index 534e79dcfd..351b4e96b3 100644 --- a/public/language/zh-TW/modules.json +++ b/public/language/zh-TW/modules.json @@ -36,6 +36,12 @@ "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "管理聊天室", "chat.add-user": "Add User", + "chat.notification-settings": "Notification Settings", + "chat.default-notification-setting": "Default Notification Setting", + "chat.notification-setting-room-default": "Room Default", + "chat.notification-setting-none": "No notifications", + "chat.notification-setting-at-mention-only": "@mention only", + "chat.notification-setting-all-messages": "All messages", "chat.select-groups": "Select Groups", "chat.add-user-help": "在這裡搜尋更多使用者。選中之後加入到聊天中,新使用者在加入聊天之前看不到聊天訊息。只有聊天室所有者()可以從聊天室中移除使用者。", "chat.confirm-chat-with-dnd-user": "該使用者已將其狀態設置為 DnD(請勿打擾)。 您仍希望與其聊天嗎?", From 472fbd85b88df3c5718185644c1a1e94d43903a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 21 Jul 2023 15:33:24 -0400 Subject: [PATCH 144/300] chore: up themes --- install/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/package.json b/install/package.json index 7d561f8e31..d1849f4777 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.14", + "nodebb-theme-harmony": "1.1.15", "nodebb-theme-lavender": "7.1.3", - "nodebb-theme-peace": "2.1.3", - "nodebb-theme-persona": "13.2.7", + "nodebb-theme-peace": "2.1.4", + "nodebb-theme-persona": "13.2.8", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", From 2792d771047a460da55180c0fc4984ffa2b8d77d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 21 Jul 2023 15:47:22 -0400 Subject: [PATCH 145/300] fix: reset_code.tpl card block expanding to bottom of container --- src/views/reset_code.tpl | 76 ++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/views/reset_code.tpl b/src/views/reset_code.tpl index 2365d7614c..ab3e58fc90 100644 --- a/src/views/reset_code.tpl +++ b/src/views/reset_code.tpl @@ -1,42 +1,42 @@ -{{{ if valid }}} -
- {{{ if displayExpiryNotice }}} -
- [[reset_password:password_expired]] +
+ {{{ if valid }}} +
+ {{{ if displayExpiryNotice }}} +
+ [[reset_password:password_expired]] +
+ {{{ end }}} + + +
+
+ +
+
+
+ +
+
+ + +
+ {{{ else }}} +
+
+ [[reset_password:wrong_reset_code.title]] +
+
+

[[reset_password:wrong_reset_code.message]]

+
{{{ end }}} - - -
-
- -
-
-
- -
-
-
- -
- -
-{{{ else }}} -
-
- [[reset_password:wrong_reset_code.title]] -
-
-

[[reset_password:wrong_reset_code.message]]

-
-
-{{{ end }}} \ No newline at end of file +
\ No newline at end of file From 4f3f9d9891b441d3bec72e2763edaa2c56965cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 21 Jul 2023 16:19:26 -0400 Subject: [PATCH 146/300] mark chat room notifs read on load --- src/api/chats.js | 18 ------------------ src/controllers/write/chats.js | 4 ++-- src/messaging/notifications.js | 14 +++++++++++++- src/messaging/rooms.js | 13 ++++++------- test/messaging.js | 2 +- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/api/chats.js b/src/api/chats.js index 976c380679..16a54de74d 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -6,7 +6,6 @@ const db = require('../database'); const user = require('../user'); const meta = require('../meta'); const messaging = require('../messaging'); -const notifications = require('../notifications'); const plugins = require('../plugins'); const privileges = require('../privileges'); @@ -152,27 +151,10 @@ chatsAPI.mark = async (caller, data) => { } else { await messaging.markRead(caller.uid, roomId); socketHelpers.emitToUids('event:chats.markedAsRead', { roomId: roomId }, [caller.uid]); - - const isUserInRoom = await messaging.isUserInRoom(caller.uid, roomId); - if (!isUserInRoom) { - return; - } - let chatNids = await db.getSortedSetScan({ - key: `uid:${caller.uid}:notifications:unread`, - match: `chat_*`, - }); - chatNids = chatNids.filter( - nid => nid && !nid.startsWith(`chat_${caller.uid}_`) && nid.endsWith(`_${roomId}`) - ); - - await notifications.markReadMultiple(chatNids, caller.uid); - await user.notifications.pushCount(caller.uid); } socketHelpers.emitToUids('event:chats.mark', { roomId, state }, [caller.uid]); messaging.pushUnreadCount(caller.uid); - - return messaging.loadRoom(caller.uid, { roomId }); }; chatsAPI.users = async (caller, data) => { diff --git a/src/controllers/write/chats.js b/src/controllers/write/chats.js index e595ef1a44..2266795eec 100644 --- a/src/controllers/write/chats.js +++ b/src/controllers/write/chats.js @@ -58,12 +58,12 @@ Chats.rename = async (req, res) => { Chats.mark = async (req, res) => { const state = req.method === 'PUT' ? 1 : 0; - const roomObj = await api.chats.mark(req, { + await api.chats.mark(req, { roomId: req.params.roomId, state, }); - helpers.formatApiResponse(200, res, roomObj); + helpers.formatApiResponse(200, res); }; Chats.users = async (req, res) => { diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 11a1ebd16f..2295dcd58a 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -5,6 +5,7 @@ const winston = require('winston'); const batch = require('../batch'); const db = require('../database'); const notifications = require('../notifications'); +const user = require('../user'); const io = require('../socket.io'); const plugins = require('../plugins'); const meta = require('../meta'); @@ -29,6 +30,17 @@ module.exports = function (Messaging) { return uids.map(uid => parseInt(settings[uid] || roomData.notificationSetting, 10)); }; + Messaging.markRoomNotificationsRead = async (uid, roomId) => { + const chatNids = await db.getSortedSetScan({ + key: `uid:${uid}:notifications:unread`, + match: `chat_${roomId}_*`, + }); + if (chatNids.length) { + await notifications.markReadMultiple(chatNids, uid); + await user.notifications.pushCount(uid); + } + }; + Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => { const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; @@ -114,7 +126,7 @@ module.exports = function (Messaging) { subject: `[[email:notif.chat.subject, ${displayname}]]`, bodyShort: `[[notifications:new_message_from, ${displayname}]]`, bodyLong: messageObj.content, - nid: `chat_${fromUid}_${roomId}`, + nid: `chat_${roomId}_${fromUid}`, from: fromUid, path: `/chats/${messageObj.roomId}`, }); diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index c5698185ac..51c76c6ce9 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -26,16 +26,14 @@ const intFields = [ module.exports = function (Messaging) { Messaging.getRoomData = async (roomId, fields = []) => { - const data = await db.getObject(`chat:room:${roomId}`, fields); - if (!data) { - throw new Error('[[error:no-chat-room]]'); - } - - modifyRoomData([data], fields); - return data; + const roomData = await Messaging.getRoomsData([roomId], fields); + return roomData[0]; }; Messaging.getRoomsData = async (roomIds, fields = []) => { + if (fields.includes('notificationSetting') && !fields.includes('public')) { + fields.push('public'); + } const roomData = await db.getObjects( roomIds.map(roomId => `chat:room:${roomId}`), fields @@ -504,6 +502,7 @@ module.exports = function (Messaging) { Messaging.isRoomOwner(uid, roomId), io.getUidsInRoom(`chat_room_${roomId}`), getNotificationOptions(), + Messaging.markRoomNotificationsRead(uid, roomId), ]); users.forEach((user) => { diff --git a/test/messaging.js b/test/messaging.js index 9b07ff3670..cb9e9f1555 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -404,7 +404,7 @@ describe('Messaging Library', () => { assert(data.unread[0]); const notification = data.unread[0]; assert.strictEqual(notification.bodyShort, 'New message from foo'); - assert.strictEqual(notification.nid, `chat_${mocks.users.foo.uid}_${roomId}`); + assert.strictEqual(notification.nid, `chat_${roomId}_${mocks.users.foo.uid}`); assert.strictEqual(notification.path, `${nconf.get('relative_path')}/chats/${roomId}`); }); From 0495b863a912fbff5749c67e860612b91825407c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 21 Jul 2023 16:20:44 -0400 Subject: [PATCH 147/300] chore: up mentions --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index d1849f4777..5b37f6774f 100644 --- a/install/package.json +++ b/install/package.json @@ -97,7 +97,7 @@ "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", - "nodebb-plugin-mentions": "4.3.3", + "nodebb-plugin-mentions": "4.3.4", "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", From fdef39d7cb5f997aa68cde0a88969bff65b0d44c Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 23 Jul 2023 09:18:10 +0000 Subject: [PATCH 148/300] Latest translations and fallbacks --- public/language/it/modules.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 2dbebd013e..808a26a41e 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -36,12 +36,12 @@ "chat.public.groups-help": "Per creare una stanza chat visibile a tutti gli utenti, seleziona gli utenti registrati dall'elenco dei gruppi.", "chat.manage-room": "Gestisci stanza chat", "chat.add-user": "Aggiungi utente", - "chat.notification-settings": "Notification Settings", - "chat.default-notification-setting": "Default Notification Setting", - "chat.notification-setting-room-default": "Room Default", - "chat.notification-setting-none": "No notifications", - "chat.notification-setting-at-mention-only": "@mention only", - "chat.notification-setting-all-messages": "All messages", + "chat.notification-settings": "Impostazioni di notifica", + "chat.default-notification-setting": "Impostazioni di notifica predefinite", + "chat.notification-setting-room-default": "Stanza predefinita", + "chat.notification-setting-none": "Nessuna notifica", + "chat.notification-setting-at-mention-only": "@solo menzione", + "chat.notification-setting-all-messages": "Tutti i messaggi", "chat.select-groups": "Seleziona gruppi", "chat.add-user-help": "Cerca qui gli utenti. Quando selezionato, l'utente sarà aggiunto alla chat.\nIl nuovo utente non sarà in grado di vedere i messaggi della chat scritti prima della sua partecipazione alla conversazione.\nSolo i proprietari della stanza () possono rimuovere gli utenti dalla stanza della chat.", "chat.confirm-chat-with-dnd-user": "Questo utente ha impostato il suo stato su Non Disturbare. Sei sicuro di voler iniziare una conversazione?", From ace3643470ee1a59503b682ff38c5854d208d705 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:20:12 -0400 Subject: [PATCH 149/300] fix(deps): update dependency esbuild to v0.18.16 (#11838) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 5b37f6774f..3414799063 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.15", + "esbuild": "0.18.16", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 878fe2170c363748a82dfe21d570b254962c5dfb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:20:29 -0400 Subject: [PATCH 150/300] fix(deps): update dependency sass to v1.64.1 (#11834) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 3414799063..77152aadaf 100644 --- a/install/package.json +++ b/install/package.json @@ -124,7 +124,7 @@ "rss": "1.2.2", "rtlcss": "4.1.0", "sanitize-html": "2.11.0", - "sass": "1.64.0", + "sass": "1.64.1", "semver": "7.5.4", "serve-favicon": "2.5.0", "sharp": "0.32.3", From 1cca1760a6e741d18a4d7e1e7a365a6e7159a79a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:20:36 -0400 Subject: [PATCH 151/300] chore(deps): update dependency sass-embedded to v1.64.1 (#11833) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 77152aadaf..ab08690f8b 100644 --- a/install/package.json +++ b/install/package.json @@ -171,7 +171,7 @@ "smtp-server": "3.12.0" }, "optionalDependencies": { - "sass-embedded": "1.64.0" + "sass-embedded": "1.64.1" }, "resolutions": { "*/jquery": "3.7.0" From ef9fd34594785c180f84eb842cd0902e93e4bf1b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:54:26 -0400 Subject: [PATCH 152/300] fix(deps): update dependency sharp to v0.32.4 (#11828) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ab08690f8b..f2d482c8af 100644 --- a/install/package.json +++ b/install/package.json @@ -127,7 +127,7 @@ "sass": "1.64.1", "semver": "7.5.4", "serve-favicon": "2.5.0", - "sharp": "0.32.3", + "sharp": "0.32.4", "sitemap": "7.1.1", "slideout": "1.0.1", "socket.io": "4.7.1", From 8d8930f8b3d9318083332b5aa165d346248cc99c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 20:54:36 -0400 Subject: [PATCH 153/300] fix(deps): update dependency postcss to v8.4.27 (#11827) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f2d482c8af..88fa0f1854 100644 --- a/install/package.json +++ b/install/package.json @@ -113,7 +113,7 @@ "passport-local": "1.0.0", "pg": "8.11.1", "pg-cursor": "2.10.1", - "postcss": "8.4.26", + "postcss": "8.4.27", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0", From 5129f87d7224a6a2a378bdbc78f393c99e83911d Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 24 Jul 2023 09:19:08 +0000 Subject: [PATCH 154/300] Latest translations and fallbacks --- public/language/bg/modules.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index b38f092017..95f0795d6a 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -36,12 +36,12 @@ "chat.public.groups-help": "За да създадете стая за разговор видима за всички потребители изберете групата с регистрирани потребители от списъка.", "chat.manage-room": "Управление на стаята за разговори", "chat.add-user": "Добавяне на потребител", - "chat.notification-settings": "Notification Settings", - "chat.default-notification-setting": "Default Notification Setting", - "chat.notification-setting-room-default": "Room Default", - "chat.notification-setting-none": "No notifications", - "chat.notification-setting-at-mention-only": "@mention only", - "chat.notification-setting-all-messages": "All messages", + "chat.notification-settings": "Настройки за известията", + "chat.default-notification-setting": "Стандартни настройки за известията", + "chat.notification-setting-room-default": "По подразбиране за стаята", + "chat.notification-setting-none": "Без известия", + "chat.notification-setting-at-mention-only": "Само @споменавания", + "chat.notification-setting-all-messages": "Всички съобщения", "chat.select-groups": "Избиране на групи", "chat.add-user-help": "Тук можете да потърсите потребители. Когато някой потребител бъде избран, той ще бъде добавен в разговора. Новият потребител няма да може да вижда съобщенията, написани преди включването му в разговора. Само собствениците на стаята () могат да премахват потребители от нея.", "chat.confirm-chat-with-dnd-user": "Този потребител е в състояние „не ме безпокойте“. Наистина ли искате да разговаряте с него?", From 0136e9248cc11aa155af35c5a053ff1e732992bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 24 Jul 2023 15:23:59 -0400 Subject: [PATCH 155/300] refactor: dont sleep if iteration is done on first one --- src/batch.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/batch.js b/src/batch.js index 4fb6c9a8e4..edc4038055 100644 --- a/src/batch.js +++ b/src/batch.js @@ -40,20 +40,20 @@ exports.processSortedSet = async function (setKey, process, options) { process = util.promisify(process); } const method = options.reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'; + let iteration = 1; while (true) { /* eslint-disable no-await-in-loop */ const ids = await db[`${method}${options.withScores ? 'WithScores' : ''}`](setKey, start, stop); if (!ids.length || options.doneIf(start, stop, ids)) { return; } - await process(ids); - - start += utils.isNumber(options.alwaysStartAt) ? options.alwaysStartAt : options.batch; - stop = start + options.batch - 1; - - if (options.interval) { + if (iteration > 1 && options.interval) { await sleep(options.interval); } + await process(ids); + iteration += 1; + start += utils.isNumber(options.alwaysStartAt) ? options.alwaysStartAt : options.batch; + stop = start + options.batch - 1; } }; @@ -72,21 +72,20 @@ exports.processArray = async function (array, process, options) { if (process && process.constructor && process.constructor.name !== 'AsyncFunction') { process = util.promisify(process); } - + let iteration = 1; while (true) { const currentBatch = array.slice(start, start + batch); if (!currentBatch.length) { return; } - + if (iteration > 1 && options.interval) { + await sleep(options.interval); + } await process(currentBatch); start += batch; - - if (options.interval) { - await sleep(options.interval); - } + iteration += 1; } }; From 17783440e4626d4a5d7423711d17c95190ade527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 25 Jul 2023 10:24:18 -0400 Subject: [PATCH 156/300] fix: #11841, use unique nid per user who flagged if multiple users flag a post/user, the notifications are merged using mergeId. if they use the same nid they overwrite each other --- src/flags.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flags.js b/src/flags.js index 904f1f71dc..7a6c16233f 100644 --- a/src/flags.js +++ b/src/flags.js @@ -844,7 +844,7 @@ Flags.notify = async function (flagObj, uid, notifySelf = false) { bodyLong: await plugins.hooks.fire('filter:parse.raw', String(flagObj.description || '')), pid: flagObj.targetId, path: `/flags/${flagObj.flagId}`, - nid: `flag:post:${flagObj.targetId}`, + nid: `flag:post:${flagObj.targetId}:${uid}`, from: uid, mergeId: `notifications:user_flagged_post_in|${flagObj.targetId}`, topicTitle: title, @@ -857,7 +857,7 @@ Flags.notify = async function (flagObj, uid, notifySelf = false) { bodyShort: `[[notifications:user_flagged_user, ${displayname}, ${targetDisplayname}]]`, bodyLong: await plugins.hooks.fire('filter:parse.raw', String(flagObj.description || '')), path: `/flags/${flagObj.flagId}`, - nid: `flag:user:${flagObj.targetId}`, + nid: `flag:user:${flagObj.targetId}:${uid}`, from: uid, mergeId: `notifications:user_flagged_user|${flagObj.targetId}`, }); From e41042eeea1bc8da2cf24379465c740dcfe786b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 25 Jul 2023 11:11:31 -0400 Subject: [PATCH 157/300] test: fix tests since nid format changed --- src/flags.js | 9 +++++++-- test/flags.js | 16 ++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/flags.js b/src/flags.js index 7a6c16233f..1c9dd3a5e1 100644 --- a/src/flags.js +++ b/src/flags.js @@ -680,6 +680,11 @@ Flags.update = async function (flagId, uid, changeset) { return allowed; }; + async function rescindNotifications(match) { + const nids = await db.getSortedSetScan({ key: 'notifications', match: `${match}*` }); + return notifications.rescind(nids); + } + // Retrieve existing flag data to compare for history-saving/reference purposes const tasks = []; for (const prop of Object.keys(changeset)) { @@ -692,10 +697,10 @@ Flags.update = async function (flagId, uid, changeset) { tasks.push(db.sortedSetAdd(`flags:byState:${changeset[prop]}`, now, flagId)); tasks.push(db.sortedSetRemove(`flags:byState:${current[prop]}`, flagId)); if (changeset[prop] === 'resolved' && meta.config['flags:actionOnResolve'] === 'rescind') { - tasks.push(notifications.rescind(`flag:${current.type}:${current.targetId}`)); + tasks.push(rescindNotifications(`flag:${current.type}:${current.targetId}`)); } if (changeset[prop] === 'rejected' && meta.config['flags:actionOnReject'] === 'rescind') { - tasks.push(notifications.rescind(`flag:${current.type}:${current.targetId}`)); + tasks.push(rescindNotifications(`flag:${current.type}:${current.targetId}`)); } } } else if (prop === 'assignee') { diff --git a/test/flags.js b/test/flags.js index 50f9c5543c..2912346519 100644 --- a/test/flags.js +++ b/test/flags.js @@ -514,40 +514,40 @@ describe('Flags', () => { it('should rescind notification if flag is resolved', async () => { let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'resolved', }); userNotifs = await User.notifications.getAll(adminUid); - assert(!userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(!userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); }); it('should rescind notification if flag is rejected', async () => { let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'rejected', }); userNotifs = await User.notifications.getAll(adminUid); - assert(!userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(!userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); }); it('should do nothing if flag is resolved but ACP action is not "rescind"', async () => { Meta.config['flags:actionOnResolve'] = ''; let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'resolved', }); userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); delete Meta.config['flags:actionOnResolve']; }); @@ -556,14 +556,14 @@ describe('Flags', () => { Meta.config['flags:actionOnReject'] = ''; let userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); await Flags.update(flagObj.flagId, adminUid, { state: 'rejected', }); userNotifs = await User.notifications.getAll(adminUid); - assert(userNotifs.includes(`flag:post:${result.postData.pid}`)); + assert(userNotifs.includes(`flag:post:${result.postData.pid}:${uid1}`)); delete Meta.config['flags:actionOnReject']; }); From 528e7e5a06a661d62f2d8f9fd736e1ac09fa9f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 25 Jul 2023 12:43:29 -0400 Subject: [PATCH 158/300] create obj with no prototype --- src/database/redis/sorted.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 6a38b5eced..07a30bab05 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -310,7 +310,7 @@ module.exports = function (module) { const returnData = []; let done = false; - const seen = {}; + const seen = Object.create(null); do { /* eslint-disable no-await-in-loop */ const res = await module.client.zscan(params.key, cursor, 'MATCH', params.match, 'COUNT', 5000); From e2fa8cf367f9c44e154520ef65878a073d0f17a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 25 Jul 2023 12:59:11 -0400 Subject: [PATCH 159/300] fix: #11837, use userslug for check --- public/src/client/register.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/register.js b/public/src/client/register.js index 3178ee8359..297bbe458a 100644 --- a/public/src/client/register.js +++ b/public/src/client/register.js @@ -124,7 +124,7 @@ define('forum/register', [ showError(username_notify, '[[error:invalid-username]]'); } else { Promise.allSettled([ - api.head(`/users/bySlug/${username}`, {}), + api.head(`/users/bySlug/${userslug}`, {}), api.head(`/groups/${username}`, {}), ]).then((results) => { if (results.every(obj => obj.status === 'rejected')) { From ac027387ec42fdf209374dacce60764f2273ea13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 25 Jul 2023 14:32:26 -0400 Subject: [PATCH 160/300] feat: #11842, ability to change reputation of users --- public/language/en-GB/admin/manage/users.json | 1 + public/src/admin/manage/users.js | 51 ++++++++++++++++++- src/socket.io/admin/user.js | 16 ++++++ src/views/admin/manage/users.tpl | 3 +- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/public/language/en-GB/admin/manage/users.json b/public/language/en-GB/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/en-GB/admin/manage/users.json +++ b/public/language/en-GB/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js index 1fb8e2701d..613389d9f9 100644 --- a/public/src/admin/manage/users.js +++ b/public/src/admin/manage/users.js @@ -1,8 +1,8 @@ 'use strict'; define('admin/manage/users', [ - 'translator', 'benchpress', 'autocomplete', 'api', 'slugify', 'bootbox', 'alerts', 'accounts/invite', -], function (translator, Benchpress, autocomplete, api, slugify, bootbox, alerts, AccountInvite) { + 'translator', 'benchpress', 'autocomplete', 'api', 'slugify', 'bootbox', 'alerts', 'accounts/invite', 'helpers', +], function (translator, Benchpress, autocomplete, api, slugify, bootbox, alerts, AccountInvite, helpers) { const Users = {}; Users.init = function () { @@ -141,6 +141,53 @@ define('admin/manage/users', [ }); }); + $('.set-reputation').on('click', function () { + const uids = getSelectedUids(); + if (!uids.length) { + alerts.error('[[error:no-users-selected]]'); + return false; + } + let currentValue = ''; + if (uids.length === 1) { + const user = ajaxify.data.users.find(u => u && u.uid === parseInt(uids[0], 10)); + if (user) { + currentValue = String(user.reputation); + } + } + const modal = bootbox.dialog({ + message: ``, + title: '[[admin/manage/users:set-reputation]]', + onEscape: true, + buttons: { + submit: { + label: '[[global:save]]', + callback: function () { + const newReputation = modal.find('#new-reputation').val(); + if (!utils.isNumber(newReputation)) { + alerts.error('[[error:invalid-data]]'); + return false; + } + socket.emit('admin.user.setReputation', { + value: newReputation, + uids: uids, + }).then(() => { + uids.forEach((uid) => { + $(`[component="user/reputation"][data-uid="${uid}"]`).text(helpers.formattedNumber(newReputation)); + const user = ajaxify.data.users.find(u => u && u.uid === parseInt(uid, 10)); + if (user) { + user.reputation = newReputation; + } + }); + }).catch(alerts.error); + }, + }, + }, + }); + modal.on('shown.bs.modal', () => { + modal.find('#new-reputation').selectRange(0, modal.find('#new-reputation').val().length); + }); + }); + $('.ban-user').on('click', function () { const uids = getSelectedUids(); if (!uids.length) { diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index afe47e4d82..6c5e0c5b28 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -8,6 +8,7 @@ const groups = require('../../groups'); const user = require('../../user'); const events = require('../../events'); const translator = require('../../translator'); +const utils = require('../../utils'); const sockets = require('..'); const User = module.exports; @@ -146,6 +147,21 @@ User.loadGroups = async function (socket, uids) { return { users: userData }; }; +User.setReputation = async function (socket, data) { + if (!data || !Array.isArray(data.uids) || !utils.isNumber(data.value)) { + throw new Error('[[error:invalid-data]]'); + } + + await Promise.all([ + db.setObjectBulk( + data.uids.map(uid => ([`user:${uid}`, { reputation: parseInt(data.value, 10) }])) + ), + db.sortedSetAddBulk( + data.uids.map(uid => (['users:reputation', data.value, uid])) + ), + ]); +}; + User.exportUsersCSV = async function (socket) { await events.log({ type: 'exportUsersCSV', diff --git a/src/views/admin/manage/users.tpl b/src/views/admin/manage/users.tpl index 7d417e9b5b..23127a9876 100644 --- a/src/views/admin/manage/users.tpl +++ b/src/views/admin/manage/users.tpl @@ -45,6 +45,7 @@
  • [[admin/manage/users:password-reset-email]]
  • [[admin/manage/users:force-password-reset]]
  • [[admin/manage/users:manage-groups]]
  • +
  • [[admin/manage/users:set-reputation]]
  • [[admin/manage/users:ban]]
  • [[admin/manage/users:temp-ban]]
  • @@ -152,7 +153,7 @@ {{{ end }}}
    - + From 9284b7e49a23a7abfa0e811cfcf74fed57dce27e Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 25 Jul 2023 18:33:20 +0000 Subject: [PATCH 161/300] chore(i18n): fallback strings for new resources: nodebb.admin-manage-users --- public/language/ar/admin/manage/users.json | 1 + public/language/bg/admin/manage/users.json | 1 + public/language/bn/admin/manage/users.json | 1 + public/language/cs/admin/manage/users.json | 1 + public/language/da/admin/manage/users.json | 1 + public/language/de/admin/manage/users.json | 1 + public/language/el/admin/manage/users.json | 1 + public/language/en-US/admin/manage/users.json | 1 + public/language/en-x-pirate/admin/manage/users.json | 1 + public/language/es/admin/manage/users.json | 1 + public/language/et/admin/manage/users.json | 1 + public/language/fa-IR/admin/manage/users.json | 1 + public/language/fi/admin/manage/users.json | 1 + public/language/fr/admin/manage/users.json | 1 + public/language/gl/admin/manage/users.json | 1 + public/language/he/admin/manage/users.json | 1 + public/language/hr/admin/manage/users.json | 1 + public/language/hu/admin/manage/users.json | 1 + public/language/hy/admin/manage/users.json | 1 + public/language/id/admin/manage/users.json | 1 + public/language/it/admin/manage/users.json | 1 + public/language/ja/admin/manage/users.json | 1 + public/language/ko/admin/manage/users.json | 1 + public/language/lt/admin/manage/users.json | 1 + public/language/lv/admin/manage/users.json | 1 + public/language/ms/admin/manage/users.json | 1 + public/language/nb/admin/manage/users.json | 1 + public/language/nl/admin/manage/users.json | 1 + public/language/pl/admin/manage/users.json | 1 + public/language/pt-BR/admin/manage/users.json | 1 + public/language/pt-PT/admin/manage/users.json | 1 + public/language/ro/admin/manage/users.json | 1 + public/language/ru/admin/manage/users.json | 1 + public/language/rw/admin/manage/users.json | 1 + public/language/sc/admin/manage/users.json | 1 + public/language/sk/admin/manage/users.json | 1 + public/language/sl/admin/manage/users.json | 1 + public/language/sq-AL/admin/manage/users.json | 1 + public/language/sr/admin/manage/users.json | 1 + public/language/sv/admin/manage/users.json | 1 + public/language/th/admin/manage/users.json | 1 + public/language/tr/admin/manage/users.json | 1 + public/language/uk/admin/manage/users.json | 1 + public/language/vi/admin/manage/users.json | 1 + public/language/zh-CN/admin/manage/users.json | 1 + public/language/zh-TW/admin/manage/users.json | 1 + 46 files changed, 46 insertions(+) diff --git a/public/language/ar/admin/manage/users.json b/public/language/ar/admin/manage/users.json index 33df2dcad5..58ec6cb0d4 100644 --- a/public/language/ar/admin/manage/users.json +++ b/public/language/ar/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/bg/admin/manage/users.json b/public/language/bg/admin/manage/users.json index bd7b12a61f..41be6ecf2b 100644 --- a/public/language/bg/admin/manage/users.json +++ b/public/language/bg/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Изтриване на потребителя/ите и съдържанието", "download-csv": "Сваляне във формат „CSV“", "manage-groups": "Управление на групите", + "set-reputation": "Set Reputation", "add-group": "Добавяне на група", "create": "Създаване на потребител", "invite": "Поканване по е-поща", diff --git a/public/language/bn/admin/manage/users.json b/public/language/bn/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/bn/admin/manage/users.json +++ b/public/language/bn/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/cs/admin/manage/users.json b/public/language/cs/admin/manage/users.json index 8b6cec0b2f..4fbf8835ea 100644 --- a/public/language/cs/admin/manage/users.json +++ b/public/language/cs/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Odstranit uživatele a obsah", "download-csv": "Stáhnout jako CSV", "manage-groups": "Spravovat skupiny", + "set-reputation": "Set Reputation", "add-group": "Přidat skupinu", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/da/admin/manage/users.json b/public/language/da/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/da/admin/manage/users.json +++ b/public/language/da/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/de/admin/manage/users.json b/public/language/de/admin/manage/users.json index e1c944af5d..5a990efdf7 100644 --- a/public/language/de/admin/manage/users.json +++ b/public/language/de/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Benutzer und Benutzer-Inhalte löschen", "download-csv": "CSV herunterladen", "manage-groups": "Gruppen verwalten", + "set-reputation": "Set Reputation", "add-group": "Gruppe hinzufügen", "create": "Benutzer erstellen", "invite": "Einladung per E-Mail", diff --git a/public/language/el/admin/manage/users.json b/public/language/el/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/el/admin/manage/users.json +++ b/public/language/el/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/en-US/admin/manage/users.json b/public/language/en-US/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/en-US/admin/manage/users.json +++ b/public/language/en-US/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/en-x-pirate/admin/manage/users.json b/public/language/en-x-pirate/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/en-x-pirate/admin/manage/users.json +++ b/public/language/en-x-pirate/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/es/admin/manage/users.json b/public/language/es/admin/manage/users.json index 05d0112765..8c138a43ed 100644 --- a/public/language/es/admin/manage/users.json +++ b/public/language/es/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Descargar CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/et/admin/manage/users.json b/public/language/et/admin/manage/users.json index 266a22b3a9..8e2d9da587 100644 --- a/public/language/et/admin/manage/users.json +++ b/public/language/et/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Lae alla CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/fa-IR/admin/manage/users.json b/public/language/fa-IR/admin/manage/users.json index e6b082afe0..e7ad339098 100644 --- a/public/language/fa-IR/admin/manage/users.json +++ b/public/language/fa-IR/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/fi/admin/manage/users.json b/public/language/fi/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/fi/admin/manage/users.json +++ b/public/language/fi/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/fr/admin/manage/users.json b/public/language/fr/admin/manage/users.json index 4cbded2a09..ef00aa09d7 100644 --- a/public/language/fr/admin/manage/users.json +++ b/public/language/fr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Supprimer le(s) compte(s) et le contenu", "download-csv": "Exporter en CSV", "manage-groups": "Gérer les groupes", + "set-reputation": "Set Reputation", "add-group": "Ajouter un groupe", "create": "Créer un utilisateur", "invite": "Inviter par mail", diff --git a/public/language/gl/admin/manage/users.json b/public/language/gl/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/gl/admin/manage/users.json +++ b/public/language/gl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/he/admin/manage/users.json b/public/language/he/admin/manage/users.json index 0e35cfa297..4c48be030d 100644 --- a/public/language/he/admin/manage/users.json +++ b/public/language/he/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "מחק משתמש(ים) ותוכן", "download-csv": "ייצא משתמשים כ-CSV", "manage-groups": "נהל קבוצות", + "set-reputation": "Set Reputation", "add-group": "הוסף קבוצה", "create": "צור משתמש", "invite": "הזמנה באמצעות דוא\"ל", diff --git a/public/language/hr/admin/manage/users.json b/public/language/hr/admin/manage/users.json index 89aa4b8c0e..93f1e680df 100644 --- a/public/language/hr/admin/manage/users.json +++ b/public/language/hr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Preuzmi CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/hu/admin/manage/users.json b/public/language/hu/admin/manage/users.json index 329d56b8d9..a36403740f 100644 --- a/public/language/hu/admin/manage/users.json +++ b/public/language/hu/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Felhasználó(k) és minden tartalmának törlése", "download-csv": "CSV letöltése", "manage-groups": "Csoportok kezelése", + "set-reputation": "Set Reputation", "add-group": "Csoport létrehozása", "create": "Felhasználó létrehozása", "invite": "Invite by Email", diff --git a/public/language/hy/admin/manage/users.json b/public/language/hy/admin/manage/users.json index 3c68fe3661..207214d588 100644 --- a/public/language/hy/admin/manage/users.json +++ b/public/language/hy/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Ջնջել օգտատերին(ներ) և բովանդակությունը", "download-csv": "Ներբեռնեք CSV", "manage-groups": "Կառավարել Խմբերը", + "set-reputation": "Set Reputation", "add-group": "Ավելացնել խումբ ", "create": "Ստեղծել օգտատեր", "invite": "հրավիրել էլ. փոստով", diff --git a/public/language/id/admin/manage/users.json b/public/language/id/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/id/admin/manage/users.json +++ b/public/language/id/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/it/admin/manage/users.json b/public/language/it/admin/manage/users.json index 334b721ef9..f46e2deba0 100644 --- a/public/language/it/admin/manage/users.json +++ b/public/language/it/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Elimina Utenti e Contenuto", "download-csv": "Scarica CSV", "manage-groups": "Gestisci Gruppi", + "set-reputation": "Set Reputation", "add-group": "Aggiungi Gruppo", "create": "Crea utente", "invite": "Invita via email", diff --git a/public/language/ja/admin/manage/users.json b/public/language/ja/admin/manage/users.json index e7aa34eed4..82381bab7d 100644 --- a/public/language/ja/admin/manage/users.json +++ b/public/language/ja/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "CSVでダウンロード", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ko/admin/manage/users.json b/public/language/ko/admin/manage/users.json index 494c4024f1..49e78ebe3e 100644 --- a/public/language/ko/admin/manage/users.json +++ b/public/language/ko/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "선택한 계정(들)컨텐츠 삭제", "download-csv": "CSV 다운로드", "manage-groups": "그룹 관리", + "set-reputation": "Set Reputation", "add-group": "그룹 추가", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/lt/admin/manage/users.json b/public/language/lt/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/lt/admin/manage/users.json +++ b/public/language/lt/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/lv/admin/manage/users.json b/public/language/lv/admin/manage/users.json index 75178297f2..37b84c7515 100644 --- a/public/language/lv/admin/manage/users.json +++ b/public/language/lv/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Lejupielādēt .csv", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ms/admin/manage/users.json b/public/language/ms/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/ms/admin/manage/users.json +++ b/public/language/ms/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/nb/admin/manage/users.json b/public/language/nb/admin/manage/users.json index d5475117e4..65f1fd05a5 100644 --- a/public/language/nb/admin/manage/users.json +++ b/public/language/nb/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/nl/admin/manage/users.json b/public/language/nl/admin/manage/users.json index e1376724be..747a92d3b2 100644 --- a/public/language/nl/admin/manage/users.json +++ b/public/language/nl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/pl/admin/manage/users.json b/public/language/pl/admin/manage/users.json index fee09fa707..7cf406d251 100644 --- a/public/language/pl/admin/manage/users.json +++ b/public/language/pl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Usuń Użytkownika(ów) i Treści", "download-csv": "Pobierz CSV", "manage-groups": "Zarządzaj grupami", + "set-reputation": "Set Reputation", "add-group": "Dodaj grupę", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/pt-BR/admin/manage/users.json b/public/language/pt-BR/admin/manage/users.json index 8b30173d39..86b3970b74 100644 --- a/public/language/pt-BR/admin/manage/users.json +++ b/public/language/pt-BR/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Excluir Usuário(s) e Conteúdo", "download-csv": "Baixar CSV", "manage-groups": "Gerenciar Grupos", + "set-reputation": "Set Reputation", "add-group": "Adicionar Grupo", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/pt-PT/admin/manage/users.json b/public/language/pt-PT/admin/manage/users.json index 7cd1500112..948989505a 100644 --- a/public/language/pt-PT/admin/manage/users.json +++ b/public/language/pt-PT/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Eliminar Utilizador(es) e os seus Conteúdos", "download-csv": "Transferir CSV", "manage-groups": "Gerir Grupos", + "set-reputation": "Set Reputation", "add-group": "Adicionar Grupo", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ro/admin/manage/users.json b/public/language/ro/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/ro/admin/manage/users.json +++ b/public/language/ro/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/ru/admin/manage/users.json b/public/language/ru/admin/manage/users.json index 17fc3343ab..ac9fa0e2da 100644 --- a/public/language/ru/admin/manage/users.json +++ b/public/language/ru/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Удалить пользователя(-ей) и данные", "download-csv": "Скачать CSV", "manage-groups": "Изменить членство в группах", + "set-reputation": "Set Reputation", "add-group": "Добавить группу", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/rw/admin/manage/users.json b/public/language/rw/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/rw/admin/manage/users.json +++ b/public/language/rw/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sc/admin/manage/users.json b/public/language/sc/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sc/admin/manage/users.json +++ b/public/language/sc/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sk/admin/manage/users.json b/public/language/sk/admin/manage/users.json index b1577d230e..d6493bbf0a 100644 --- a/public/language/sk/admin/manage/users.json +++ b/public/language/sk/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Stiahnuť ako CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sl/admin/manage/users.json b/public/language/sl/admin/manage/users.json index c20a749a9f..b7604c0d00 100644 --- a/public/language/sl/admin/manage/users.json +++ b/public/language/sl/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Izbrišiteuporabnika(e) in vsebino", "download-csv": "Prenesite CSV", "manage-groups": "Upravljaj skupine", + "set-reputation": "Set Reputation", "add-group": "Dodaj skupino", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sq-AL/admin/manage/users.json b/public/language/sq-AL/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sq-AL/admin/manage/users.json +++ b/public/language/sq-AL/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sr/admin/manage/users.json b/public/language/sr/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sr/admin/manage/users.json +++ b/public/language/sr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/sv/admin/manage/users.json b/public/language/sv/admin/manage/users.json index 96b024fec5..1fef96f56d 100644 --- a/public/language/sv/admin/manage/users.json +++ b/public/language/sv/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Download CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/th/admin/manage/users.json b/public/language/th/admin/manage/users.json index eaf40ba943..a3cfe00931 100644 --- a/public/language/th/admin/manage/users.json +++ b/public/language/th/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "ดาวน์โหลด CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/tr/admin/manage/users.json b/public/language/tr/admin/manage/users.json index 150cdeb098..4cc0417d38 100644 --- a/public/language/tr/admin/manage/users.json +++ b/public/language/tr/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Kullanıcıyı/ları ve İçeriği Sil", "download-csv": "CSV İndir", "manage-groups": "Grupları Düzenle", + "set-reputation": "Set Reputation", "add-group": "Grup ekle", "create": "Kullanıcı Oluştur", "invite": "E-posta ile Davet Et", diff --git a/public/language/uk/admin/manage/users.json b/public/language/uk/admin/manage/users.json index 010a781379..2b7df34d4f 100644 --- a/public/language/uk/admin/manage/users.json +++ b/public/language/uk/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "Скачати CSV", "manage-groups": "Manage Groups", + "set-reputation": "Set Reputation", "add-group": "Add Group", "create": "Create User", "invite": "Invite by Email", diff --git a/public/language/vi/admin/manage/users.json b/public/language/vi/admin/manage/users.json index ad02785a9e..a318c8b711 100644 --- a/public/language/vi/admin/manage/users.json +++ b/public/language/vi/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Xóa Người DùngNội Dung", "download-csv": "Tải về CSV", "manage-groups": "Quản Lý Nhóm", + "set-reputation": "Set Reputation", "add-group": "Thêm Nhóm", "create": "Tạo Người Dùng", "invite": "Mời qua Email", diff --git a/public/language/zh-CN/admin/manage/users.json b/public/language/zh-CN/admin/manage/users.json index e53a2b051f..94e8dd4cd6 100644 --- a/public/language/zh-CN/admin/manage/users.json +++ b/public/language/zh-CN/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "删除用户和内容", "download-csv": "下载CSV", "manage-groups": "管理用户组", + "set-reputation": "Set Reputation", "add-group": "添加至群组", "create": "创建用户", "invite": "通过邮件邀请", diff --git a/public/language/zh-TW/admin/manage/users.json b/public/language/zh-TW/admin/manage/users.json index 15d1c53559..403dd12ccf 100644 --- a/public/language/zh-TW/admin/manage/users.json +++ b/public/language/zh-TW/admin/manage/users.json @@ -18,6 +18,7 @@ "purge": "Delete User(s) and Content", "download-csv": "下載CSV", "manage-groups": "管理群組", + "set-reputation": "Set Reputation", "add-group": "新增至群組", "create": "Create User", "invite": "Invite by Email", From 45db294cbfb0dfdc163b4a06ae71e4d30034af04 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 26 Jul 2023 09:19:34 +0000 Subject: [PATCH 162/300] Latest translations and fallbacks --- public/language/bg/admin/manage/users.json | 2 +- public/language/he/admin/manage/users.json | 2 +- public/language/he/modules.json | 12 ++++++------ public/language/he/topic.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/public/language/bg/admin/manage/users.json b/public/language/bg/admin/manage/users.json index 41be6ecf2b..03bc24b017 100644 --- a/public/language/bg/admin/manage/users.json +++ b/public/language/bg/admin/manage/users.json @@ -18,7 +18,7 @@ "purge": "Изтриване на потребителя/ите и съдържанието", "download-csv": "Сваляне във формат „CSV“", "manage-groups": "Управление на групите", - "set-reputation": "Set Reputation", + "set-reputation": "Задаване на репутация", "add-group": "Добавяне на група", "create": "Създаване на потребител", "invite": "Поканване по е-поща", diff --git a/public/language/he/admin/manage/users.json b/public/language/he/admin/manage/users.json index 4c48be030d..847a9b871b 100644 --- a/public/language/he/admin/manage/users.json +++ b/public/language/he/admin/manage/users.json @@ -18,7 +18,7 @@ "purge": "מחק משתמש(ים) ותוכן", "download-csv": "ייצא משתמשים כ-CSV", "manage-groups": "נהל קבוצות", - "set-reputation": "Set Reputation", + "set-reputation": "הגדר מוניטין", "add-group": "הוסף קבוצה", "create": "צור משתמש", "invite": "הזמנה באמצעות דוא\"ל", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index f3944b2c87..17ff6ace10 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -36,12 +36,12 @@ "chat.public.groups-help": "כדי ליצור חדר צ'אט הגלוי לכל המשתמשים בחר \"משתמשים רשומים\" מרשימת הקבוצות.", "chat.manage-room": "ניהול חדר צ'אט", "chat.add-user": "הוסף משתמש", - "chat.notification-settings": "Notification Settings", - "chat.default-notification-setting": "Default Notification Setting", - "chat.notification-setting-room-default": "Room Default", - "chat.notification-setting-none": "No notifications", - "chat.notification-setting-at-mention-only": "@mention only", - "chat.notification-setting-all-messages": "All messages", + "chat.notification-settings": "הגדרות התראות", + "chat.default-notification-setting": "הגדרת ברירת מחדל להתראות", + "chat.notification-setting-room-default": "ברירת המחדל של החדר", + "chat.notification-setting-none": "ללא התראות", + "chat.notification-setting-at-mention-only": "@אזכור בלבד", + "chat.notification-setting-all-messages": "כל ההודעות", "chat.select-groups": "בחר קבוצות", "chat.add-user-help": "חפשו משתמשים כאן. כאשר משתמש נבחר, הוא יצורף לצ'אט. המשתמש החדש לא יוכל לראות הודעות שנכתבו לפני הצטרפותו. רק מנהלי החדר () יכולים להסיר משתמשים מהצ'אט.", "chat.confirm-chat-with-dnd-user": "משתמש זה שינה את הסטטוס שלו ל'לא להפריע'. אתם עדיין מעוניין לשוחח איתו?", diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 940d924f8e..9efe2423e4 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "כתב ", "wrote-on": "כתב ב", "replied-to-user-ago": "השיב ל%3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "השיב ל%3 ב ", "user-locked-topic-ago": "%1 נעל נושא זה %2", "user-locked-topic-on": "%1 נעל נושא זה ב-%2", "user-unlocked-topic-ago": "%1 ביטל את נעילת נושא זה %2", From 907c5fa6877160a99c07aa42cf172cbee85ead32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 26 Jul 2023 09:42:10 -0400 Subject: [PATCH 163/300] feat: closes #11843, refresh search after changing filters --- public/src/client/search.js | 14 ++++++++++---- public/src/modules/search.js | 3 +-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/public/src/client/search.js b/public/src/client/search.js index f9d7bdbc6d..4ca01b80f9 100644 --- a/public/src/client/search.js +++ b/public/src/client/search.js @@ -15,7 +15,7 @@ define('forum/search', [ let selectedUsers = []; let selectedTags = []; let selectedCids = []; - + let searchFilters = {}; Search.init = function () { const searchIn = $('#search-in'); searchIn.on('change', function () { @@ -30,9 +30,7 @@ define('forum/search', [ $('#advanced-search form').off('submit').on('submit', function (e) { e.preventDefault(); - searchModule.query(getSearchDataFromDOM(), function () { - $('#search-input').val(''); - }); + searchModule.query(getSearchDataFromDOM()); return false; }); @@ -53,12 +51,20 @@ define('forum/search', [ if (updateFns[$(this).attr('data-filter-name')]) { updateFns[$(this).attr('data-filter-name')](); } + + const searchFiltersNew = getSearchDataFromDOM(); + if (JSON.stringify(searchFilters) !== JSON.stringify(searchFiltersNew)) { + searchFilters = searchFiltersNew; + searchModule.query(searchFilters); + } }); fillOutForm(); updateTimeFilter(); updateReplyCountFilter(); updateSortFilter(); + + searchFilters = getSearchDataFromDOM(); }; function updateTagFilter() { diff --git a/public/src/modules/search.js b/public/src/modules/search.js index ebcc12dab0..566be43ab2 100644 --- a/public/src/modules/search.js +++ b/public/src/modules/search.js @@ -243,8 +243,7 @@ define('search', [ Search.query = function (data, callback) { callback = callback || function () {}; - ajaxify.go('search?' + createQueryString(data)); - callback(); + ajaxify.go('search?' + createQueryString(data), callback); }; Search.api = function (data, callback) { From f359a76702165169b536b733feca1bd268cd6cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 26 Jul 2023 09:58:16 -0400 Subject: [PATCH 164/300] feat: #11814, dont check content len for admins --- public/src/modules/uploadHelpers.js | 2 +- src/controllers/uploads.js | 4 ++-- src/topics/create.js | 34 +++++++++++++++++------------ 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/public/src/modules/uploadHelpers.js b/public/src/modules/uploadHelpers.js index e532054288..ce6cb08476 100644 --- a/public/src/modules/uploadHelpers.js +++ b/public/src/modules/uploadHelpers.js @@ -160,7 +160,7 @@ define('uploadHelpers', ['alerts'], function (alerts) { if ((isImage && !app.user.privileges['upload:post:image']) || (!isImage && !app.user.privileges['upload:post:file'])) { return alerts.error('[[error:no-privileges]]'); } - if (files[i].size > parseInt(config.maximumFileSize, 10) * 1024) { + if (!app.user.isAdmin && files[i].size > parseInt(config.maximumFileSize, 10) * 1024) { options.uploadForm[0].reset(); return alerts.error('[[error:file-too-big, ' + config.maximumFileSize + ']]'); } diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 46871ca076..d5105d25f1 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -163,8 +163,8 @@ uploadsController.uploadFile = async function (uid, uploadedFile) { if (!uploadedFile) { throw new Error('[[error:invalid-file]]'); } - - if (uploadedFile.size > meta.config.maximumFileSize * 1024) { + const isAdmin = await user.isAdministrator(uid); + if (!isAdmin && uploadedFile.size > meta.config.maximumFileSize * 1024) { throw new Error(`[[error:file-too-big, ${meta.config.maximumFileSize}]]`); } diff --git a/src/topics/create.js b/src/topics/create.js index 5d631cce27..f962b21ddf 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -80,23 +80,26 @@ module.exports = function (Topics) { data = await plugins.hooks.fire('filter:topic.post', data); const { uid } = data; - data.title = String(data.title).trim(); - data.tags = data.tags || []; - data.content = String(data.content || '').trimEnd(); - - Topics.checkTitle(data.title); - await Topics.validateTags(data.tags, data.cid, uid); - data.tags = await Topics.filterTags(data.tags, data.cid); - if (!data.fromQueue) { - Topics.checkContent(data.content); - } - - const [categoryExists, canCreate, canTag] = await Promise.all([ + const [categoryExists, canCreate, canTag, isAdmin] = await Promise.all([ categories.exists(data.cid), privileges.categories.can('topics:create', data.cid, uid), privileges.categories.can('topics:tag', data.cid, uid), + privileges.users.isAdministrator(uid), ]); + data.title = String(data.title).trim(); + data.tags = data.tags || []; + data.content = String(data.content || '').trimEnd(); + if (!isAdmin) { + Topics.checkTitle(data.title); + } + + await Topics.validateTags(data.tags, data.cid, uid); + data.tags = await Topics.filterTags(data.tags, data.cid); + if (!data.fromQueue && !isAdmin) { + Topics.checkContent(data.content); + } + if (!categoryExists) { throw new Error('[[error:no-category]]'); } @@ -159,7 +162,10 @@ module.exports = function (Topics) { const { tid } = data; const { uid } = data; - const topicData = await Topics.getTopicData(tid); + const [topicData, isAdmin] = await Promise.all([ + Topics.getTopicData(tid), + privileges.users.isAdministrator(uid), + ]); await canReply(data, topicData); @@ -168,7 +174,7 @@ module.exports = function (Topics) { await guestHandleValid(data); data.content = String(data.content || '').trimEnd(); - if (!data.fromQueue) { + if (!data.fromQueue && !isAdmin) { await user.isReadyToPost(uid, data.cid); Topics.checkContent(data.content); } From b1db67ce8717e44567119d19567baa80aa4b399a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 09:58:38 -0400 Subject: [PATCH 165/300] fix(deps): update dependency cron to v2.4.0 (#11839) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 88fa0f1854..a78309294a 100644 --- a/install/package.json +++ b/install/package.json @@ -57,7 +57,7 @@ "connect-pg-simple": "9.0.0", "connect-redis": "7.1.0", "cookie-parser": "1.4.6", - "cron": "2.3.1", + "cron": "2.4.0", "cropperjs": "1.5.13", "csrf-sync": "4.0.1", "daemon": "1.1.0", From ba37983686b76149f9268e4bb22b0ccbbdd28f7c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 09:58:47 -0400 Subject: [PATCH 166/300] fix(deps): update dependency esbuild to v0.18.17 (#11844) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a78309294a..a8e703bf05 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.16", + "esbuild": "0.18.17", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From d615273d90b4d2e2df118d7d6c38953256a9ab3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 26 Jul 2023 10:07:38 -0400 Subject: [PATCH 167/300] test: fix tests to use regular uid --- test/topics.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/topics.js b/test/topics.js index 0febc38699..07af567b25 100644 --- a/test/topics.js +++ b/test/topics.js @@ -106,14 +106,14 @@ describe('Topic\'s', () => { }); it('should fail to create new topic with empty title', (done) => { - topics.post({ uid: topic.userId, title: '', content: topic.content, cid: topic.categoryId }, (err) => { + topics.post({ uid: fooUid, title: '', content: topic.content, cid: topic.categoryId }, (err) => { assert.ok(err); done(); }); }); it('should fail to create new topic with empty content', (done) => { - topics.post({ uid: topic.userId, title: topic.title, content: '', cid: topic.categoryId }, (err) => { + topics.post({ uid: fooUid, title: topic.title, content: '', cid: topic.categoryId }, (err) => { assert.ok(err); done(); }); @@ -304,7 +304,7 @@ describe('Topic\'s', () => { }); it('should fail to create new reply with empty content', (done) => { - topics.reply({ uid: topic.userId, content: '', tid: newTopic.tid }, (err) => { + topics.reply({ uid: fooUid, content: '', tid: newTopic.tid }, (err) => { assert.strictEqual(err.message, '[[error:content-too-short, 8]]'); done(); }); From 7bfe327cc6f25ae4b02b43fec53c297156f8a149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 26 Jul 2023 10:14:06 -0400 Subject: [PATCH 168/300] chore: up composer --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a8e703bf05..b134def2fe 100644 --- a/install/package.json +++ b/install/package.json @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.1.3", - "nodebb-plugin-composer-default": "10.2.5", + "nodebb-plugin-composer-default": "10.2.6", "nodebb-plugin-dbsearch": "6.1.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", From a16fcf766fbf40a8833be87ab60b44b10c156d46 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Thu, 27 Jul 2023 09:19:09 +0000 Subject: [PATCH 169/300] Latest translations and fallbacks --- public/language/it/admin/manage/users.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/language/it/admin/manage/users.json b/public/language/it/admin/manage/users.json index f46e2deba0..f06ec1f32c 100644 --- a/public/language/it/admin/manage/users.json +++ b/public/language/it/admin/manage/users.json @@ -18,7 +18,7 @@ "purge": "Elimina Utenti e Contenuto", "download-csv": "Scarica CSV", "manage-groups": "Gestisci Gruppi", - "set-reputation": "Set Reputation", + "set-reputation": "Imposta reputazione", "add-group": "Aggiungi Gruppo", "create": "Crea utente", "invite": "Invita via email", From 5a8b4125c7c81edc29821241af13c2494c582ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 10:53:15 -0400 Subject: [PATCH 170/300] fix: #11847, typo in markNotification --- public/src/client/notifications.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/notifications.js b/public/src/client/notifications.js index af509a1edd..d42b23d51e 100644 --- a/public/src/client/notifications.js +++ b/public/src/client/notifications.js @@ -8,7 +8,7 @@ define('forum/notifications', ['components', 'notifications'], function (compone const listEl = $('.notifications-list'); listEl.on('click', '[component="notifications/item/link"]', function () { const nid = $(this).parents('[data-nid]').attr('data-nid'); - Notifications.markNotification(nid, true); + notifications.markNotification(nid, true); }); notifications.handleUnreadButton(listEl); From 6faec9376e2d0fbb5fb05cfccc038782bb0b0214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 10:54:16 -0400 Subject: [PATCH 171/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b134def2fe..b0c7f40171 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.15", + "nodebb-theme-harmony": "1.1.16", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.4", "nodebb-theme-persona": "13.2.8", From 9ac52dbf5f7f3fe6f2e25de6060080648cb74d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 10:59:13 -0400 Subject: [PATCH 172/300] change from/to --- src/events.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events.js b/src/events.js index 09c9062ae8..53f1e160ac 100644 --- a/src/events.js +++ b/src/events.js @@ -101,10 +101,10 @@ events.log = async function (data) { events.getEvents = async function (filter, start, stop, from, to) { // from/to optional if (from === undefined) { - from = 0; + from = '-inf'; } if (to === undefined) { - to = Date.now(); + to = '+inf'; } const eids = await db.getSortedSetRevRangeByScore(`events:time${filter ? `:${filter}` : ''}`, start, stop - start + 1, to, from); From 78aa904e97daf14b28658b9d35102820197ab4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 14:26:31 -0400 Subject: [PATCH 173/300] gimme mid --- src/messaging/data.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/messaging/data.js b/src/messaging/data.js index b65f8737fb..38c2e7761a 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -143,6 +143,9 @@ async function modifyMessage(message, fields, mid) { if (message.hasOwnProperty('edited')) { message.editedISO = utils.toISOString(message.edited); } + if (!fields.length || fields.includes('mid')) { + message.mid = parseInt(mid, 10); + } } const payload = await plugins.hooks.fire('filter:messaging.getFields', { From e68f7c20647fcf0b74fd2349b8f53067bc0fcb4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 16:51:07 -0400 Subject: [PATCH 174/300] add missing hooks --- public/openapi/components/schemas/Chats.yaml | 2 ++ public/openapi/read/user/userslug/chats/roomid.yaml | 2 ++ src/messaging/create.js | 4 +--- src/messaging/delete.js | 5 ++++- src/messaging/edit.js | 1 + 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 3af68f754a..fe2ff9f73c 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -46,6 +46,8 @@ MessageObject: type: string editedISO: type: string + mid: + type: number messageId: type: number fromUser: diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index d3eaee8e67..025499b753 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -69,6 +69,8 @@ get: description: An ISO 8601 formatted date string (complementing `timestamp`) editedISO: type: string + mid: + type: number messageId: type: number fromUser: diff --git a/src/messaging/create.js b/src/messaging/create.js index ed6b0b6a33..fe0fbb7de0 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -86,9 +86,7 @@ module.exports = function (Messaging) { } messages[0].newSet = isNewSet; - messages[0].mid = mid; // TODO: messageId is a duplicate - messages[0].roomId = roomId; - plugins.hooks.fire('action:messaging.save', { message: messages[0], data: data }); + plugins.hooks.fire('action:messaging.save', { message: message, data: data }); return messages[0]; }; diff --git a/src/messaging/delete.js b/src/messaging/delete.js index 0363481e42..aca7570c34 100644 --- a/src/messaging/delete.js +++ b/src/messaging/delete.js @@ -1,6 +1,7 @@ 'use strict'; const sockets = require('../socket.io'); +const plugins = require('../plugins'); module.exports = function (Messaging) { Messaging.deleteMessage = async (mid, uid) => await doDeleteRestore(mid, 1, uid); @@ -8,7 +9,7 @@ module.exports = function (Messaging) { async function doDeleteRestore(mid, state, uid) { const field = state ? 'deleted' : 'restored'; - const { deleted, roomId } = await Messaging.getMessageFields(mid, ['deleted', 'roomId']); + const { content, deleted, roomId } = await Messaging.getMessageFields(mid, ['deleted', 'roomId', 'content']); if (deleted === state) { throw new Error(`[[error:chat-${field}-already]]`); } @@ -17,9 +18,11 @@ module.exports = function (Messaging) { const ioRoom = sockets.in(`chat_room_${roomId}`); if (state === 1 && ioRoom) { ioRoom.emit('event:chats.delete', mid); + plugins.hooks.fire('action:messaging.delete', { message: { mid, content, deleted: 1, roomId } }); } else if (state === 0 && ioRoom) { const messages = await Messaging.getMessagesData([mid], uid, roomId, true); ioRoom.emit('event:chats.restore', messages[0]); + plugins.hooks.fire('action:messaging.restore', { message: { ...messages[0], content } }); } } }; diff --git a/src/messaging/edit.js b/src/messaging/edit.js index d54b5dc587..bd930f9ae9 100644 --- a/src/messaging/edit.js +++ b/src/messaging/edit.js @@ -31,6 +31,7 @@ module.exports = function (Messaging) { sockets.in(`chat_room_${roomId}`).emit('event:chats.edit', { messages: messages, }); + plugins.hooks.fire('action:messaging.edit', { message: messages[0] }); }; const canEditDelete = async (messageId, uid, type) => { From d652da61d83277c9479275367ec0a78917a2afd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 17:32:35 -0400 Subject: [PATCH 175/300] add upgrade script to set mid on msg objects and create messages:mid for easy msg retrieval --- src/messaging/create.js | 2 ++ src/messaging/data.js | 7 +--- src/messaging/delete.js | 15 +++++---- src/messaging/edit.js | 4 ++- src/upgrades/3.3.0/chat_message_mids.js | 45 +++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 src/upgrades/3.3.0/chat_message_mids.js diff --git a/src/messaging/create.js b/src/messaging/create.js index fe0fbb7de0..87ec24729f 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -44,6 +44,7 @@ module.exports = function (Messaging) { const mid = await db.incrObjectField('global', 'nextMid'); const timestamp = data.timestamp || Date.now(); let message = { + mid: mid, content: String(data.content), timestamp: timestamp, fromuid: uid, @@ -65,6 +66,7 @@ module.exports = function (Messaging) { const tasks = [ Messaging.addMessageToRoom(roomId, mid, timestamp), Messaging.markRead(uid, roomId), + db.sortedSetAdd('messages:mid', timestamp, mid), ]; if (roomData.public) { tasks.push( diff --git a/src/messaging/data.js b/src/messaging/data.js index 38c2e7761a..3542de799f 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -7,7 +7,7 @@ const user = require('../user'); const utils = require('../utils'); const plugins = require('../plugins'); -const intFields = ['timestamp', 'edited', 'fromuid', 'roomId', 'deleted', 'system']; +const intFields = ['mid', 'timestamp', 'edited', 'fromuid', 'roomId', 'deleted', 'system']; module.exports = function (Messaging) { Messaging.newMessageCutoff = 1000 * 60 * 3; @@ -71,8 +71,6 @@ module.exports = function (Messaging) { message.newSet = false; message.roomId = String(message.roomId || roomId); - message.deleted = !!message.deleted; - message.system = !!message.system; }); messages = await Promise.all(messages.map(async (message) => { @@ -143,9 +141,6 @@ async function modifyMessage(message, fields, mid) { if (message.hasOwnProperty('edited')) { message.editedISO = utils.toISOString(message.edited); } - if (!fields.length || fields.includes('mid')) { - message.mid = parseInt(mid, 10); - } } const payload = await plugins.hooks.fire('filter:messaging.getFields', { diff --git a/src/messaging/delete.js b/src/messaging/delete.js index aca7570c34..1c16ceddc1 100644 --- a/src/messaging/delete.js +++ b/src/messaging/delete.js @@ -9,20 +9,23 @@ module.exports = function (Messaging) { async function doDeleteRestore(mid, state, uid) { const field = state ? 'deleted' : 'restored'; - const { content, deleted, roomId } = await Messaging.getMessageFields(mid, ['deleted', 'roomId', 'content']); - if (deleted === state) { + const msgData = await Messaging.getMessageFields(mid, [ + 'mid', 'fromuid', 'deleted', 'roomId', 'content', 'system', + ]); + if (msgData.deleted === state) { throw new Error(`[[error:chat-${field}-already]]`); } await Messaging.setMessageField(mid, 'deleted', state); - const ioRoom = sockets.in(`chat_room_${roomId}`); + msgData.deleted = state; + const ioRoom = sockets.in(`chat_room_${msgData.roomId}`); if (state === 1 && ioRoom) { ioRoom.emit('event:chats.delete', mid); - plugins.hooks.fire('action:messaging.delete', { message: { mid, content, deleted: 1, roomId } }); + plugins.hooks.fire('action:messaging.delete', { message: msgData }); } else if (state === 0 && ioRoom) { - const messages = await Messaging.getMessagesData([mid], uid, roomId, true); + const messages = await Messaging.getMessagesData([mid], uid, msgData.roomId, true); ioRoom.emit('event:chats.restore', messages[0]); - plugins.hooks.fire('action:messaging.restore', { message: { ...messages[0], content } }); + plugins.hooks.fire('action:messaging.restore', { message: msgData }); } } }; diff --git a/src/messaging/edit.js b/src/messaging/edit.js index bd930f9ae9..438d43685a 100644 --- a/src/messaging/edit.js +++ b/src/messaging/edit.js @@ -31,7 +31,9 @@ module.exports = function (Messaging) { sockets.in(`chat_room_${roomId}`).emit('event:chats.edit', { messages: messages, }); - plugins.hooks.fire('action:messaging.edit', { message: messages[0] }); + plugins.hooks.fire('action:messaging.edit', { + message: { ...messages[0], content: payload.content }, + }); }; const canEditDelete = async (messageId, uid, type) => { diff --git a/src/upgrades/3.3.0/chat_message_mids.js b/src/upgrades/3.3.0/chat_message_mids.js new file mode 100644 index 0000000000..ebb79324fa --- /dev/null +++ b/src/upgrades/3.3.0/chat_message_mids.js @@ -0,0 +1,45 @@ +'use strict'; + + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Set mid on message objects and create messages:mid', + timestamp: Date.UTC(2023, 6, 27), + method: async function () { + const { progress } = this; + + progress.total = await db.sortedSetCard(`chat:rooms`); + await batch.processSortedSet(`chat:rooms`, async (roomIds) => { + progress.incr(roomIds.length); + await Promise.all(roomIds.map(async (roomId) => { + await batch.processSortedSet(`chat:room:${roomId}:mids`, async (mids) => { + let messageData = await db.getObjects(mids.map(mid => `message:${mid}`)); + messageData.forEach((m, idx) => { + if (m) { + m.mid = parseInt(mids[idx], 10); + } + }); + messageData = messageData.filter(Boolean); + + const bulkSet = messageData.map( + msg => [`message:${msg.mid}`, { mid: msg.mid }] + ); + + await db.setObjectBulk(bulkSet); + await db.sortedSetAdd( + 'messages:mid', + messageData.map(msg => msg.timestamp), + messageData.map(msg => msg.mid) + ); + }, { + batch: 500, + }); + })); + }, { + batch: 500, + }); + }, +}; From 48a66b74f11dc0526545b18bef65436d75d978e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 27 Jul 2023 17:39:14 -0400 Subject: [PATCH 176/300] fix tests --- public/openapi/components/schemas/Chats.yaml | 4 ++-- public/openapi/read/user/userslug/chats/roomid.yaml | 4 ++-- src/messaging/create.js | 1 + src/upgrades/3.3.0/chat_message_mids.js | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index fe2ff9f73c..36404313ff 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -37,9 +37,9 @@ MessageObject: roomId: type: number deleted: - type: boolean + type: number system: - type: boolean + type: number edited: type: number timestampISO: diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index 025499b753..cb350aa2e0 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -59,9 +59,9 @@ get: roomId: type: string deleted: - type: boolean + type: number system: - type: boolean + type: number edited: type: number timestampISO: diff --git a/src/messaging/create.js b/src/messaging/create.js index 87ec24729f..872f22613f 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -67,6 +67,7 @@ module.exports = function (Messaging) { Messaging.addMessageToRoom(roomId, mid, timestamp), Messaging.markRead(uid, roomId), db.sortedSetAdd('messages:mid', timestamp, mid), + db.incrObjectField('global', 'messageCount'), ]; if (roomData.public) { tasks.push( diff --git a/src/upgrades/3.3.0/chat_message_mids.js b/src/upgrades/3.3.0/chat_message_mids.js index ebb79324fa..d7f349ae98 100644 --- a/src/upgrades/3.3.0/chat_message_mids.js +++ b/src/upgrades/3.3.0/chat_message_mids.js @@ -4,7 +4,6 @@ const db = require('../../database'); const batch = require('../../batch'); - module.exports = { name: 'Set mid on message objects and create messages:mid', timestamp: Date.UTC(2023, 6, 27), @@ -41,5 +40,7 @@ module.exports = { }, { batch: 500, }); + const count = await db.sortedSetCard(`messages:mid`); + await db.setObjectField('global', 'messageCount', count); }, }; From 50fd7930ed570604faa455df63811a0e9cd00f41 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Fri, 28 Jul 2023 09:21:22 +0000 Subject: [PATCH 177/300] Latest translations and fallbacks --- public/language/sr/modules.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index f992ff3143..8c4f816535 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -36,12 +36,12 @@ "chat.public.groups-help": "За креирање собе за ћаскање која је видљива свим корисницима, изаберите регистроване кориснике са листе група.", "chat.manage-room": "Управљај собом за ћаскање", "chat.add-user": "Додај корисника", - "chat.notification-settings": "Notification Settings", - "chat.default-notification-setting": "Default Notification Setting", - "chat.notification-setting-room-default": "Room Default", - "chat.notification-setting-none": "No notifications", - "chat.notification-setting-at-mention-only": "@mention only", - "chat.notification-setting-all-messages": "All messages", + "chat.notification-settings": "Подешавања обавештења", + "chat.default-notification-setting": "Подразумевано подешавање обавештења", + "chat.notification-setting-room-default": "Подразумевана соба", + "chat.notification-setting-none": "Без обавештења", + "chat.notification-setting-at-mention-only": "@помињање само", + "chat.notification-setting-all-messages": "Све поруке", "chat.select-groups": "Изаберите групе", "chat.add-user-help": "Потражите кориснике овде. Када буде изабран, корисник ће бити додан у ћаскање. Нови корисник неће бити у могућности да види поруке написане пре него што је додан у преписку. Само власници соба () могу уклонити кориснике из соба за ћаскање.", "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на „Не узнемиравај”. Да ли и даље желите да ћаскате са њим?", @@ -60,7 +60,7 @@ "chat.kick": "Избаци", "chat.show-ip": "Прикажи IP", "chat.owner": "Власник собе", - "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.grant-rescind-ownership": "Додели/поништи власништво", "chat.system.user-join": "%1 се придружио соби", "chat.system.user-leave": "%1 је напустио собу", "chat.system.room-rename": "%2 је преименовао собу: %1", From 11bfeaf1300b8b66b394e43164bcb18add88c72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 28 Jul 2023 10:56:25 -0400 Subject: [PATCH 178/300] feat: #11850, chat msg search --- install/package.json | 8 +- public/src/client/chats.js | 31 +++---- public/src/client/chats/create.js | 6 +- public/src/client/chats/message-search.js | 82 +++++++++++++++++++ public/src/client/chats/messages.js | 25 +++--- .../chats/{search.js => user-search.js} | 8 +- src/socket.io/modules.js | 38 +++++++++ test/messaging.js | 10 +-- 8 files changed, 165 insertions(+), 43 deletions(-) create mode 100644 public/src/client/chats/message-search.js rename public/src/client/chats/{search.js => user-search.js} (94%) diff --git a/install/package.json b/install/package.json index b0c7f40171..6aac8d3c23 100644 --- a/install/package.json +++ b/install/package.json @@ -93,7 +93,7 @@ "nconf": "0.12.0", "nodebb-plugin-2factor": "7.1.3", "nodebb-plugin-composer-default": "10.2.6", - "nodebb-plugin-dbsearch": "6.1.0", + "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.16", + "nodebb-theme-harmony": "1.1.17", "nodebb-theme-lavender": "7.1.3", - "nodebb-theme-peace": "2.1.4", - "nodebb-theme-persona": "13.2.8", + "nodebb-theme-peace": "2.1.5", + "nodebb-theme-persona": "13.2.9", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", diff --git a/public/src/client/chats.js b/public/src/client/chats.js index b329310bd8..7dab41cd22 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -9,6 +9,7 @@ define('forum/chats', [ 'forum/chats/manage', 'forum/chats/messages', 'forum/chats/user-list', + 'forum/chats/message-search', 'composer/autocomplete', 'hooks', 'bootbox', @@ -17,10 +18,9 @@ define('forum/chats', [ 'api', 'uploadHelpers', ], function ( - components, mousetrap, - recentChats, create, manage, messages, - userList, autocomplete, hooks, bootbox, - alerts, chatModule, api, uploadHelpers + components, mousetrap, recentChats, create, + manage, messages, userList, messageSearch, autocomplete, + hooks, bootbox, alerts, chatModule, api, uploadHelpers ) { const Chats = { initialised: false, @@ -62,8 +62,8 @@ define('forum/chats', [ } Chats.initialised = true; - messages.scrollToBottom($('.expanded-chat ul.chat-content')); - messages.wrapImagesInLinks($('.expanded-chat ul.chat-content')); + messages.scrollToBottom($('[component="chat/message/content"]')); + messages.wrapImagesInLinks($('[component="chat/message/content"]')); create.init(); hooks.fire('action:chat.loaded', $('.chats-full')); @@ -80,8 +80,8 @@ define('forum/chats', [ Chats.addRenameHandler(roomId, chatControls.find('[data-action="rename"]')); Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]')); Chats.addDeleteHandler(roomId, chatControls.find('[data-action="delete"]')); - Chats.addScrollHandler(roomId, ajaxify.data.uid, $('.chat-content')); - Chats.addScrollBottomHandler($('.chat-content')); + Chats.addScrollHandler(roomId, ajaxify.data.uid, $('[component="chat/message/content"]')); + Chats.addScrollBottomHandler($('[component="chat/message/content"]')); Chats.addCharactersLeftHandler(mainWrapper); Chats.addTextareaResizeHandler(mainWrapper); Chats.addIPHandler(mainWrapper); @@ -98,6 +98,7 @@ define('forum/chats', [ Chats.switchChat(); }); userList.init(roomId, mainWrapper); + messageSearch.init(roomId); Chats.addPublicRoomSortHandler(); Chats.addTooltipHandler(); Chats.addNotificationSettingHandler(); @@ -268,24 +269,24 @@ define('forum/chats', [ // https://stackoverflow.com/questions/454202/creating-a-textarea-with-auto-resize const textarea = parent.find('[component="chat/input"]'); textarea.on('input', function () { - const isAtBottom = messages.isAtBottom(parent.find('.chat-content')); + const isAtBottom = messages.isAtBottom(parent.find('[component="chat/message/content"]')); textarea.css({ height: 0 }); textarea.css({ height: messages.calcAutoTextAreaHeight(textarea) + 'px' }); if (isAtBottom) { - messages.scrollToBottom(parent.find('.chat-content')); + messages.scrollToBottom(parent.find('[component="chat/message/content"]')); } }); }; Chats.addActionHandlers = function (element, roomId) { element.on('click', '[data-mid] [data-action]', function () { - const messageId = $(this).parents('[data-mid]').attr('data-mid'); + const msgEl = $(this).parents('[data-mid]'); + const messageId = msgEl.attr('data-mid'); const action = this.getAttribute('data-action'); switch (action) { case 'edit': { - const inputEl = $('[data-roomid="' + roomId + '"] [component="chat/input"]'); - messages.prepEdit(inputEl, messageId, roomId); + messages.prepEdit(msgEl, messageId, roomId); break; } case 'delete': @@ -509,7 +510,7 @@ define('forum/chats', [ Chats.setActive(roomId); Chats.addEventListeners(); hooks.fire('action:chat.loaded', $('.chats-full')); - messages.scrollToBottom(mainWrapper.find('.expanded-chat ul.chat-content')); + messages.scrollToBottom(mainWrapper.find('[component="chat/message/content"]')); if (history.pushState) { history.pushState({ url: url, @@ -543,7 +544,7 @@ define('forum/chats', [ data.message.self = data.self; data.message.timestamp = Math.min(Date.now(), data.message.timestamp); data.message.timestampISO = utils.toISOString(data.message.timestamp); - messages.appendChatMessage($('.expanded-chat .chat-content'), data.message); + messages.appendChatMessage($('[component="chat/message/content"]'), data.message); } }); diff --git a/public/src/client/chats/create.js b/public/src/client/chats/create.js index 6f5077e2e1..f9e48c2f13 100644 --- a/public/src/client/chats/create.js +++ b/public/src/client/chats/create.js @@ -2,8 +2,8 @@ define('forum/chats/create', [ - 'components', 'api', 'alerts', 'forum/chats/search', -], function (components, api, alerts, search) { + 'components', 'api', 'alerts', 'forum/chats/user-search', +], function (components, api, alerts, userSearch) { const create = {}; create.init = function () { components.get('chat/create').on('click', handleCreate); @@ -65,7 +65,7 @@ define('forum/chats/create', [ const chatRoomUsersList = modal.find('[component="chat/room/users"]'); - search.init({ + userSearch.init({ onSelect: async function (user) { const html = await app.parseAndTranslate('modals/create-room', 'selectedUsers', { selectedUsers: [user] }); chatRoomUsersList.append(html); diff --git a/public/src/client/chats/message-search.js b/public/src/client/chats/message-search.js new file mode 100644 index 0000000000..1da91577fc --- /dev/null +++ b/public/src/client/chats/message-search.js @@ -0,0 +1,82 @@ +'use strict'; + + +define('forum/chats/message-search', [ + 'components', 'alerts', 'forum/chats/messages', +], function (components, alerts, messages) { + const messageSearch = {}; + let roomId = 0; + let resultListEl; + let chatContent; + let clearEl; + + messageSearch.init = function (_roomId) { + roomId = _roomId; + const searchInput = $('[component="chat/room/search"]'); + searchInput.on('keyup', utils.debounce(doSearch, 250)) + .on('focus', () => { + if (searchInput.val()) { + doSearch(); + } + }); + resultListEl = $('[component="chat/message/search/results"]'); + chatContent = $('[component="chat/message/content"]'); + clearEl = $('[component="chat/room/search/clear"]'); + $('[component="chat/input"]').on('focus', () => { + resultListEl.addClass('hidden'); + chatContent.removeClass('hidden'); + }); + clearEl.on('click', clearInputAndResults); + }; + + function clearInputAndResults() { + components.get('chat/room/search').val(''); + removeResults(); + resultListEl.addClass('hidden'); + chatContent.removeClass('hidden'); + clearEl.addClass('hidden'); + } + + async function doSearch() { + const query = components.get('chat/room/search').val(); + if (!query) { + return clearInputAndResults(); + } + if (query.length <= 2) { + return; + } + clearEl.removeClass('hidden'); + socket.emit('modules.chats.searchMessages', { + content: query, + roomId: roomId, + }).then(displayResults) + .catch(alerts.error); + } + + function removeResults() { + resultListEl.children('[data-mid]').remove(); + } + + async function displayResults(data) { + removeResults(); + + if (!data.length) { + resultListEl.removeClass('hidden'); + chatContent.addClass('hidden'); + return resultListEl.find('[component="chat/message/search/no-results"]').removeClass('hidden'); + } + resultListEl.find('[component="chat/message/search/no-results"]').addClass('hidden'); + + const html = await app.parseAndTranslate('partials/chats/messages', { + messages: data, + isAdminOrGlobalMod: app.user.isAdmin || app.user.isGlobalMod, + }); + + resultListEl.append(html); + messages.onMessagesAddedToDom(resultListEl.find('[component="chat/message"]')); + chatContent.addClass('hidden'); + resultListEl.removeClass('hidden'); + } + + return messageSearch; +}); diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 0105c82666..041cee4585 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -108,14 +108,15 @@ define('forum/chats/messages', [ messages.onMessagesAddedToDom = function (messageEls) { messageEls.find('.timeago').timeago(); messageEls.find('img:not(.not-responsive)').addClass('img-fluid'); - messages.wrapImagesInLinks(messageEls.first().parent()); + messageEls.find('img:not(.emoji)').each(function () { + images.wrapImageInLink($(this)); + }); }; messages.parseMessage = function (data, callback) { const tplData = { messages: data, isAdminOrGlobalMod: app.user.isAdmin || app.user.isGlobalMod, - }; if (Array.isArray(data)) { app.parseAndTranslate('partials/chats/messages', tplData).then(callback); @@ -155,14 +156,14 @@ define('forum/chats/messages', [ .toggleClass('hidden', isAtBottom); }; - messages.prepEdit = async function (inputEl, mid, roomId) { + messages.prepEdit = async function (msgEl, mid, roomId) { const raw = await socket.emit('modules.chats.getRaw', { mid: mid, roomId: roomId }); const editEl = await app.parseAndTranslate('partials/chats/edit-message', { rawContent: raw, }); - const messageBody = $(`[data-roomid="${roomId}"] [data-mid="${mid}"] [component="chat/message/body"]`); - const messageControls = $(`[data-roomid="${roomId}"] [data-mid="${mid}"] [component="chat/message/controls"]`); - const chatContent = messageBody.parents('.chat-content'); + const messageBody = msgEl.find(`[component="chat/message/body"]`); + const messageControls = msgEl.find(`[component="chat/message/controls"]`); + const chatContent = messageBody.parents('[component="chat/message/content"]'); messageBody.addClass('hidden'); messageControls.addClass('hidden'); @@ -173,7 +174,7 @@ define('forum/chats/messages', [ textarea.focus().putCursorAtEnd(); autoresizeTextArea(textarea); - if (messages.isAtBottom(chatContent)) { + if (chatContent.length && messages.isAtBottom(chatContent)) { messages.scrollToBottom(chatContent); } @@ -212,7 +213,7 @@ define('forum/chats/messages', [ }); hooks.fire('action:chat.prepEdit', { - inputEl: inputEl, + msgEl: msgEl, messageId: mid, roomId: roomId, editEl: editEl, @@ -236,10 +237,10 @@ define('forum/chats/messages', [ const self = parseInt(message.fromuid, 10) === parseInt(app.user.uid, 10); message.self = self ? 1 : 0; messages.parseMessage(message, function (html) { - const body = components.get('chat/message', message.messageId); - if (body.length) { - body.replaceWith(html); - messages.onMessagesAddedToDom(html); + const msgEl = components.get('chat/message', message.mid); + if (msgEl.length) { + msgEl.replaceWith(html); + messages.onMessagesAddedToDom(components.get('chat/message', message.mid)); } }); }); diff --git a/public/src/client/chats/search.js b/public/src/client/chats/user-search.js similarity index 94% rename from public/src/client/chats/search.js rename to public/src/client/chats/user-search.js index bb0d160328..a07ebd7099 100644 --- a/public/src/client/chats/search.js +++ b/public/src/client/chats/user-search.js @@ -1,13 +1,13 @@ 'use strict'; -define('forum/chats/search', [ +define('forum/chats/user-search', [ 'components', 'api', 'alerts', ], function (components, api, alerts) { - const search = {}; + const userSearch = {}; let users = []; - search.init = function (options) { + userSearch.init = function (options) { options = options || {}; users.length = 0; components.get('chat/search').on('keyup', utils.debounce(doSearch, 250)); @@ -65,5 +65,5 @@ define('forum/chats/search', [ chatsListEl.parent().toggleClass('show', true); } - return search; + return userSearch; }); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 7b233d7d35..0595e1b59f 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -6,6 +6,7 @@ const db = require('../database'); const Messaging = require('../messaging'); const utils = require('../utils'); const user = require('../user'); +const plugins = require('../plugins'); const privileges = require('../privileges'); const groups = require('../groups'); @@ -213,4 +214,41 @@ SocketModules.chats.setNotificationSetting = async (socket, data) => { await Messaging.setUserNotificationSetting(socket.uid, data.roomId, data.value); }; +SocketModules.chats.searchMessages = async (socket, data) => { + if (!data || !utils.isNumber(data.roomId) || !data.content) { + throw new Error('[[error:invalid-data]]'); + } + const [roomData, inRoom] = await Promise.all([ + Messaging.getRoomData(data.roomId), + Messaging.isUserInRoom(socket.uid, data.roomId), + ]); + + if (!roomData) { + throw new Error('[[error:no-room]]'); + } + if (!inRoom) { + throw new Error('[[error:no-privileges]]'); + } + const { ids } = await plugins.hooks.fire('filter:messaging.searchMessages', { + content: data.content, + roomId: [data.roomId], + uid: [data.uid], + matchWords: 'any', + ids: [], + }); + + let userjoinTimestamp = 0; + if (!roomData.public) { + userjoinTimestamp = await db.sortedSetScore(`chat:room:${data.roomId}:uids`, socket.uid); + } + const messageData = await Messaging.getMessagesData(ids, socket.uid, data.roomId, false); + messageData.forEach((msg) => { + if (msg) { + msg.newSet = true; + } + }); + + return messageData.filter(msg => msg && !msg.deleted && msg.timestamp > userjoinTimestamp); +}; + require('../promisify')(SocketModules); diff --git a/test/messaging.js b/test/messaging.js index cb9e9f1555..1501f28e17 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -154,7 +154,7 @@ describe('Messaging Library', () => { const { body } = await callv3API('get', `/chats/${roomId}`, {}, 'foo'); const { messages } = body.response; assert.equal(messages.length, 2); - assert.strictEqual(messages[0].system, true); + assert.strictEqual(messages[0].system, 1); assert.strictEqual(messages[0].content, 'user-join'); const { statusCode, body: body2 } = await callv3API('put', `/chats/${roomId}/messages/${messages[0].messageId}`, { @@ -233,7 +233,7 @@ describe('Messaging Library', () => { const { body } = await callv3API('get', `/chats/${roomId}`, {}, 'foo'); const { messages } = body.response; const message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'user-leave'); }); @@ -244,12 +244,12 @@ describe('Messaging Library', () => { assert.equal(messages.length, 4); let message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'user-leave'); // The message before should still be a user-join message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'user-join'); }); @@ -466,7 +466,7 @@ describe('Messaging Library', () => { const { messages } = body.response; const message = messages.pop(); - assert.strictEqual(message.system, true); + assert.strictEqual(message.system, 1); assert.strictEqual(message.content, 'room-rename, new room name'); }); From 2fe193d68ffc4382adc109786e6cc46b3561adc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 28 Jul 2023 11:47:52 -0400 Subject: [PATCH 179/300] refactor: dont load all tokens in verify token use sortedSetsRemove --- src/api/utils.js | 16 ++++++++++------ src/routes/authentication.js | 3 +-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/api/utils.js b/src/api/utils.js index 4597bed42b..67e496a5f5 100644 --- a/src/api/utils.js +++ b/src/api/utils.js @@ -94,9 +94,11 @@ utils.tokens.roll = async (token) => { const updates = [ db.rename(`token:${token}`, `token:${newToken}`), - db.sortedSetRemove(`tokens:createtime`, token), - db.sortedSetRemove(`tokens:uid`, token), - db.sortedSetRemove(`tokens:lastSeen`, token), + db.sortedSetsRemove([ + `tokens:createtime`, + `tokens:uid`, + `tokens:lastSeen`, + ], token), db.sortedSetAdd(`tokens:createtime`, createTime, newToken), db.sortedSetAdd(`tokens:uid`, uid, newToken), ]; @@ -113,9 +115,11 @@ utils.tokens.roll = async (token) => { utils.tokens.delete = async (token) => { await Promise.all([ db.delete(`token:${token}`), - db.sortedSetRemove(`tokens:createtime`, token), - db.sortedSetRemove(`tokens:uid`, token), - db.sortedSetRemove(`tokens:lastSeen`, token), + db.sortedSetsRemove([ + `tokens:createtime`, + `tokens:uid`, + `tokens:lastSeen`, + ], token), ]); }; diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 8d5bee679e..e24ff064b9 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -45,8 +45,7 @@ Auth.getLoginStrategies = function () { }; Auth.verifyToken = async function (token, done) { - const tokens = await api.utils.tokens.list(); - const tokenObj = tokens.filter((t => t.token === token)).pop(); + const tokenObj = await api.utils.tokens.get(token); const uid = tokenObj ? tokenObj.uid : undefined; if (uid !== undefined) { From 7adfe0c16a25bb2988032a5de636f4ea5166ffb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 28 Jul 2023 12:06:18 -0400 Subject: [PATCH 180/300] show timestamp on system messages --- public/language/en-GB/modules.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index 46ea48a225..d65ba7cbba 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -62,9 +62,9 @@ "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", From 2c54e362b86c82430cc46b427b45d9e6b14c2e1c Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Fri, 28 Jul 2023 16:06:43 +0000 Subject: [PATCH 181/300] chore(i18n): fallback strings for new resources: nodebb.modules --- public/language/ar/modules.json | 6 +++--- public/language/bg/modules.json | 6 +++--- public/language/bn/modules.json | 6 +++--- public/language/cs/modules.json | 6 +++--- public/language/da/modules.json | 6 +++--- public/language/de/modules.json | 6 +++--- public/language/el/modules.json | 6 +++--- public/language/en-US/modules.json | 6 +++--- public/language/en-x-pirate/modules.json | 6 +++--- public/language/es/modules.json | 6 +++--- public/language/et/modules.json | 6 +++--- public/language/fa-IR/modules.json | 6 +++--- public/language/fi/modules.json | 6 +++--- public/language/fr/modules.json | 6 +++--- public/language/gl/modules.json | 6 +++--- public/language/he/modules.json | 6 +++--- public/language/hr/modules.json | 6 +++--- public/language/hu/modules.json | 6 +++--- public/language/hy/modules.json | 6 +++--- public/language/id/modules.json | 6 +++--- public/language/it/modules.json | 6 +++--- public/language/ja/modules.json | 6 +++--- public/language/ko/modules.json | 6 +++--- public/language/lt/modules.json | 6 +++--- public/language/lv/modules.json | 6 +++--- public/language/ms/modules.json | 6 +++--- public/language/nb/modules.json | 6 +++--- public/language/nl/modules.json | 6 +++--- public/language/pl/modules.json | 6 +++--- public/language/pt-BR/modules.json | 6 +++--- public/language/pt-PT/modules.json | 6 +++--- public/language/ro/modules.json | 6 +++--- public/language/ru/modules.json | 6 +++--- public/language/rw/modules.json | 6 +++--- public/language/sc/modules.json | 6 +++--- public/language/sk/modules.json | 6 +++--- public/language/sl/modules.json | 6 +++--- public/language/sq-AL/modules.json | 6 +++--- public/language/sr/modules.json | 6 +++--- public/language/sv/modules.json | 6 +++--- public/language/th/modules.json | 6 +++--- public/language/tr/modules.json | 6 +++--- public/language/uk/modules.json | 6 +++--- public/language/vi/modules.json | 6 +++--- public/language/zh-CN/modules.json | 6 +++--- public/language/zh-TW/modules.json | 6 +++--- 46 files changed, 138 insertions(+), 138 deletions(-) diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 181b234279..fbdf7dfe4e 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "اكتب", "composer.show_preview": "عرض المعاينة", "composer.hide_preview": "إخفاء المعاينة", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 95f0795d6a..c185b58c7f 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Показване на IP адреса", "chat.owner": "Собственик на стаята", "chat.grant-rescind-ownership": "Даване/отнемане на собственост", - "chat.system.user-join": "%1 се присъедини към стаята", - "chat.system.user-leave": "%1 напусна стаята", - "chat.system.room-rename": "%2 преименува тази стая: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Писане", "composer.show_preview": "Показване на прегледа", "composer.hide_preview": "Скриване на прегледа", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index 52c9a4105a..34ed5158f8 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index eb5cb5e3de..c85beb8727 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Zobrazit IP", "chat.owner": "Majitel místnosti", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 se připojil k místnosti", - "chat.system.user-leave": "%1 opustil místnost", - "chat.system.room-rename": "%2 přejmenoval tuto místnost: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Napsat", "composer.show_preview": "Ukázat náhled", "composer.hide_preview": "Skrýt náhled", diff --git a/public/language/da/modules.json b/public/language/da/modules.json index fecc99f04e..02b9f3c7b4 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Skriv", "composer.show_preview": "Vis forhåndsvisning", "composer.hide_preview": "Fjern forhåndsvisning", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index 522254fd7a..a59290000b 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "IP anzeigen", "chat.owner": "Raumbesitzer", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 ist dem Raum beigetreten", - "chat.system.user-leave": "%1 hat den Raum verlassen", - "chat.system.room-rename": "%2 hat den Raum umbenannt: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Verfassen", "composer.show_preview": "Vorschau zeigen", "composer.hide_preview": "Vorschau ausblenden", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index aecc617128..cabfa8feaa 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/en-US/modules.json b/public/language/en-US/modules.json index aecc617128..cabfa8feaa 100644 --- a/public/language/en-US/modules.json +++ b/public/language/en-US/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/en-x-pirate/modules.json b/public/language/en-x-pirate/modules.json index f338462a53..ecd5f0f7f7 100644 --- a/public/language/en-x-pirate/modules.json +++ b/public/language/en-x-pirate/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index a389cd7609..3270b233ec 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Mostrar IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Crear", "composer.show_preview": "Ver Previsualización", "composer.hide_preview": "Ocultar Previsualización", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index 37b20c6d42..e4b95555a1 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Koosta", "composer.show_preview": "Kuva eelvaadet", "composer.hide_preview": "Peida eelvaade", diff --git a/public/language/fa-IR/modules.json b/public/language/fa-IR/modules.json index a46b518f34..42cba33bb6 100644 --- a/public/language/fa-IR/modules.json +++ b/public/language/fa-IR/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "نشان دادن IP", "chat.owner": "مدیر چت روم", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "ارسال", "composer.show_preview": "نمایش پیش‌نمایش", "composer.hide_preview": "مخفی کردن پیش‌نمایش", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index 6dd7931adf..5bac4fcf40 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index ba8ce2afef..451dafc5ba 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Voir IP", "chat.owner": "Espace Admin", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 a rejoint la discussion", - "chat.system.user-leave": "%1 a quitté la discussion", - "chat.system.room-rename": "%2 a renommé la discussion: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Écrire", "composer.show_preview": "Afficher l'aperçu", "composer.hide_preview": "Masquer l'aperçu", diff --git a/public/language/gl/modules.json b/public/language/gl/modules.json index fc8ddc4481..793453dd84 100644 --- a/public/language/gl/modules.json +++ b/public/language/gl/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Elaborar", "composer.show_preview": "Amosar vista previa", "composer.hide_preview": "Agochar vista previa", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 17ff6ace10..d25b426051 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "הצג IP", "chat.owner": "מנהלי החדר", "chat.grant-rescind-ownership": "הענק/בטל בעלות", - "chat.system.user-join": "%1 הצטרף לחדר", - "chat.system.user-leave": "%1 יצא מהחדר", - "chat.system.room-rename": "%2 שינה את שם החדר: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "יצירה", "composer.show_preview": "הצגת תצוגה מקדימה", "composer.hide_preview": "הסתרת תצוגה מקדימה", diff --git a/public/language/hr/modules.json b/public/language/hr/modules.json index d44499d5e2..acf8cacc93 100644 --- a/public/language/hr/modules.json +++ b/public/language/hr/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Sastavi", "composer.show_preview": "Prikaz", "composer.hide_preview": "Sakrij prikaz", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index b814f6efcd..9a058aa48e 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "IP cím mutatása", "chat.owner": "Szoba tulajdonos", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 csatlakozott a szobához", - "chat.system.user-leave": "%1 elhagyta a szobát", - "chat.system.room-rename": "%2 megváltoztatta ennek a szobának a nevét: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Üzenetírás", "composer.show_preview": "Előnézet megjelenítése", "composer.hide_preview": "Előnézet elrejtése", diff --git a/public/language/hy/modules.json b/public/language/hy/modules.json index 40cbb76d75..a73d40682f 100644 --- a/public/language/hy/modules.json +++ b/public/language/hy/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Ցույց տալ IP", "chat.owner": "Սենյակի սեփականատեր", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1-ը միացել է սենյակին", - "chat.system.user-leave": "%1 դուրս է եկել սենյակից", - "chat.system.room-rename": "%2-ը վերանվանել է այս սենյակը՝ %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Կազմել", "composer.show_preview": "Ցույց տալ նախադիտումը", "composer.hide_preview": "Թաքցնել նախադիտումը", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index 89ccc3bf5c..458c0d5c54 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 808a26a41e..1999a52e71 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Mostra indirizzo IP", "chat.owner": "Propietario stanza", "chat.grant-rescind-ownership": "Concedi/Revoca Proprietà", - "chat.system.user-join": "%1 si è iscritto alla stanza", - "chat.system.user-leave": "%1 ha lasciato la stanza", - "chat.system.room-rename": "%2 ha rinominato questa stanza: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Componi", "composer.show_preview": "Visualizza Anteprima", "composer.hide_preview": "Nascondi Anteprima", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index 18dd1bf21b..a61995dc75 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "IP表示", "chat.owner": "部屋の管理者", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "構成", "composer.show_preview": "プレビュー表示", "composer.hide_preview": "プレビュー非表示", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index 40d3a33dd7..c1250bdf0e 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "IP 보이기", "chat.owner": "채팅 관리자", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1님이 입장하셨습니다.", - "chat.system.user-leave": "%1님이 퇴장하셨습니다.", - "chat.system.room-rename": "%2님의 채팅방 이름 변경: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "작성", "composer.show_preview": "미리보기", "composer.hide_preview": "미리보기 숨김", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index 459a2a9b17..9eb7a5582c 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Sukomponuoti", "composer.show_preview": "Rodyti pavyzdį", "composer.hide_preview": "Slėpti pavyzdį", diff --git a/public/language/lv/modules.json b/public/language/lv/modules.json index 87fc215797..1f38d20f22 100644 --- a/public/language/lv/modules.json +++ b/public/language/lv/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Rādīt IP adresi", "chat.owner": "Tērzētavas īpašnieks", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Rediģēt", "composer.show_preview": "Rādīt priekšskatu", "composer.hide_preview": "Slēpt priekšskatu", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index c730b8c1ff..283a56131f 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Tulis", "composer.show_preview": "Pra-lihat", "composer.hide_preview": "Sorok pra-lihat", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 0be7553875..46cab144c6 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Komponer", "composer.show_preview": "Vis forhåndsvisning", "composer.hide_preview": "Skjul forhåndsvisning", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index 26c542dca1..f66aa4ecea 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Geef IP weer", "chat.owner": "Chatroom-eigenaar", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 neemt nu deel aan de chatroom", - "chat.system.user-leave": "%1 heeft de chatroom verlaten", - "chat.system.room-rename": "%2 heeft deze chatroom hernoemd: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Samenstellen", "composer.show_preview": "Voorbeeldweergave", "composer.hide_preview": "Verberg voorbeeld", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 1717f2a916..2c01303394 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Pokaż IP", "chat.owner": "Właściciel pokoju", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 dołączył(a) do pokoju", - "chat.system.user-leave": "%1 opuścił(a) pokój", - "chat.system.room-rename": "%2 zmienił(a) nazwę pokoju: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Napisz", "composer.show_preview": "Pokaż podgląd", "composer.hide_preview": "Ukryj podgląd", diff --git a/public/language/pt-BR/modules.json b/public/language/pt-BR/modules.json index 16bc2f74a4..3bc3d9ab68 100644 --- a/public/language/pt-BR/modules.json +++ b/public/language/pt-BR/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Mostrar IP", "chat.owner": "Dono da Sala", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 entrou na sala", - "chat.system.user-leave": "%1 saiu da sala", - "chat.system.room-rename": "%2 renomeou esta sala: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compor", "composer.show_preview": "Exibir Pré-visualização", "composer.hide_preview": "Esconder Pré-visualização", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index d842bbda62..cb139a7422 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Mostrar IP", "chat.owner": "Dono da Sala", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 entrou na sala", - "chat.system.user-leave": "%1 saiu da sala", - "chat.system.room-rename": "%2 renomeou esta sala: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compor", "composer.show_preview": "Mostrar pré-visualização", "composer.hide_preview": "Ocultar pré-visualização", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index 3127065391..71bea16413 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Scrie", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 0eb1e78d70..ff107d8c02 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Показать IP", "chat.owner": "Владелец комнаты", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 присоединился к беседе", - "chat.system.user-leave": "%1 покинул беседу", - "chat.system.room-rename": "%2 переименовал беседу: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Редактор сообщений", "composer.show_preview": "Показать предпросмотр сообщения", "composer.hide_preview": "Скрыть предпросмотр", diff --git a/public/language/rw/modules.json b/public/language/rw/modules.json index 775280fee3..a95079801a 100644 --- a/public/language/rw/modules.json +++ b/public/language/rw/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Andika", "composer.show_preview": "Bona Uko Biza Gusa", "composer.hide_preview": "Hisha Uko Biza Gusa", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index 32d867babb..ffe8ad3a6b 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Compose", "composer.show_preview": "Show Preview", "composer.hide_preview": "Hide Preview", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index d7826260cd..533a63ea17 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Zobraziť IP adresu", "chat.owner": "Majiteľ miestnosti", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Napísať", "composer.show_preview": "Zobraziť náhľad", "composer.hide_preview": "Skryť náhľad", diff --git a/public/language/sl/modules.json b/public/language/sl/modules.json index 84bb172316..93020498f5 100644 --- a/public/language/sl/modules.json +++ b/public/language/sl/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Pokaži IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Sestavljanje", "composer.show_preview": "Pokaži predogled", "composer.hide_preview": "Skrij predogled", diff --git a/public/language/sq-AL/modules.json b/public/language/sq-AL/modules.json index 83012f9373..a9180aa6ff 100644 --- a/public/language/sq-AL/modules.json +++ b/public/language/sq-AL/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Shfaq IP", "chat.owner": "Administratori i hapësirës", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 i është bashkuar hapësirës", - "chat.system.user-leave": "%1 ka dalë nga hapësira", - "chat.system.room-rename": "%2 e ka riemërtuar këtë hapësirë: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Harto", "composer.show_preview": "Shiko rezultatin", "composer.hide_preview": "Mbulo rezultatin", diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index 8c4f816535..b275dd2136 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Прикажи IP", "chat.owner": "Власник собе", "chat.grant-rescind-ownership": "Додели/поништи власништво", - "chat.system.user-join": "%1 се придружио соби", - "chat.system.user-leave": "%1 је напустио собу", - "chat.system.room-rename": "%2 је преименовао собу: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Писање поруке", "composer.show_preview": "Прикажи преглед", "composer.hide_preview": "Сакриј преглед", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 6bc128d3e2..20ffa27565 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Visa IP", "chat.owner": "Rummets ägare", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 har anslutit till rummet", - "chat.system.user-leave": "%1 har lämnat rummet", - "chat.system.room-rename": "%2 har döpt om rummet: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Komponera", "composer.show_preview": "Visa förhandsgranskning", "composer.hide_preview": "Dölj förhandsgranskning", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index 16bfea1ecb..55690f2b3c 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Show IP", "chat.owner": "Room Owner", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room", - "chat.system.user-leave": "%1 has left the room", - "chat.system.room-rename": "%2 has renamed this room: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "เขียน", "composer.show_preview": "แสดงพรีวิว", "composer.hide_preview": "ซ่อนพรีวิว", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 9bfbdb71f2..660a37b410 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "IP Göster", "chat.owner": "Oda Sahibi", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 odaya katıldı", - "chat.system.user-leave": "%1 odadan çıktı", - "chat.system.room-rename": "%2 şu grubun ismini değiştirdi: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Yaz", "composer.show_preview": "Önizleme Göster", "composer.hide_preview": "Önizleme Sakla", diff --git a/public/language/uk/modules.json b/public/language/uk/modules.json index 55a8c2fa05..1d56251f71 100644 --- a/public/language/uk/modules.json +++ b/public/language/uk/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Показати IP", "chat.owner": "Власник кімнати", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 зайшов в кімнату", - "chat.system.user-leave": "%1 покинув кімнату", - "chat.system.room-rename": "%2 перейменував кімнату на: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Редактор повідомлень", "composer.show_preview": "Показати попередній перегляд", "composer.hide_preview": "Сховати попередній перегляд", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index e8f686c2cc..45edc6289b 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Hiện IP", "chat.owner": "Chủ Phòng", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 đã vào phòng", - "chat.system.user-leave": "%1 đã rời phòng", - "chat.system.room-rename": "%2 đã đổi tên phòng: %1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "Soạn thảo", "composer.show_preview": "Hiện Xem trước", "composer.hide_preview": "Ẩn Xem trước", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index 28c3195a75..aa264a32e3 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "显示 IP", "chat.owner": "房间所有者", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 加入了房间", - "chat.system.user-leave": "%1 离开了房间", - "chat.system.room-rename": "%2 更改房间名为:%1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "编写帮助", "composer.show_preview": "显示预览", "composer.hide_preview": "隐藏预览", diff --git a/public/language/zh-TW/modules.json b/public/language/zh-TW/modules.json index 351b4e96b3..2245a72dcf 100644 --- a/public/language/zh-TW/modules.json +++ b/public/language/zh-TW/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "顯示 IP", "chat.owner": "房間所有者", "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 加入了房間", - "chat.system.user-leave": "%1 離開了房間", - "chat.system.room-rename": "%2 更改房間名為:%1", + "chat.system.user-join": "%1 has joined the room ", + "chat.system.user-leave": "%1 has left the room ", + "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", "composer.compose": "撰寫", "composer.show_preview": "顯示預覽", "composer.hide_preview": "隱藏預覽", From 8444af1ce500e3035005a0bf9953887f5fab60be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 28 Jul 2023 12:08:29 -0400 Subject: [PATCH 182/300] chore: up themes --- install/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/package.json b/install/package.json index 6aac8d3c23..75f31bf384 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.17", + "nodebb-theme-harmony": "1.1.18", "nodebb-theme-lavender": "7.1.3", - "nodebb-theme-peace": "2.1.5", - "nodebb-theme-persona": "13.2.9", + "nodebb-theme-peace": "2.1.6", + "nodebb-theme-persona": "13.2.10", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", From 97127092b5013874826df5b84a3dc805842970d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 28 Jul 2023 13:51:57 -0400 Subject: [PATCH 183/300] hide search --- install/package.json | 4 +- public/src/client/chats/message-search.js | 47 +++++++++++++++-------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/install/package.json b/install/package.json index 75f31bf384..78b7ad0b60 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.18", + "nodebb-theme-harmony": "1.1.19", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.6", - "nodebb-theme-persona": "13.2.10", + "nodebb-theme-persona": "13.2.11", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", diff --git a/public/src/client/chats/message-search.js b/public/src/client/chats/message-search.js index 1da91577fc..b46cd651dc 100644 --- a/public/src/client/chats/message-search.js +++ b/public/src/client/chats/message-search.js @@ -6,43 +6,60 @@ define('forum/chats/message-search', [ ], function (components, alerts, messages) { const messageSearch = {}; let roomId = 0; + let searchInputEl; let resultListEl; let chatContent; let clearEl; - + let toggleEl; + let containerEl; messageSearch.init = function (_roomId) { roomId = _roomId; - const searchInput = $('[component="chat/room/search"]'); - searchInput.on('keyup', utils.debounce(doSearch, 250)) - .on('focus', () => { - if (searchInput.val()) { - doSearch(); - } - }); + resultListEl = $('[component="chat/message/search/results"]'); chatContent = $('[component="chat/message/content"]'); clearEl = $('[component="chat/room/search/clear"]'); + containerEl = $('[component="chat/room/search/container"]'); + toggleEl = $('[component="chat/room/search/toggle"'); + + searchInputEl = $('[component="chat/room/search"]'); + searchInputEl.on('keyup', utils.debounce(doSearch, 250)) + .on('focus', () => { + if (searchInputEl.val()) { + doSearch(); + } + }); + $('[component="chat/input"]').on('focus', () => { resultListEl.addClass('hidden'); chatContent.removeClass('hidden'); }); clearEl.on('click', clearInputAndResults); + + toggleEl.on('click', () => { + containerEl.removeClass('hidden'); + toggleEl.addClass('hidden'); + searchInputEl.trigger('focus'); + }); + searchInputEl.on('blur', () => { + if (!searchInputEl.val()) { + clearInputAndResults(); + } + }); }; function clearInputAndResults() { - components.get('chat/room/search').val(''); + searchInputEl.val(''); removeResults(); resultListEl.addClass('hidden'); - chatContent.removeClass('hidden'); clearEl.addClass('hidden'); + containerEl.addClass('hidden'); + chatContent.removeClass('hidden'); + toggleEl.removeClass('hidden'); } async function doSearch() { - const query = components.get('chat/room/search').val(); - if (!query) { - return clearInputAndResults(); - } - if (query.length <= 2) { + const query = searchInputEl.val(); + if (!query || query.length <= 2) { return; } clearEl.removeClass('hidden'); From c95119156db5d586d9235ac0f36557e06a611288 Mon Sep 17 00:00:00 2001 From: Opliko Date: Sun, 30 Jul 2023 02:11:17 +0200 Subject: [PATCH 184/300] fix: register abort can error on weird session state (#11854) --- src/controllers/authentication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index dcd9aa371f..58eff94299 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -210,7 +210,7 @@ authenticationController.registerComplete = async function (req, res) { }; authenticationController.registerAbort = async (req, res) => { - if (req.uid) { + if (req.uid && req.session.registration) { // Email is the only cancelable interstitial delete req.session.registration.updateEmail; From 8a761ff7ff641ec44b5926ac2642d15d198ad262 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jul 2023 20:12:00 -0400 Subject: [PATCH 185/300] chore(deps): update dependency eslint to v8.46.0 (#11852) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 78b7ad0b60..48d5ee947f 100644 --- a/install/package.json +++ b/install/package.json @@ -156,7 +156,7 @@ "@commitlint/cli": "17.6.7", "@commitlint/config-angular": "17.6.7", "coveralls": "3.1.1", - "eslint": "8.45.0", + "eslint": "8.46.0", "eslint-config-nodebb": "0.2.1", "eslint-plugin-import": "2.27.5", "grunt": "1.6.1", From 27c3f92be4193470aeb3c2ed7e51c15fd7f3cf5f Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 30 Jul 2023 09:18:15 +0000 Subject: [PATCH 186/300] Latest translations and fallbacks --- public/language/it/modules.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 1999a52e71..6bcf7cc1ad 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Mostra indirizzo IP", "chat.owner": "Propietario stanza", "chat.grant-rescind-ownership": "Concedi/Revoca Proprietà", - "chat.system.user-join": "%1 has joined the room ", - "chat.system.user-leave": "%1 has left the room ", - "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", + "chat.system.user-join": "%1 si è unito alla stanza ", + "chat.system.user-leave": "%1 ha lasciato la stanza ", + "chat.system.room-rename": "%2 ha rinominato questa stanza in \"%1\" ", "composer.compose": "Componi", "composer.show_preview": "Visualizza Anteprima", "composer.hide_preview": "Nascondi Anteprima", From 8ac34f8e8e630a9cb99a8c435ede15cbd4d9f542 Mon Sep 17 00:00:00 2001 From: Opliko Date: Mon, 31 Jul 2023 01:18:21 +0200 Subject: [PATCH 187/300] feat: password check hook (#11853) * feat: filter:password.check hook As requested on Discord, hopefully including all relevant user data * fix: don't use caller uid * feat: don't forward username separately --- src/controllers/authentication.js | 2 ++ src/user/profile.js | 2 ++ src/user/reset.js | 6 +++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 58eff94299..08515f1124 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -102,6 +102,8 @@ authenticationController.register = async function (req, res) { user.isPasswordValid(userData.password); + await plugins.hooks.fire('filter:password.check', { password: userData.password, uid: 0, userData: userData }); + res.locals.processLogin = true; // set it to false in plugin if you wish to just register only await plugins.hooks.fire('filter:register.check', { req: req, res: res, userData: userData }); diff --git a/src/user/profile.js b/src/user/profile.js index 09c4814410..8daba09758 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -310,6 +310,8 @@ module.exports = function (User) { throw new Error('[[user:change_password_error_privileges]]'); } + await plugins.hooks.fire('filter:password.check', { password: data.newPassword, uid: data.uid }); + if (isSelf && hasPassword) { const correct = await User.isPasswordCorrect(data.uid, data.currentPassword, data.ip); if (!correct) { diff --git a/src/user/reset.js b/src/user/reset.js index 557a83285c..9a6d6330ff 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -12,6 +12,7 @@ const db = require('../database'); const meta = require('../meta'); const emailer = require('../emailer'); const Password = require('../password'); +const plugins = require('../plugins'); const UserReset = module.exports; @@ -92,8 +93,11 @@ UserReset.commit = async function (code, password) { } const userData = await db.getObjectFields( `user:${uid}`, - ['password', 'passwordExpiry', 'password:shaWrapped'] + ['password', 'passwordExpiry', 'password:shaWrapped', 'username'] ); + + await plugins.hooks.fire('filter:password.check', { password: password, uid }); + const ok = await Password.compare(password, userData.password, !!parseInt(userData['password:shaWrapped'], 10)); if (ok) { throw new Error('[[error:reset-same-password]]'); From e38fe06fa932cf74f94a8cf27abd3f4906f5ce7a Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 31 Jul 2023 09:18:49 +0000 Subject: [PATCH 188/300] Latest translations and fallbacks --- public/language/bg/modules.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index c185b58c7f..22b4e1eeb3 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -61,9 +61,9 @@ "chat.show-ip": "Показване на IP адреса", "chat.owner": "Собственик на стаята", "chat.grant-rescind-ownership": "Даване/отнемане на собственост", - "chat.system.user-join": "%1 has joined the room ", - "chat.system.user-leave": "%1 has left the room ", - "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", + "chat.system.user-join": "%1 се присъедини към стаята ", + "chat.system.user-leave": "%1 напусна стаята ", + "chat.system.room-rename": "%2 преименува тази стая на „%1“ ", "composer.compose": "Писане", "composer.show_preview": "Показване на прегледа", "composer.hide_preview": "Скриване на прегледа", From b709ed9e63084da58ecd3f969f4ab2cb3979f6a5 Mon Sep 17 00:00:00 2001 From: Opliko Date: Mon, 31 Jul 2023 17:22:09 +0200 Subject: [PATCH 189/300] feat: move to npm fontawesome dependency and support fa pro (#11820) * feat: move to npm fontawesome dependency * feat: move shims to a separate file * fix: thin style prefix * feat: proper style and FA pro handling in icon selector * docs: add fontawesome properties to openAPI * fix: default for styles * feat: select all styles by default Turns out browsers lazy-load fonts. So since the actual CSS for each style is small, there is no perf reason for defaulting to free styles for FA pro users. This means they'll have to only change one setting. Still, the option to select styles remains for those who want it. * fix: remove console.log --- install/package.json | 1 + public/openapi/read/config.yaml | 11 + public/scss/fontawesome.scss | 7 - public/scss/fontawesome/loader.scss | 4 + .../fontawesome}/nodebb-shims.scss | 2 +- public/scss/fontawesome/style-brands.scss | 1 + public/scss/fontawesome/style-duotone.scss | 2 + public/scss/fontawesome/style-light.scss | 1 + public/scss/fontawesome/style-regular.scss | 1 + .../scss/fontawesome/style-sharp-light.scss | 1 + .../scss/fontawesome/style-sharp-regular.scss | 1 + .../scss/fontawesome/style-sharp-solid.scss | 1 + public/scss/fontawesome/style-sharp.scss | 3 + public/scss/fontawesome/style-solid.scss | 1 + public/scss/fontawesome/style-thin.scss | 1 + public/src/modules/iconSelect.js | 137 +- public/vendor/fontawesome/.gitignore | 29 - public/vendor/fontawesome/LICENSE.txt | 165 - public/vendor/fontawesome/attribution.js | 3 - public/vendor/fontawesome/scss/_animated.scss | 153 - .../fontawesome/scss/_bordered-pulled.scss | 20 - public/vendor/fontawesome/scss/_core.scss | 43 - .../vendor/fontawesome/scss/_fixed-width.scss | 7 - .../vendor/fontawesome/scss/_functions.scss | 57 - public/vendor/fontawesome/scss/_icons.scss | 9 - public/vendor/fontawesome/scss/_larger.scss | 24 - public/vendor/fontawesome/scss/_list.scss | 18 - public/vendor/fontawesome/scss/_mixins.scss | 75 - .../fontawesome/scss/_rotated-flipped.scss | 31 - .../fontawesome/scss/_screen-reader.scss | 14 - public/vendor/fontawesome/scss/_shims.scss | 2042 ------- public/vendor/fontawesome/scss/_sizing.scss | 16 - public/vendor/fontawesome/scss/_stacked.scss | 32 - .../vendor/fontawesome/scss/_variables.scss | 4951 ----------------- public/vendor/fontawesome/scss/brands.scss | 30 - .../vendor/fontawesome/scss/fontawesome.scss | 21 - public/vendor/fontawesome/scss/regular.scss | 26 - public/vendor/fontawesome/scss/solid.scss | 26 - public/vendor/fontawesome/scss/v4-shims.scss | 11 - .../webfonts/6.2.0/fa-brands-400.ttf | Bin 186112 -> 0 bytes .../webfonts/6.2.0/fa-brands-400.woff2 | Bin 107460 -> 0 bytes .../webfonts/6.2.0/fa-regular-400.ttf | Bin 62048 -> 0 bytes .../webfonts/6.2.0/fa-regular-400.woff2 | Bin 25096 -> 0 bytes .../webfonts/6.2.0/fa-solid-900.ttf | Bin 397728 -> 0 bytes .../webfonts/6.2.0/fa-solid-900.woff2 | Bin 150472 -> 0 bytes .../webfonts/6.2.0/fa-v4compatibility.ttf | Bin 10136 -> 0 bytes .../webfonts/6.2.0/fa-v4compatibility.woff2 | Bin 4584 -> 0 bytes src/controllers/api.js | 9 + src/meta/css.js | 15 +- src/prestart.js | 4 + src/routes/index.js | 2 + src/utils.js | 34 + 52 files changed, 193 insertions(+), 7849 deletions(-) delete mode 100644 public/scss/fontawesome.scss create mode 100644 public/scss/fontawesome/loader.scss rename public/{vendor/fontawesome/scss => scss/fontawesome}/nodebb-shims.scss (99%) create mode 100644 public/scss/fontawesome/style-brands.scss create mode 100644 public/scss/fontawesome/style-duotone.scss create mode 100644 public/scss/fontawesome/style-light.scss create mode 100644 public/scss/fontawesome/style-regular.scss create mode 100644 public/scss/fontawesome/style-sharp-light.scss create mode 100644 public/scss/fontawesome/style-sharp-regular.scss create mode 100644 public/scss/fontawesome/style-sharp-solid.scss create mode 100644 public/scss/fontawesome/style-sharp.scss create mode 100644 public/scss/fontawesome/style-solid.scss create mode 100644 public/scss/fontawesome/style-thin.scss delete mode 100644 public/vendor/fontawesome/.gitignore delete mode 100644 public/vendor/fontawesome/LICENSE.txt delete mode 100644 public/vendor/fontawesome/attribution.js delete mode 100644 public/vendor/fontawesome/scss/_animated.scss delete mode 100644 public/vendor/fontawesome/scss/_bordered-pulled.scss delete mode 100644 public/vendor/fontawesome/scss/_core.scss delete mode 100644 public/vendor/fontawesome/scss/_fixed-width.scss delete mode 100644 public/vendor/fontawesome/scss/_functions.scss delete mode 100644 public/vendor/fontawesome/scss/_icons.scss delete mode 100644 public/vendor/fontawesome/scss/_larger.scss delete mode 100644 public/vendor/fontawesome/scss/_list.scss delete mode 100644 public/vendor/fontawesome/scss/_mixins.scss delete mode 100644 public/vendor/fontawesome/scss/_rotated-flipped.scss delete mode 100644 public/vendor/fontawesome/scss/_screen-reader.scss delete mode 100644 public/vendor/fontawesome/scss/_shims.scss delete mode 100644 public/vendor/fontawesome/scss/_sizing.scss delete mode 100644 public/vendor/fontawesome/scss/_stacked.scss delete mode 100644 public/vendor/fontawesome/scss/_variables.scss delete mode 100644 public/vendor/fontawesome/scss/brands.scss delete mode 100644 public/vendor/fontawesome/scss/fontawesome.scss delete mode 100644 public/vendor/fontawesome/scss/regular.scss delete mode 100644 public/vendor/fontawesome/scss/solid.scss delete mode 100644 public/vendor/fontawesome/scss/v4-shims.scss delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.ttf delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.woff2 delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.ttf delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-regular-400.woff2 delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.ttf delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.woff2 delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.ttf delete mode 100644 public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.woff2 diff --git a/install/package.json b/install/package.json index 48d5ee947f..ce041b6c28 100644 --- a/install/package.json +++ b/install/package.json @@ -31,6 +31,7 @@ "@adactive/bootstrap-tagsinput": "0.8.2", "@fontsource/inter": "5.0.5", "@fontsource/poppins": "5.0.5", + "@fortawesome/fontawesome-free": "6.4.0", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", "ace-builds": "1.23.4", diff --git a/public/openapi/read/config.yaml b/public/openapi/read/config.yaml index 61fcfb4bba..795ef2f2d0 100644 --- a/public/openapi/read/config.yaml +++ b/public/openapi/read/config.yaml @@ -275,3 +275,14 @@ get: type: boolean composer-default: type: object + fontawesome: + type: object + properties: + pro: + type: boolean + styles: + type: array + items: + type: string + version: + type: string diff --git a/public/scss/fontawesome.scss b/public/scss/fontawesome.scss deleted file mode 100644 index cbe2a7e504..0000000000 --- a/public/scss/fontawesome.scss +++ /dev/null @@ -1,7 +0,0 @@ -$fa-font-path: "vendor/fontawesome/webfonts/6.2.0"; -@import "../public/vendor/fontawesome/scss/fontawesome"; -@import "../public/vendor/fontawesome/scss/regular"; -@import "../public/vendor/fontawesome/scss/solid"; -@import "../public/vendor/fontawesome/scss/brands"; -@import "../public/vendor/fontawesome/scss/v4-shims"; -@import "../public/vendor/fontawesome/scss/nodebb-shims"; \ No newline at end of file diff --git a/public/scss/fontawesome/loader.scss b/public/scss/fontawesome/loader.scss new file mode 100644 index 0000000000..ceeca56340 --- /dev/null +++ b/public/scss/fontawesome/loader.scss @@ -0,0 +1,4 @@ +$fa-font-path: "./vendor/fontawesome/webfonts"; +@import "fontawesome"; +@import "v4-shims"; +@import "nodebb-shims"; \ No newline at end of file diff --git a/public/vendor/fontawesome/scss/nodebb-shims.scss b/public/scss/fontawesome/nodebb-shims.scss similarity index 99% rename from public/vendor/fontawesome/scss/nodebb-shims.scss rename to public/scss/fontawesome/nodebb-shims.scss index 8c3bc5230d..04add18cd8 100644 --- a/public/vendor/fontawesome/scss/nodebb-shims.scss +++ b/public/scss/fontawesome/nodebb-shims.scss @@ -1,5 +1,5 @@ -@import "_variables.scss"; +// NodeBB backwards compatibility shims @font-face { font-family: 'FontAwesome'; font-style: normal; diff --git a/public/scss/fontawesome/style-brands.scss b/public/scss/fontawesome/style-brands.scss new file mode 100644 index 0000000000..52da4901e0 --- /dev/null +++ b/public/scss/fontawesome/style-brands.scss @@ -0,0 +1 @@ +@import "brands"; \ No newline at end of file diff --git a/public/scss/fontawesome/style-duotone.scss b/public/scss/fontawesome/style-duotone.scss new file mode 100644 index 0000000000..e285cc86fa --- /dev/null +++ b/public/scss/fontawesome/style-duotone.scss @@ -0,0 +1,2 @@ +@import "duotone"; +@import "_duotone-icons"; \ No newline at end of file diff --git a/public/scss/fontawesome/style-light.scss b/public/scss/fontawesome/style-light.scss new file mode 100644 index 0000000000..989bcd0bc5 --- /dev/null +++ b/public/scss/fontawesome/style-light.scss @@ -0,0 +1 @@ +@import "light"; diff --git a/public/scss/fontawesome/style-regular.scss b/public/scss/fontawesome/style-regular.scss new file mode 100644 index 0000000000..b85bc17bf1 --- /dev/null +++ b/public/scss/fontawesome/style-regular.scss @@ -0,0 +1 @@ +@import "regular"; diff --git a/public/scss/fontawesome/style-sharp-light.scss b/public/scss/fontawesome/style-sharp-light.scss new file mode 100644 index 0000000000..bdf377c050 --- /dev/null +++ b/public/scss/fontawesome/style-sharp-light.scss @@ -0,0 +1 @@ +@import "sharp-light"; diff --git a/public/scss/fontawesome/style-sharp-regular.scss b/public/scss/fontawesome/style-sharp-regular.scss new file mode 100644 index 0000000000..4b9bf9a613 --- /dev/null +++ b/public/scss/fontawesome/style-sharp-regular.scss @@ -0,0 +1 @@ +@import "sharp-regular"; diff --git a/public/scss/fontawesome/style-sharp-solid.scss b/public/scss/fontawesome/style-sharp-solid.scss new file mode 100644 index 0000000000..ae01f10776 --- /dev/null +++ b/public/scss/fontawesome/style-sharp-solid.scss @@ -0,0 +1 @@ +@import "sharp-solid"; diff --git a/public/scss/fontawesome/style-sharp.scss b/public/scss/fontawesome/style-sharp.scss new file mode 100644 index 0000000000..7f2ae6f020 --- /dev/null +++ b/public/scss/fontawesome/style-sharp.scss @@ -0,0 +1,3 @@ +@import "sharp-light"; +@import "sharp-regular"; +@import "sharp-solid"; diff --git a/public/scss/fontawesome/style-solid.scss b/public/scss/fontawesome/style-solid.scss new file mode 100644 index 0000000000..ad46ec9b0b --- /dev/null +++ b/public/scss/fontawesome/style-solid.scss @@ -0,0 +1 @@ +@import "solid"; diff --git a/public/scss/fontawesome/style-thin.scss b/public/scss/fontawesome/style-thin.scss new file mode 100644 index 0000000000..ebe25b67e3 --- /dev/null +++ b/public/scss/fontawesome/style-thin.scss @@ -0,0 +1 @@ +@import "thin"; diff --git a/public/src/modules/iconSelect.js b/public/src/modules/iconSelect.js index 3795c00e23..fb4d537a45 100644 --- a/public/src/modules/iconSelect.js +++ b/public/src/modules/iconSelect.js @@ -2,6 +2,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { + const fontawesome_license = config.fontawesome.pro ? 'pro' : 'free'; const iconSelect = {}; const initialIcons = [ { id: 'nbb-none', label: 'None (NodeBB)', style: 'nodebb' }, @@ -222,16 +223,17 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { { id: 'address-book', label: 'Address Book (solid)', style: 'solid' }, ]; iconSelect.init = function (el, onModified) { - onModified = onModified || function () {}; - let selected = cleanFAClass(el.attr('class')); - + onModified = onModified || function () { }; + let selected = cleanFAClass(el[0].classList); $('#icons .selected').removeClass('selected'); - - if (selected) { + if (selected.icon) { try { - $('#icons .nbb-fa-icons .fa.' + selected).addClass('selected'); + $(`#icons .nbb-fa-icons ${selected.styles.length ? '.' + selected.styles.join('.') : ''}.${selected.icon}`).addClass('selected'); } catch (err) { - selected = ''; + selected = { + icon: '', + style: '', + }; } } @@ -250,26 +252,39 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { label: 'No Icon', className: 'btn-default', callback: function () { - el.removeClass(selected); + el.removeClass(selected.icon); + // eslint-disable-next-line no-restricted-syntax + for (const style of selected.styles) { + el.removeClass(style); + } el.val(''); el.attr('value', ''); - onModified(el, ''); + onModified(el, '', []); }, }, success: { label: 'Select', className: 'btn-primary', callback: function () { - const iconClass = $('.bootbox .selected').attr('class') || `fa fa-${$('.bootbox #fa-filter').val()}`; - const newIconClass = cleanFAClass(iconClass); - - if (newIconClass) { - el.removeClass(selected).addClass(newIconClass); - el.val(newIconClass); - el.attr('value', newIconClass); + const iconClass = $('.bootbox .selected')[0]?.classList || [`fa-${$('.bootbox #fa-filter').val()}`]; + const newIcon = cleanFAClass(iconClass); + if (newIcon.icon) { + el.removeClass(selected.icon).addClass(newIcon.icon); + // eslint-disable-next-line no-restricted-syntax + for (const style of selected.styles || []) { + el.removeClass(style); + } + // eslint-disable-next-line no-restricted-syntax + for (const style of newIcon.styles || []) { + el.addClass(style); + } + // Simple workaround for lack of style information in icons by just adding the style class to the value + const newValue = newIcon.icon + (newIcon.styles.length ? ' ' + newIcon.styles.join(' ') : ''); + el.val(newValue); + el.attr('value', newValue); } - onModified(el, newIconClass); + onModified(el, newIcon.icon, newIcon.styles); }, }, }, @@ -279,9 +294,9 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { const modalEl = $(this); const searchEl = modalEl.find('input'); - if (selected) { - modalEl.find('.' + selected).addClass('selected'); - searchEl.val(selected.replace('fa-', '')); + if (selected.icon) { + modalEl.find('.' + selected.icon).addClass('selected'); + searchEl.val(selected.icon.replace('fa-', '')); } }).modal('show'); @@ -298,8 +313,8 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { if (newSelection) { newSelection.addClass('selected'); } else if (searchEl.val().length === 0) { - if (selected) { - modalEl.find('.' + selected).addClass('selected'); + if (selected.icon) { + modalEl.find('.' + selected.icon).addClass('selected'); } } else { modalEl.find('i:visible').first().addClass('selected'); @@ -310,7 +325,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { searchEl.selectRange(0, searchEl.val().length); modalEl.find('.icon-container').on('click', 'i', function () { - searchEl.val(cleanFAClass($(this).attr('class')).replace('fa-', '')); + searchEl.val(cleanFAClass($(this)[0].classList).icon.replace('fa-', '')); changeSelection($(this)); }); const debouncedSearch = utils.debounce(async () => { @@ -323,7 +338,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { } icons.remove(); iconData.forEach((iconData) => { - iconContainer.append($(``)); + iconContainer.append($(``)); }); icons = modalEl.find('.nbb-fa-icons i'); changeSelection(); @@ -340,13 +355,54 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { }); }; - // turns "fa fa-2x fa-solid fa-heart" into "fa-heart" - function cleanFAClass(className) { - className = className.replace(/fa-(solid|regular|brands|light|thin|duotone|nodebb) /, ''); - const filterNames = ['fa-2x', 'fa-xl', 'fa', 'fa-']; - return className.split(' ') - .filter(c => !filterNames.includes(c)) - .filter(c => c && c.startsWith('fa-')).join(''); + const excludedClassList = [ + 'nodebb', + 'fw', + '\\d{1,2}?[xsl][smgl]', + 'rotate-(\\d+|horizontal|vertical|both|by)', + 'flip-(\\d+|horizontal|vertical|both)', + 'beat', + 'fade', + 'beat-fade', + 'bounce', + 'flip', + 'shake', + 'spin', + 'spin-pulse', + 'spin-reverse', + 'border', + 'pull-(left|right)', + 'stack(-\\dx)?', + 'inverse', + 'layers(-text)?(-counter)?', + 'ul', + 'li', + 'border', + 'swap-opacity', + 'sr-only(-focusable)?', + ]; + + const excludedClassRegex = RegExp(`\\bfa-(${excludedClassList.join('|')})\\b`, 'i'); + + const styleRegex = /fa-(solid|regular|brands|light|thin|duotone|sharp)/; + // turns 'fa fa-2x fa-solid fa-heart' into 'fa-heart' + function cleanFAClass(classList) { + const styles = []; + let icon; + // eslint-disable-next-line no-restricted-syntax + for (const className of classList) { + if (className.startsWith('fa-') && !excludedClassRegex.test(className)) { + if (styleRegex.test(className)) { + styles.push(className); + } else { + icon = className; + } + } + } + return { + icon, + styles, + }; } iconSelect.findIcons = async function (searchString) { @@ -357,26 +413,35 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) { }, body: JSON.stringify({ query: `query { - search(version: "6.2.0", query: "${searchString}", first: 200) { + search(version: "${config.fontawesome.version}", query: "${searchString}", first: 200) { id, label, familyStylesByLicense { - free { - style + ${fontawesome_license} { + style, + family } } } - }`, + }`.replace(/(\n| {2,}|\t{2,})/g, ''), // very simple minification }), }); const response = await request.json(); const icons = response.data.search.filter(icon => icon.familyStylesByLicense.free.length > 0).flatMap((icon) => { const result = []; - icon.familyStylesByLicense.free.forEach((style) => { + icon.familyStylesByLicense[fontawesome_license].forEach((style) => { + let familyStyle = style.style; + if (style.family !== 'classic') { + familyStyle = `${style.family}-${familyStyle}`; + } + if (!config.fontawesome.styles.includes(familyStyle)) { + return; + } result.push({ id: icon.id, label: `${icon.label} (${style.style})`, style: style.style, + family: style.family, }); }); return result; diff --git a/public/vendor/fontawesome/.gitignore b/public/vendor/fontawesome/.gitignore deleted file mode 100644 index aaad45f3c8..0000000000 --- a/public/vendor/fontawesome/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -*.pyc -*.egg-info -*.db -*.db.old -*.swp -*.db-journal - -.coverage -.DS_Store -.installed.cfg - -.idea/* -.svn/* -src/website/static/* -src/website/media/* - -bin -build -cfcache -develop-eggs -dist -downloads -eggs -parts -tmp -.sass-cache - -src/website/settingslocal.py -stunnel.log \ No newline at end of file diff --git a/public/vendor/fontawesome/LICENSE.txt b/public/vendor/fontawesome/LICENSE.txt deleted file mode 100644 index cc557ece45..0000000000 --- a/public/vendor/fontawesome/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ -Fonticons, Inc. (https://fontawesome.com) - --------------------------------------------------------------------------------- - -Font Awesome Free License - -Font Awesome Free is free, open source, and GPL friendly. You can use it for -commercial projects, open source projects, or really almost whatever you want. -Full Font Awesome Free license: https://fontawesome.com/license/free. - --------------------------------------------------------------------------------- - -# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) - -The Font Awesome Free download is licensed under a Creative Commons -Attribution 4.0 International License and applies to all icons packaged -as SVG and JS file types. - --------------------------------------------------------------------------------- - -# Fonts: SIL OFL 1.1 License - -In the Font Awesome Free download, the SIL OFL license applies to all icons -packaged as web and desktop font files. - -Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com) -with Reserved Font Name: "Font Awesome". - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - -SIL OPEN FONT LICENSE -Version 1.1 - 26 February 2007 - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting — in part or in whole — any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - --------------------------------------------------------------------------------- - -# Code: MIT License (https://opensource.org/licenses/MIT) - -In the Font Awesome Free download, the MIT license applies to all non-font and -non-icon files. - -Copyright 2022 Fonticons, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in the -Software without restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------------------------------------- - -# Attribution - -Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font -Awesome Free files already contain embedded comments with sufficient -attribution, so you shouldn't need to do anything additional when using these -files normally. - -We've kept attribution comments terse, so we ask that you do not actively work -to remove them from files, especially code. They're a great way for folks to -learn about Font Awesome. - --------------------------------------------------------------------------------- - -# Brand Icons - -All brand icons are trademarks of their respective owners. The use of these -trademarks does not indicate endorsement of the trademark holder by Font -Awesome, nor vice versa. **Please do not use brand logos for any purpose except -to represent the company, product, or service to which they refer.** diff --git a/public/vendor/fontawesome/attribution.js b/public/vendor/fontawesome/attribution.js deleted file mode 100644 index a659606c8d..0000000000 --- a/public/vendor/fontawesome/attribution.js +++ /dev/null @@ -1,3 +0,0 @@ -console.log(`Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com -License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -`) \ No newline at end of file diff --git a/public/vendor/fontawesome/scss/_animated.scss b/public/vendor/fontawesome/scss/_animated.scss deleted file mode 100644 index 93555b2f43..0000000000 --- a/public/vendor/fontawesome/scss/_animated.scss +++ /dev/null @@ -1,153 +0,0 @@ -// animating icons -// -------------------------- - -.#{$fa-css-prefix}-beat { - animation-name: #{$fa-css-prefix}-beat; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, ease-in-out); -} - -.#{$fa-css-prefix}-bounce { - animation-name: #{$fa-css-prefix}-bounce; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(0.280, 0.840, 0.420, 1)); -} - -.#{$fa-css-prefix}-fade { - animation-name: #{$fa-css-prefix}-fade; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1)); -} - -.#{$fa-css-prefix}-beat-fade { - animation-name: #{$fa-css-prefix}-beat-fade; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, cubic-bezier(.4,0,.6,1)); -} - -.#{$fa-css-prefix}-flip { - animation-name: #{$fa-css-prefix}-flip; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, ease-in-out); -} - -.#{$fa-css-prefix}-shake { - animation-name: #{$fa-css-prefix}-shake; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, linear); -} - -.#{$fa-css-prefix}-spin { - animation-name: #{$fa-css-prefix}-spin; - animation-delay: var(--#{$fa-css-prefix}-animation-delay, 0s); - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 2s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, linear); -} - -.#{$fa-css-prefix}-spin-reverse { - --#{$fa-css-prefix}-animation-direction: reverse; -} - -.#{$fa-css-prefix}-pulse, -.#{$fa-css-prefix}-spin-pulse { - animation-name: #{$fa-css-prefix}-spin; - animation-direction: var(--#{$fa-css-prefix}-animation-direction, normal); - animation-duration: var(--#{$fa-css-prefix}-animation-duration, 1s); - animation-iteration-count: var(--#{$fa-css-prefix}-animation-iteration-count, infinite); - animation-timing-function: var(--#{$fa-css-prefix}-animation-timing, steps(8)); -} - -// if agent or operating system prefers reduced motion, disable animations -// see: https://www.smashingmagazine.com/2020/09/design-reduced-motion-sensitivities/ -// see: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion -@media (prefers-reduced-motion: reduce) { - .#{$fa-css-prefix}-beat, - .#{$fa-css-prefix}-bounce, - .#{$fa-css-prefix}-fade, - .#{$fa-css-prefix}-beat-fade, - .#{$fa-css-prefix}-flip, - .#{$fa-css-prefix}-pulse, - .#{$fa-css-prefix}-shake, - .#{$fa-css-prefix}-spin, - .#{$fa-css-prefix}-spin-pulse { - animation-delay: -1ms; - animation-duration: 1ms; - animation-iteration-count: 1; - transition-delay: 0s; - transition-duration: 0s; - } -} - -@keyframes #{$fa-css-prefix}-beat { - 0%, 90% { transform: scale(1); } - 45% { transform: scale(var(--#{$fa-css-prefix}-beat-scale, 1.25)); } -} - -@keyframes #{$fa-css-prefix}-bounce { - 0% { transform: scale(1,1) translateY(0); } - 10% { transform: scale(var(--#{$fa-css-prefix}-bounce-start-scale-x, 1.1),var(--#{$fa-css-prefix}-bounce-start-scale-y, 0.9)) translateY(0); } - 30% { transform: scale(var(--#{$fa-css-prefix}-bounce-jump-scale-x, 0.9),var(--#{$fa-css-prefix}-bounce-jump-scale-y, 1.1)) translateY(var(--#{$fa-css-prefix}-bounce-height, -0.5em)); } - 50% { transform: scale(var(--#{$fa-css-prefix}-bounce-land-scale-x, 1.05),var(--#{$fa-css-prefix}-bounce-land-scale-y, 0.95)) translateY(0); } - 57% { transform: scale(1,1) translateY(var(--#{$fa-css-prefix}-bounce-rebound, -0.125em)); } - 64% { transform: scale(1,1) translateY(0); } - 100% { transform: scale(1,1) translateY(0); } -} - -@keyframes #{$fa-css-prefix}-fade { - 50% { opacity: var(--#{$fa-css-prefix}-fade-opacity, 0.4); } -} - -@keyframes #{$fa-css-prefix}-beat-fade { - 0%, 100% { - opacity: var(--#{$fa-css-prefix}-beat-fade-opacity, 0.4); - transform: scale(1); - } - 50% { - opacity: 1; - transform: scale(var(--#{$fa-css-prefix}-beat-fade-scale, 1.125)); - } -} - -@keyframes #{$fa-css-prefix}-flip { - 50% { - transform: rotate3d(var(--#{$fa-css-prefix}-flip-x, 0), var(--#{$fa-css-prefix}-flip-y, 1), var(--#{$fa-css-prefix}-flip-z, 0), var(--#{$fa-css-prefix}-flip-angle, -180deg)); - } -} - -@keyframes #{$fa-css-prefix}-shake { - 0% { transform: rotate(-15deg); } - 4% { transform: rotate(15deg); } - 8%, 24% { transform: rotate(-18deg); } - 12%, 28% { transform: rotate(18deg); } - 16% { transform: rotate(-22deg); } - 20% { transform: rotate(22deg); } - 32% { transform: rotate(-12deg); } - 36% { transform: rotate(12deg); } - 40%, 100% { transform: rotate(0deg); } -} - -@keyframes #{$fa-css-prefix}-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - diff --git a/public/vendor/fontawesome/scss/_bordered-pulled.scss b/public/vendor/fontawesome/scss/_bordered-pulled.scss deleted file mode 100644 index 9068253a74..0000000000 --- a/public/vendor/fontawesome/scss/_bordered-pulled.scss +++ /dev/null @@ -1,20 +0,0 @@ -// bordered + pulled icons -// ------------------------- - -.#{$fa-css-prefix}-border { - border-color: var(--#{$fa-css-prefix}-border-color, #{$fa-border-color}); - border-radius: var(--#{$fa-css-prefix}-border-radius, #{$fa-border-radius}); - border-style: var(--#{$fa-css-prefix}-border-style, #{$fa-border-style}); - border-width: var(--#{$fa-css-prefix}-border-width, #{$fa-border-width}); - padding: var(--#{$fa-css-prefix}-border-padding, #{$fa-border-padding}); -} - -.#{$fa-css-prefix}-pull-left { - float: left; - margin-right: var(--#{$fa-css-prefix}-pull-margin, #{$fa-pull-margin}); -} - -.#{$fa-css-prefix}-pull-right { - float: right; - margin-left: var(--#{$fa-css-prefix}-pull-margin, #{$fa-pull-margin}); -} diff --git a/public/vendor/fontawesome/scss/_core.scss b/public/vendor/fontawesome/scss/_core.scss deleted file mode 100644 index 1b2fd99205..0000000000 --- a/public/vendor/fontawesome/scss/_core.scss +++ /dev/null @@ -1,43 +0,0 @@ -// base icon class definition -// ------------------------- - -.#{$fa-css-prefix} { - font-family: var(--#{$fa-css-prefix}-style-family, '#{$fa-style-family}'); - font-weight: var(--#{$fa-css-prefix}-style, #{$fa-style}); -} - -.#{$fa-css-prefix}, -.#{$fa-css-prefix}-classic, -.#{$fa-css-prefix}-sharp, -.fas, -.#{$fa-css-prefix}-solid, -.far, -.#{$fa-css-prefix}-regular, -.fab, -.#{$fa-css-prefix}-brands { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - display: var(--#{$fa-css-prefix}-display, #{$fa-display}); - font-style: normal; - font-variant: normal; - line-height: 1; - text-rendering: auto; -} - -.fas, -.#{$fa-css-prefix}-classic, -.#{$fa-css-prefix}-solid, -.far, -.#{$fa-css-prefix}-regular { - font-family: 'Font Awesome 6 Free'; -} - -.fab, -.#{$fa-css-prefix}-brands { - font-family: 'Font Awesome 6 Brands'; -} - - -%fa-icon { - @include fa-icon; -} diff --git a/public/vendor/fontawesome/scss/_fixed-width.scss b/public/vendor/fontawesome/scss/_fixed-width.scss deleted file mode 100644 index 72342368af..0000000000 --- a/public/vendor/fontawesome/scss/_fixed-width.scss +++ /dev/null @@ -1,7 +0,0 @@ -// fixed-width icons -// ------------------------- - -.#{$fa-css-prefix}-fw { - text-align: center; - width: $fa-fw-width; -} diff --git a/public/vendor/fontawesome/scss/_functions.scss b/public/vendor/fontawesome/scss/_functions.scss deleted file mode 100644 index a17ffe87cc..0000000000 --- a/public/vendor/fontawesome/scss/_functions.scss +++ /dev/null @@ -1,57 +0,0 @@ -// functions -// -------------------------- - -// fa-content: convenience function used to set content property -@function fa-content($fa-var) { - @return unquote("\"#{ $fa-var }\""); -} - -// fa-divide: Originally obtained from the Bootstrap https://github.com/twbs/bootstrap -// -// Licensed under: The MIT License (MIT) -// -// Copyright (c) 2011-2021 Twitter, Inc. -// Copyright (c) 2011-2021 The Bootstrap Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -@function fa-divide($dividend, $divisor, $precision: 10) { - $sign: if($dividend > 0 and $divisor > 0, 1, -1); - $dividend: abs($dividend); - $divisor: abs($divisor); - $quotient: 0; - $remainder: $dividend; - @if $dividend == 0 { - @return 0; - } - @if $divisor == 0 { - @error "Cannot divide by 0"; - } - @if $divisor == 1 { - @return $dividend; - } - @while $remainder >= $divisor { - $quotient: $quotient + 1; - $remainder: $remainder - $divisor; - } - @if $remainder > 0 and $precision > 0 { - $remainder: fa-divide($remainder * 10, $divisor, $precision - 1) * .1; - } - @return ($quotient + $remainder) * $sign; -} diff --git a/public/vendor/fontawesome/scss/_icons.scss b/public/vendor/fontawesome/scss/_icons.scss deleted file mode 100644 index 9e57e39cb3..0000000000 --- a/public/vendor/fontawesome/scss/_icons.scss +++ /dev/null @@ -1,9 +0,0 @@ -// specific icon class definition -// ------------------------- - -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen -readers do not read off random characters that represent icons */ - -@each $name, $icon in $fa-icons { - .#{$fa-css-prefix}-#{$name}::before { content: unquote("\"#{ $icon }\""); } -} diff --git a/public/vendor/fontawesome/scss/_larger.scss b/public/vendor/fontawesome/scss/_larger.scss deleted file mode 100644 index e88f4e54d0..0000000000 --- a/public/vendor/fontawesome/scss/_larger.scss +++ /dev/null @@ -1,24 +0,0 @@ -// Icon Sizes -// ------------------------- -@use "sass:math"; - -// makes the font 33% larger relative to the icon container -.#{$fa-css-prefix}-lg { - font-size: math.div(4em, 3); - line-height: math.div(3em, 4); - vertical-align: -.0667em; -} - -.#{$fa-css-prefix}-xs { - font-size: .75em; -} - -.#{$fa-css-prefix}-sm { - font-size: .875em; -} - -@for $i from 1 through 10 { - .#{$fa-css-prefix}-#{$i}x { - font-size: $i * 1em; - } -} diff --git a/public/vendor/fontawesome/scss/_list.scss b/public/vendor/fontawesome/scss/_list.scss deleted file mode 100644 index ced36e20a2..0000000000 --- a/public/vendor/fontawesome/scss/_list.scss +++ /dev/null @@ -1,18 +0,0 @@ -// icons in a list -// ------------------------- - -.#{$fa-css-prefix}-ul { - list-style-type: none; - margin-left: var(--#{$fa-css-prefix}-li-margin, #{$fa-li-margin}); - padding-left: 0; - - > li { position: relative; } -} - -.#{$fa-css-prefix}-li { - left: calc(var(--#{$fa-css-prefix}-li-width, #{$fa-li-width}) * -1); - position: absolute; - text-align: center; - width: var(--#{$fa-css-prefix}-li-width, #{$fa-li-width}); - line-height: inherit; -} diff --git a/public/vendor/fontawesome/scss/_mixins.scss b/public/vendor/fontawesome/scss/_mixins.scss deleted file mode 100644 index e06b69aa54..0000000000 --- a/public/vendor/fontawesome/scss/_mixins.scss +++ /dev/null @@ -1,75 +0,0 @@ -// mixins -// -------------------------- - -// base rendering for an icon -@mixin fa-icon { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - display: inline-block; - font-style: normal; - font-variant: normal; - font-weight: normal; - line-height: 1; -} - -// sets relative font-sizing and alignment (in _sizing) -@mixin fa-size ($font-size) { - font-size: fa-divide($font-size, $fa-size-scale-base) * 1em; // converts step in sizing scale into an em-based value that's relative to the scale's base - line-height: fa-divide(1, $font-size) * 1em; // sets the line-height of the icon back to that of it's parent - vertical-align: (fa-divide(6, $font-size) - fa-divide(3, 8)) * 1em; // vertically centers the icon taking into account the surrounding text's descender -} - -// only display content to screen readers -// see: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ -// see: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/ -@mixin fa-sr-only() { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; -} - -// use in conjunction with .sr-only to only display content when it's focused -@mixin fa-sr-only-focusable() { - &:not(:focus) { - @include fa-sr-only(); - } -} - -// sets a specific icon family to use alongside style + icon mixins - -// convenience mixins for declaring pseudo-elements by CSS variable, -// including all style-specific font properties, and both the ::before -// and ::after elements in the duotone case. -@mixin fa-icon-solid($fa-var) { - @extend %fa-icon; - @extend .fa-solid; - - &::before { - content: unquote("\"#{ $fa-var }\""); - } -} - -@mixin fa-icon-regular($fa-var) { - @extend %fa-icon; - @extend .fa-regular; - - &::before { - content: unquote("\"#{ $fa-var }\""); - } -} - -@mixin fa-icon-brands($fa-var) { - @extend %fa-icon; - @extend .fa-brands; - - &::before { - content: unquote("\"#{ $fa-var }\""); - } -} - diff --git a/public/vendor/fontawesome/scss/_rotated-flipped.scss b/public/vendor/fontawesome/scss/_rotated-flipped.scss deleted file mode 100644 index f27fabee40..0000000000 --- a/public/vendor/fontawesome/scss/_rotated-flipped.scss +++ /dev/null @@ -1,31 +0,0 @@ -// rotating + flipping icons -// ------------------------- - -.#{$fa-css-prefix}-rotate-90 { - transform: rotate(90deg); -} - -.#{$fa-css-prefix}-rotate-180 { - transform: rotate(180deg); -} - -.#{$fa-css-prefix}-rotate-270 { - transform: rotate(270deg); -} - -.#{$fa-css-prefix}-flip-horizontal { - transform: scale(-1, 1); -} - -.#{$fa-css-prefix}-flip-vertical { - transform: scale(1, -1); -} - -.#{$fa-css-prefix}-flip-both, -.#{$fa-css-prefix}-flip-horizontal.#{$fa-css-prefix}-flip-vertical { - transform: scale(-1, -1); -} - -.#{$fa-css-prefix}-rotate-by { - transform: rotate(var(--#{$fa-css-prefix}-rotate-angle, none)); -} diff --git a/public/vendor/fontawesome/scss/_screen-reader.scss b/public/vendor/fontawesome/scss/_screen-reader.scss deleted file mode 100644 index 2beb887b49..0000000000 --- a/public/vendor/fontawesome/scss/_screen-reader.scss +++ /dev/null @@ -1,14 +0,0 @@ -// screen-reader utilities -// ------------------------- - -// only display content to screen readers -.sr-only, -.#{$fa-css-prefix}-sr-only { - @include fa-sr-only; -} - -// use in conjunction with .sr-only to only display content when it's focused -.sr-only-focusable, -.#{$fa-css-prefix}-sr-only-focusable { - @include fa-sr-only-focusable; -} diff --git a/public/vendor/fontawesome/scss/_shims.scss b/public/vendor/fontawesome/scss/_shims.scss deleted file mode 100644 index 7809aa6490..0000000000 --- a/public/vendor/fontawesome/scss/_shims.scss +++ /dev/null @@ -1,2042 +0,0 @@ -.#{$fa-css-prefix}.#{$fa-css-prefix}-glass:before { content: unquote("\"#{ $fa-var-martini-glass-empty }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-o:before { content: unquote("\"#{ $fa-var-envelope }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-o:before { content: unquote("\"#{ $fa-var-star }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-remove:before { content: unquote("\"#{ $fa-var-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-close:before { content: unquote("\"#{ $fa-var-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gear:before { content: unquote("\"#{ $fa-var-gear }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-trash-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-trash-o:before { content: unquote("\"#{ $fa-var-trash-can }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-home:before { content: unquote("\"#{ $fa-var-house }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-o:before { content: unquote("\"#{ $fa-var-file }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-clock-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-clock-o:before { content: unquote("\"#{ $fa-var-clock }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-down:before { content: unquote("\"#{ $fa-var-circle-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-up:before { content: unquote("\"#{ $fa-var-circle-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-play-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-play-circle-o:before { content: unquote("\"#{ $fa-var-circle-play }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-repeat:before { content: unquote("\"#{ $fa-var-arrow-rotate-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rotate-right:before { content: unquote("\"#{ $fa-var-arrow-rotate-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-refresh:before { content: unquote("\"#{ $fa-var-arrows-rotate }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-list-alt { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-list-alt:before { content: unquote("\"#{ $fa-var-rectangle-list }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dedent:before { content: unquote("\"#{ $fa-var-outdent }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-video-camera:before { content: unquote("\"#{ $fa-var-video }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-picture-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-picture-o:before { content: unquote("\"#{ $fa-var-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-photo { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-photo:before { content: unquote("\"#{ $fa-var-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-image { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-image:before { content: unquote("\"#{ $fa-var-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-map-marker:before { content: unquote("\"#{ $fa-var-location-dot }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square-o:before { content: unquote("\"#{ $fa-var-pen-to-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-edit { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-edit:before { content: unquote("\"#{ $fa-var-pen-to-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-share-square-o:before { content: unquote("\"#{ $fa-var-share-from-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-square-o:before { content: unquote("\"#{ $fa-var-square-check }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows:before { content: unquote("\"#{ $fa-var-up-down-left-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-circle-o:before { content: unquote("\"#{ $fa-var-circle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-check-circle-o:before { content: unquote("\"#{ $fa-var-circle-check }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-forward:before { content: unquote("\"#{ $fa-var-share }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-expand:before { content: unquote("\"#{ $fa-var-up-right-and-down-left-from-center }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-compress:before { content: unquote("\"#{ $fa-var-down-left-and-up-right-to-center }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eye { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eye-slash { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-warning:before { content: unquote("\"#{ $fa-var-triangle-exclamation }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar:before { content: unquote("\"#{ $fa-var-calendar-days }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-v:before { content: unquote("\"#{ $fa-var-up-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-h:before { content: unquote("\"#{ $fa-var-left-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bar-chart:before { content: unquote("\"#{ $fa-var-chart-column }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bar-chart-o:before { content: unquote("\"#{ $fa-var-chart-column }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter-square:before { content: unquote("\"#{ $fa-var-square-twitter }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-square:before { content: unquote("\"#{ $fa-var-square-facebook }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gears:before { content: unquote("\"#{ $fa-var-gears }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-up:before { content: unquote("\"#{ $fa-var-thumbs-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumbs-o-down:before { content: unquote("\"#{ $fa-var-thumbs-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-heart-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-heart-o:before { content: unquote("\"#{ $fa-var-heart }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sign-out:before { content: unquote("\"#{ $fa-var-right-from-bracket }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin-square:before { content: unquote("\"#{ $fa-var-linkedin }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thumb-tack:before { content: unquote("\"#{ $fa-var-thumbtack }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-external-link:before { content: unquote("\"#{ $fa-var-up-right-from-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sign-in:before { content: unquote("\"#{ $fa-var-right-to-bracket }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-github-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-github-square:before { content: unquote("\"#{ $fa-var-square-github }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lemon-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-lemon-o:before { content: unquote("\"#{ $fa-var-lemon }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-square-o:before { content: unquote("\"#{ $fa-var-square }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bookmark-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bookmark-o:before { content: unquote("\"#{ $fa-var-bookmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitter { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook:before { content: unquote("\"#{ $fa-var-facebook-f }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-f { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-f:before { content: unquote("\"#{ $fa-var-facebook-f }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-github { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-credit-card { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-feed:before { content: unquote("\"#{ $fa-var-rss }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hdd-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hdd-o:before { content: unquote("\"#{ $fa-var-hard-drive }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-right:before { content: unquote("\"#{ $fa-var-hand-point-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-left:before { content: unquote("\"#{ $fa-var-hand-point-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-up:before { content: unquote("\"#{ $fa-var-hand-point-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-o-down:before { content: unquote("\"#{ $fa-var-hand-point-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-globe:before { content: unquote("\"#{ $fa-var-earth-americas }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tasks:before { content: unquote("\"#{ $fa-var-bars-progress }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrows-alt:before { content: unquote("\"#{ $fa-var-maximize }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-group:before { content: unquote("\"#{ $fa-var-users }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-chain:before { content: unquote("\"#{ $fa-var-link }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cut:before { content: unquote("\"#{ $fa-var-scissors }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-files-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-files-o:before { content: unquote("\"#{ $fa-var-copy }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-floppy-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-floppy-o:before { content: unquote("\"#{ $fa-var-floppy-disk }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-save { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-save:before { content: unquote("\"#{ $fa-var-floppy-disk }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-navicon:before { content: unquote("\"#{ $fa-var-bars }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reorder:before { content: unquote("\"#{ $fa-var-bars }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-magic:before { content: unquote("\"#{ $fa-var-wand-magic-sparkles }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-square:before { content: unquote("\"#{ $fa-var-square-pinterest }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-square:before { content: unquote("\"#{ $fa-var-square-google-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus:before { content: unquote("\"#{ $fa-var-google-plus-g }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-money:before { content: unquote("\"#{ $fa-var-money-bill-1 }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-unsorted:before { content: unquote("\"#{ $fa-var-sort }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-desc:before { content: unquote("\"#{ $fa-var-sort-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-asc:before { content: unquote("\"#{ $fa-var-sort-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-linkedin:before { content: unquote("\"#{ $fa-var-linkedin-in }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rotate-left:before { content: unquote("\"#{ $fa-var-arrow-rotate-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-legal:before { content: unquote("\"#{ $fa-var-gavel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tachometer:before { content: unquote("\"#{ $fa-var-gauge-high }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dashboard:before { content: unquote("\"#{ $fa-var-gauge-high }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-comment-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-comment-o:before { content: unquote("\"#{ $fa-var-comment }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-comments-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-comments-o:before { content: unquote("\"#{ $fa-var-comments }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-flash:before { content: unquote("\"#{ $fa-var-bolt }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-clipboard:before { content: unquote("\"#{ $fa-var-paste }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lightbulb-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-lightbulb-o:before { content: unquote("\"#{ $fa-var-lightbulb }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-exchange:before { content: unquote("\"#{ $fa-var-right-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cloud-download:before { content: unquote("\"#{ $fa-var-cloud-arrow-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cloud-upload:before { content: unquote("\"#{ $fa-var-cloud-arrow-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-o:before { content: unquote("\"#{ $fa-var-bell }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cutlery:before { content: unquote("\"#{ $fa-var-utensils }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text-o:before { content: unquote("\"#{ $fa-var-file-lines }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-building-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-building-o:before { content: unquote("\"#{ $fa-var-building }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hospital-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hospital-o:before { content: unquote("\"#{ $fa-var-hospital }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tablet:before { content: unquote("\"#{ $fa-var-tablet-screen-button }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mobile:before { content: unquote("\"#{ $fa-var-mobile-screen-button }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mobile-phone:before { content: unquote("\"#{ $fa-var-mobile-screen-button }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o:before { content: unquote("\"#{ $fa-var-circle }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-reply:before { content: unquote("\"#{ $fa-var-reply }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-github-alt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-o:before { content: unquote("\"#{ $fa-var-folder }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-open-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-folder-open-o:before { content: unquote("\"#{ $fa-var-folder-open }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-smile-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-smile-o:before { content: unquote("\"#{ $fa-var-face-smile }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-frown-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-frown-o:before { content: unquote("\"#{ $fa-var-face-frown }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-meh-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-meh-o:before { content: unquote("\"#{ $fa-var-face-meh }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-keyboard-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-keyboard-o:before { content: unquote("\"#{ $fa-var-keyboard }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-flag-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-flag-o:before { content: unquote("\"#{ $fa-var-flag }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mail-reply-all:before { content: unquote("\"#{ $fa-var-reply-all }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-o:before { content: unquote("\"#{ $fa-var-star-half-stroke }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-empty { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-empty:before { content: unquote("\"#{ $fa-var-star-half-stroke }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-full { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-star-half-full:before { content: unquote("\"#{ $fa-var-star-half-stroke }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-code-fork:before { content: unquote("\"#{ $fa-var-code-branch }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-chain-broken:before { content: unquote("\"#{ $fa-var-link-slash }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-unlink:before { content: unquote("\"#{ $fa-var-link-slash }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-o:before { content: unquote("\"#{ $fa-var-calendar }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-maxcdn { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-html5 { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-css3 { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-unlock-alt:before { content: unquote("\"#{ $fa-var-unlock }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-minus-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-minus-square-o:before { content: unquote("\"#{ $fa-var-square-minus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-level-up:before { content: unquote("\"#{ $fa-var-turn-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-level-down:before { content: unquote("\"#{ $fa-var-turn-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pencil-square:before { content: unquote("\"#{ $fa-var-square-pen }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-external-link-square:before { content: unquote("\"#{ $fa-var-square-up-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-compass { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-down:before { content: unquote("\"#{ $fa-var-square-caret-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-down { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-down:before { content: unquote("\"#{ $fa-var-square-caret-down }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-up:before { content: unquote("\"#{ $fa-var-square-caret-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-up { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-up:before { content: unquote("\"#{ $fa-var-square-caret-up }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-right:before { content: unquote("\"#{ $fa-var-square-caret-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-right:before { content: unquote("\"#{ $fa-var-square-caret-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eur:before { content: unquote("\"#{ $fa-var-euro-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-euro:before { content: unquote("\"#{ $fa-var-euro-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gbp:before { content: unquote("\"#{ $fa-var-sterling-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-usd:before { content: unquote("\"#{ $fa-var-dollar-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dollar:before { content: unquote("\"#{ $fa-var-dollar-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-inr:before { content: unquote("\"#{ $fa-var-indian-rupee-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rupee:before { content: unquote("\"#{ $fa-var-indian-rupee-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-jpy:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cny:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rmb:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yen:before { content: unquote("\"#{ $fa-var-yen-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rub:before { content: unquote("\"#{ $fa-var-ruble-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ruble:before { content: unquote("\"#{ $fa-var-ruble-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rouble:before { content: unquote("\"#{ $fa-var-ruble-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-krw:before { content: unquote("\"#{ $fa-var-won-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-won:before { content: unquote("\"#{ $fa-var-won-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-btc { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitcoin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitcoin:before { content: unquote("\"#{ $fa-var-btc }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-text:before { content: unquote("\"#{ $fa-var-file-lines }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-alpha-asc:before { content: unquote("\"#{ $fa-var-arrow-down-a-z }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-alpha-desc:before { content: unquote("\"#{ $fa-var-arrow-down-z-a }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-amount-asc:before { content: unquote("\"#{ $fa-var-arrow-down-short-wide }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-amount-desc:before { content: unquote("\"#{ $fa-var-arrow-down-wide-short }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-numeric-asc:before { content: unquote("\"#{ $fa-var-arrow-down-1-9 }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sort-numeric-desc:before { content: unquote("\"#{ $fa-var-arrow-down-9-1 }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-square:before { content: unquote("\"#{ $fa-var-square-youtube }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-xing { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-xing-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-xing-square:before { content: unquote("\"#{ $fa-var-square-xing }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-play { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-youtube-play:before { content: unquote("\"#{ $fa-var-youtube }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dropbox { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stack-overflow { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-instagram { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-flickr { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-adn { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bitbucket-square:before { content: unquote("\"#{ $fa-var-bitbucket }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-tumblr-square:before { content: unquote("\"#{ $fa-var-square-tumblr }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-down:before { content: unquote("\"#{ $fa-var-down-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-up:before { content: unquote("\"#{ $fa-var-up-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-left:before { content: unquote("\"#{ $fa-var-left-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-long-arrow-right:before { content: unquote("\"#{ $fa-var-right-long }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-apple { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-windows { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-android { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linux { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dribbble { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-skype { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-foursquare { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-trello { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gratipay { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gittip { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-gittip:before { content: unquote("\"#{ $fa-var-gratipay }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sun-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-sun-o:before { content: unquote("\"#{ $fa-var-sun }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-moon-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-moon-o:before { content: unquote("\"#{ $fa-var-moon }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vk { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-weibo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-renren { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pagelines { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stack-exchange { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-right { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-right:before { content: unquote("\"#{ $fa-var-circle-right }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-arrow-circle-o-left:before { content: unquote("\"#{ $fa-var-circle-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-caret-square-o-left:before { content: unquote("\"#{ $fa-var-square-caret-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-left { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-toggle-left:before { content: unquote("\"#{ $fa-var-square-caret-left }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dot-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-dot-circle-o:before { content: unquote("\"#{ $fa-var-circle-dot }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo-square:before { content: unquote("\"#{ $fa-var-square-vimeo }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-try:before { content: unquote("\"#{ $fa-var-turkish-lira-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-turkish-lira:before { content: unquote("\"#{ $fa-var-turkish-lira-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-plus-square-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-plus-square-o:before { content: unquote("\"#{ $fa-var-square-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-slack { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wordpress { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-openid { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-institution:before { content: unquote("\"#{ $fa-var-building-columns }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bank:before { content: unquote("\"#{ $fa-var-building-columns }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mortar-board:before { content: unquote("\"#{ $fa-var-graduation-cap }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yahoo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-square:before { content: unquote("\"#{ $fa-var-square-reddit }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stumbleupon-circle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stumbleupon { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-delicious { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-digg { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper-pp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper-alt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-drupal { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-joomla { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-behance { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-behance-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-behance-square:before { content: unquote("\"#{ $fa-var-square-behance }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-steam { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-steam-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-steam-square:before { content: unquote("\"#{ $fa-var-square-steam }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-automobile:before { content: unquote("\"#{ $fa-var-car }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cab:before { content: unquote("\"#{ $fa-var-taxi }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-spotify { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-deviantart { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-soundcloud { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-pdf-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-pdf-o:before { content: unquote("\"#{ $fa-var-file-pdf }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-word-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-word-o:before { content: unquote("\"#{ $fa-var-file-word }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-excel-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-excel-o:before { content: unquote("\"#{ $fa-var-file-excel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-powerpoint-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-powerpoint-o:before { content: unquote("\"#{ $fa-var-file-powerpoint }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-image-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-image-o:before { content: unquote("\"#{ $fa-var-file-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-photo-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-photo-o:before { content: unquote("\"#{ $fa-var-file-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-picture-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-picture-o:before { content: unquote("\"#{ $fa-var-file-image }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-archive-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-archive-o:before { content: unquote("\"#{ $fa-var-file-zipper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-zip-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-zip-o:before { content: unquote("\"#{ $fa-var-file-zipper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-audio-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-audio-o:before { content: unquote("\"#{ $fa-var-file-audio }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-sound-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-sound-o:before { content: unquote("\"#{ $fa-var-file-audio }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-video-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-video-o:before { content: unquote("\"#{ $fa-var-file-video }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-movie-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-movie-o:before { content: unquote("\"#{ $fa-var-file-video }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-code-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-file-code-o:before { content: unquote("\"#{ $fa-var-file-code }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vine { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-codepen { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-jsfiddle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-life-bouy:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-life-buoy:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-life-saver:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-support:before { content: unquote("\"#{ $fa-var-life-ring }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-o-notch:before { content: unquote("\"#{ $fa-var-circle-notch }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-rebel { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ra { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-ra:before { content: unquote("\"#{ $fa-var-rebel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-resistance { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-resistance:before { content: unquote("\"#{ $fa-var-rebel }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-empire { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ge { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-ge:before { content: unquote("\"#{ $fa-var-empire }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-git-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-git-square:before { content: unquote("\"#{ $fa-var-square-git }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-git { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hacker-news { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator-square:before { content: unquote("\"#{ $fa-var-hacker-news }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc-square:before { content: unquote("\"#{ $fa-var-hacker-news }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-tencent-weibo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-qq { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-weixin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wechat { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-wechat:before { content: unquote("\"#{ $fa-var-weixin }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-send:before { content: unquote("\"#{ $fa-var-paper-plane }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-paper-plane-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-paper-plane-o:before { content: unquote("\"#{ $fa-var-paper-plane }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-send-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-send-o:before { content: unquote("\"#{ $fa-var-paper-plane }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-thin { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-circle-thin:before { content: unquote("\"#{ $fa-var-circle }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-header:before { content: unquote("\"#{ $fa-var-heading }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-futbol-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-futbol-o:before { content: unquote("\"#{ $fa-var-futbol }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-soccer-ball-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-soccer-ball-o:before { content: unquote("\"#{ $fa-var-futbol }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-slideshare { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-twitch { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yelp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-newspaper-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-newspaper-o:before { content: unquote("\"#{ $fa-var-newspaper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-paypal { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-wallet { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-visa { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-mastercard { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-discover { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-amex { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-paypal { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-stripe { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-slash-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-bell-slash-o:before { content: unquote("\"#{ $fa-var-bell-slash }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-trash:before { content: unquote("\"#{ $fa-var-trash-can }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-copyright { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eyedropper:before { content: unquote("\"#{ $fa-var-eye-dropper }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-area-chart:before { content: unquote("\"#{ $fa-var-chart-area }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pie-chart:before { content: unquote("\"#{ $fa-var-chart-pie }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-line-chart:before { content: unquote("\"#{ $fa-var-chart-line }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-lastfm-square:before { content: unquote("\"#{ $fa-var-square-lastfm }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ioxhost { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-angellist { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc:before { content: unquote("\"#{ $fa-var-closed-captioning }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ils:before { content: unquote("\"#{ $fa-var-shekel-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-shekel:before { content: unquote("\"#{ $fa-var-shekel-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sheqel:before { content: unquote("\"#{ $fa-var-shekel-sign }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-buysellads { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-connectdevelop { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-dashcube { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-forumbee { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-leanpub { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sellsy { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-shirtsinbulk { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-simplybuilt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-skyatlas { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-diamond { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-diamond:before { content: unquote("\"#{ $fa-var-gem }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-transgender:before { content: unquote("\"#{ $fa-var-mars-and-venus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-intersex:before { content: unquote("\"#{ $fa-var-mars-and-venus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-transgender-alt:before { content: unquote("\"#{ $fa-var-transgender }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-official { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-facebook-official:before { content: unquote("\"#{ $fa-var-facebook }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pinterest-p { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-whatsapp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hotel:before { content: unquote("\"#{ $fa-var-bed }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-viacoin { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-medium { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-y-combinator { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-yc:before { content: unquote("\"#{ $fa-var-y-combinator }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-optin-monster { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-opencart { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-expeditedssl { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-4:before { content: unquote("\"#{ $fa-var-battery-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery:before { content: unquote("\"#{ $fa-var-battery-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-3:before { content: unquote("\"#{ $fa-var-battery-three-quarters }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-2:before { content: unquote("\"#{ $fa-var-battery-half }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-1:before { content: unquote("\"#{ $fa-var-battery-quarter }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-battery-0:before { content: unquote("\"#{ $fa-var-battery-empty }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-object-group { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-object-ungroup { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-sticky-note-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-sticky-note-o:before { content: unquote("\"#{ $fa-var-note-sticky }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-jcb { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-cc-diners-club { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-clone { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-o:before { content: unquote("\"#{ $fa-var-hourglass }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-1:before { content: unquote("\"#{ $fa-var-hourglass-start }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-2:before { content: unquote("\"#{ $fa-var-hourglass-half }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hourglass-3:before { content: unquote("\"#{ $fa-var-hourglass-end }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-rock-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-rock-o:before { content: unquote("\"#{ $fa-var-hand-back-fist }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-grab-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-grab-o:before { content: unquote("\"#{ $fa-var-hand-back-fist }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-paper-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-paper-o:before { content: unquote("\"#{ $fa-var-hand }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-stop-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-stop-o:before { content: unquote("\"#{ $fa-var-hand }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-scissors-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-scissors-o:before { content: unquote("\"#{ $fa-var-hand-scissors }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-lizard-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-lizard-o:before { content: unquote("\"#{ $fa-var-hand-lizard }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-spock-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-spock-o:before { content: unquote("\"#{ $fa-var-hand-spock }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-pointer-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-pointer-o:before { content: unquote("\"#{ $fa-var-hand-pointer }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-peace-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-hand-peace-o:before { content: unquote("\"#{ $fa-var-hand-peace }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-registered { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-creative-commons { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gg { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gg-circle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-odnoklassniki-square:before { content: unquote("\"#{ $fa-var-square-odnoklassniki }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-get-pocket { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wikipedia-w { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-safari { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-chrome { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-firefox { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-opera { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-internet-explorer { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-television:before { content: unquote("\"#{ $fa-var-tv }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-contao { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-500px { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-amazon { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-plus-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-plus-o:before { content: unquote("\"#{ $fa-var-calendar-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-minus-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-minus-o:before { content: unquote("\"#{ $fa-var-calendar-minus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-times-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-times-o:before { content: unquote("\"#{ $fa-var-calendar-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-check-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-calendar-check-o:before { content: unquote("\"#{ $fa-var-calendar-check }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-map-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-map-o:before { content: unquote("\"#{ $fa-var-map }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting:before { content: unquote("\"#{ $fa-var-comment-dots }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-commenting-o:before { content: unquote("\"#{ $fa-var-comment-dots }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-houzz { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-vimeo:before { content: unquote("\"#{ $fa-var-vimeo-v }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-black-tie { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-fonticons { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-reddit-alien { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-edge { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-credit-card-alt:before { content: unquote("\"#{ $fa-var-credit-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-codiepie { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-modx { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-fort-awesome { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-usb { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-product-hunt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-mixcloud { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-scribd { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pause-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-pause-circle-o:before { content: unquote("\"#{ $fa-var-circle-pause }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-stop-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-stop-circle-o:before { content: unquote("\"#{ $fa-var-circle-stop }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bluetooth { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bluetooth-b { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-gitlab { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wpbeginner { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wpforms { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-envira { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wheelchair-alt { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-wheelchair-alt:before { content: unquote("\"#{ $fa-var-accessible-icon }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-question-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-question-circle-o:before { content: unquote("\"#{ $fa-var-circle-question }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-volume-control-phone:before { content: unquote("\"#{ $fa-var-phone-volume }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-asl-interpreting:before { content: unquote("\"#{ $fa-var-hands-asl-interpreting }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-deafness:before { content: unquote("\"#{ $fa-var-ear-deaf }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-hard-of-hearing:before { content: unquote("\"#{ $fa-var-ear-deaf }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-glide { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-glide-g { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-signing:before { content: unquote("\"#{ $fa-var-hands }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-viadeo-square:before { content: unquote("\"#{ $fa-var-square-viadeo }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-ghost { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-ghost:before { content: unquote("\"#{ $fa-var-snapchat }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-square { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-snapchat-square:before { content: unquote("\"#{ $fa-var-square-snapchat }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-pied-piper { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-first-order { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-yoast { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-themeisle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-official { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-official:before { content: unquote("\"#{ $fa-var-google-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-circle { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-google-plus-circle:before { content: unquote("\"#{ $fa-var-google-plus }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-font-awesome { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-fa { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-fa:before { content: unquote("\"#{ $fa-var-font-awesome }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-handshake-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-handshake-o:before { content: unquote("\"#{ $fa-var-handshake }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-open-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-envelope-open-o:before { content: unquote("\"#{ $fa-var-envelope-open }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-linode { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-book-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-book-o:before { content: unquote("\"#{ $fa-var-address-book }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard:before { content: unquote("\"#{ $fa-var-address-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-card-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-address-card-o:before { content: unquote("\"#{ $fa-var-address-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-vcard-o:before { content: unquote("\"#{ $fa-var-address-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-circle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-circle-o:before { content: unquote("\"#{ $fa-var-circle-user }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-user-o:before { content: unquote("\"#{ $fa-var-user }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-id-badge { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license:before { content: unquote("\"#{ $fa-var-id-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-id-card-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-id-card-o:before { content: unquote("\"#{ $fa-var-id-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-drivers-license-o:before { content: unquote("\"#{ $fa-var-id-card }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-quora { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-free-code-camp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-telegram { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-4:before { content: unquote("\"#{ $fa-var-temperature-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer:before { content: unquote("\"#{ $fa-var-temperature-full }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-3:before { content: unquote("\"#{ $fa-var-temperature-three-quarters }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-2:before { content: unquote("\"#{ $fa-var-temperature-half }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-1:before { content: unquote("\"#{ $fa-var-temperature-quarter }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-thermometer-0:before { content: unquote("\"#{ $fa-var-temperature-empty }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bathtub:before { content: unquote("\"#{ $fa-var-bath }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-s15:before { content: unquote("\"#{ $fa-var-bath }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-maximize { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-restore { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle:before { content: unquote("\"#{ $fa-var-rectangle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-close-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-window-close-o:before { content: unquote("\"#{ $fa-var-rectangle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-times-rectangle-o:before { content: unquote("\"#{ $fa-var-rectangle-xmark }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-bandcamp { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-grav { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-etsy { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-imdb { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-ravelry { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-eercast { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-eercast:before { content: unquote("\"#{ $fa-var-sellcast }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-snowflake-o { - font-family: 'Font Awesome 6 Free'; - font-weight: 400; -} -.#{$fa-css-prefix}.#{$fa-css-prefix}-snowflake-o:before { content: unquote("\"#{ $fa-var-snowflake }\""); } - -.#{$fa-css-prefix}.#{$fa-css-prefix}-superpowers { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-wpexplorer { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - -.#{$fa-css-prefix}.#{$fa-css-prefix}-meetup { - font-family: 'Font Awesome 6 Brands'; - font-weight: 400; -} - diff --git a/public/vendor/fontawesome/scss/_sizing.scss b/public/vendor/fontawesome/scss/_sizing.scss deleted file mode 100644 index e171e7df4c..0000000000 --- a/public/vendor/fontawesome/scss/_sizing.scss +++ /dev/null @@ -1,16 +0,0 @@ -// sizing icons -// ------------------------- - -// literal magnification scale -@for $i from 1 through 10 { - .#{$fa-css-prefix}-#{$i}x { - font-size: $i * 1em; - } -} - -// step-based scale (with alignment) -@each $size, $value in $fa-sizes { - .#{$fa-css-prefix}-#{$size} { - @include fa-size($value); - } -} diff --git a/public/vendor/fontawesome/scss/_stacked.scss b/public/vendor/fontawesome/scss/_stacked.scss deleted file mode 100644 index d9a9d4e98f..0000000000 --- a/public/vendor/fontawesome/scss/_stacked.scss +++ /dev/null @@ -1,32 +0,0 @@ -// stacking icons -// ------------------------- - -.#{$fa-css-prefix}-stack { - display: inline-block; - height: 2em; - line-height: 2em; - position: relative; - vertical-align: $fa-stack-vertical-align; - width: $fa-stack-width; -} - -.#{$fa-css-prefix}-stack-1x, -.#{$fa-css-prefix}-stack-2x { - left: 0; - position: absolute; - text-align: center; - width: 100%; - z-index: var(--#{$fa-css-prefix}-stack-z-index, #{$fa-stack-z-index}); -} - -.#{$fa-css-prefix}-stack-1x { - line-height: inherit; -} - -.#{$fa-css-prefix}-stack-2x { - font-size: 2em; -} - -.#{$fa-css-prefix}-inverse { - color: var(--#{$fa-css-prefix}-inverse, #{$fa-inverse}); -} diff --git a/public/vendor/fontawesome/scss/_variables.scss b/public/vendor/fontawesome/scss/_variables.scss deleted file mode 100644 index e3a920deab..0000000000 --- a/public/vendor/fontawesome/scss/_variables.scss +++ /dev/null @@ -1,4951 +0,0 @@ -// variables -// -------------------------- - -$fa-css-prefix : fa !default; -$fa-style : 900 !default; -$fa-style-family : "Font Awesome 6 Free" !default; - -$fa-display : inline-block !default; - -$fa-fw-width : fa-divide(20em, 16) !default; -$fa-inverse : #fff !default; - -$fa-border-color : #eee !default; -$fa-border-padding : .2em .25em .15em !default; -$fa-border-radius : .1em !default; -$fa-border-style : solid !default; -$fa-border-width : .08em !default; - -$fa-size-scale-2xs : 10 !default; -$fa-size-scale-xs : 12 !default; -$fa-size-scale-sm : 14 !default; -$fa-size-scale-base : 16 !default; -$fa-size-scale-lg : 20 !default; -$fa-size-scale-xl : 24 !default; -$fa-size-scale-2xl : 32 !default; - -$fa-sizes: ( - "2xs" : $fa-size-scale-2xs, - "xs" : $fa-size-scale-xs, - "sm" : $fa-size-scale-sm, - "lg" : $fa-size-scale-lg, - "xl" : $fa-size-scale-xl, - "2xl" : $fa-size-scale-2xl -) !default; - -$fa-li-width : 2em !default; -$fa-li-margin : $fa-li-width * fa-divide(5, 4) !default; - -$fa-pull-margin : .3em !default; - -$fa-primary-opacity : 1 !default; -$fa-secondary-opacity : .4 !default; - -$fa-stack-vertical-align: middle !default; -$fa-stack-width : ($fa-fw-width * 2) !default; -$fa-stack-z-index : auto !default; - -$fa-font-display : block !default; -$fa-font-path : "../webfonts" !default; - -$fa-var-0: \30; -$fa-var-1: \31; -$fa-var-2: \32; -$fa-var-3: \33; -$fa-var-4: \34; -$fa-var-5: \35; -$fa-var-6: \36; -$fa-var-7: \37; -$fa-var-8: \38; -$fa-var-9: \39; -$fa-var-fill-drip: \f576; -$fa-var-arrows-to-circle: \e4bd; -$fa-var-circle-chevron-right: \f138; -$fa-var-chevron-circle-right: \f138; -$fa-var-at: \40; -$fa-var-trash-can: \f2ed; -$fa-var-trash-alt: \f2ed; -$fa-var-text-height: \f034; -$fa-var-user-xmark: \f235; -$fa-var-user-times: \f235; -$fa-var-stethoscope: \f0f1; -$fa-var-message: \f27a; -$fa-var-comment-alt: \f27a; -$fa-var-info: \f129; -$fa-var-down-left-and-up-right-to-center: \f422; -$fa-var-compress-alt: \f422; -$fa-var-explosion: \e4e9; -$fa-var-file-lines: \f15c; -$fa-var-file-alt: \f15c; -$fa-var-file-text: \f15c; -$fa-var-wave-square: \f83e; -$fa-var-ring: \f70b; -$fa-var-building-un: \e4d9; -$fa-var-dice-three: \f527; -$fa-var-calendar-days: \f073; -$fa-var-calendar-alt: \f073; -$fa-var-anchor-circle-check: \e4aa; -$fa-var-building-circle-arrow-right: \e4d1; -$fa-var-volleyball: \f45f; -$fa-var-volleyball-ball: \f45f; -$fa-var-arrows-up-to-line: \e4c2; -$fa-var-sort-down: \f0dd; -$fa-var-sort-desc: \f0dd; -$fa-var-circle-minus: \f056; -$fa-var-minus-circle: \f056; -$fa-var-door-open: \f52b; -$fa-var-right-from-bracket: \f2f5; -$fa-var-sign-out-alt: \f2f5; -$fa-var-atom: \f5d2; -$fa-var-soap: \e06e; -$fa-var-icons: \f86d; -$fa-var-heart-music-camera-bolt: \f86d; -$fa-var-microphone-lines-slash: \f539; -$fa-var-microphone-alt-slash: \f539; -$fa-var-bridge-circle-check: \e4c9; -$fa-var-pump-medical: \e06a; -$fa-var-fingerprint: \f577; -$fa-var-hand-point-right: \f0a4; -$fa-var-magnifying-glass-location: \f689; -$fa-var-search-location: \f689; -$fa-var-forward-step: \f051; -$fa-var-step-forward: \f051; -$fa-var-face-smile-beam: \f5b8; -$fa-var-smile-beam: \f5b8; -$fa-var-flag-checkered: \f11e; -$fa-var-football: \f44e; -$fa-var-football-ball: \f44e; -$fa-var-school-circle-exclamation: \e56c; -$fa-var-crop: \f125; -$fa-var-angles-down: \f103; -$fa-var-angle-double-down: \f103; -$fa-var-users-rectangle: \e594; -$fa-var-people-roof: \e537; -$fa-var-people-line: \e534; -$fa-var-beer-mug-empty: \f0fc; -$fa-var-beer: \f0fc; -$fa-var-diagram-predecessor: \e477; -$fa-var-arrow-up-long: \f176; -$fa-var-long-arrow-up: \f176; -$fa-var-fire-flame-simple: \f46a; -$fa-var-burn: \f46a; -$fa-var-person: \f183; -$fa-var-male: \f183; -$fa-var-laptop: \f109; -$fa-var-file-csv: \f6dd; -$fa-var-menorah: \f676; -$fa-var-truck-plane: \e58f; -$fa-var-record-vinyl: \f8d9; -$fa-var-face-grin-stars: \f587; -$fa-var-grin-stars: \f587; -$fa-var-bong: \f55c; -$fa-var-spaghetti-monster-flying: \f67b; -$fa-var-pastafarianism: \f67b; -$fa-var-arrow-down-up-across-line: \e4af; -$fa-var-spoon: \f2e5; -$fa-var-utensil-spoon: \f2e5; -$fa-var-jar-wheat: \e517; -$fa-var-envelopes-bulk: \f674; -$fa-var-mail-bulk: \f674; -$fa-var-file-circle-exclamation: \e4eb; -$fa-var-circle-h: \f47e; -$fa-var-hospital-symbol: \f47e; -$fa-var-pager: \f815; -$fa-var-address-book: \f2b9; -$fa-var-contact-book: \f2b9; -$fa-var-strikethrough: \f0cc; -$fa-var-k: \4b; -$fa-var-landmark-flag: \e51c; -$fa-var-pencil: \f303; -$fa-var-pencil-alt: \f303; -$fa-var-backward: \f04a; -$fa-var-caret-right: \f0da; -$fa-var-comments: \f086; -$fa-var-paste: \f0ea; -$fa-var-file-clipboard: \f0ea; -$fa-var-code-pull-request: \e13c; -$fa-var-clipboard-list: \f46d; -$fa-var-truck-ramp-box: \f4de; -$fa-var-truck-loading: \f4de; -$fa-var-user-check: \f4fc; -$fa-var-vial-virus: \e597; -$fa-var-sheet-plastic: \e571; -$fa-var-blog: \f781; -$fa-var-user-ninja: \f504; -$fa-var-person-arrow-up-from-line: \e539; -$fa-var-scroll-torah: \f6a0; -$fa-var-torah: \f6a0; -$fa-var-broom-ball: \f458; -$fa-var-quidditch: \f458; -$fa-var-quidditch-broom-ball: \f458; -$fa-var-toggle-off: \f204; -$fa-var-box-archive: \f187; -$fa-var-archive: \f187; -$fa-var-person-drowning: \e545; -$fa-var-arrow-down-9-1: \f886; -$fa-var-sort-numeric-desc: \f886; -$fa-var-sort-numeric-down-alt: \f886; -$fa-var-face-grin-tongue-squint: \f58a; -$fa-var-grin-tongue-squint: \f58a; -$fa-var-spray-can: \f5bd; -$fa-var-truck-monster: \f63b; -$fa-var-w: \57; -$fa-var-earth-africa: \f57c; -$fa-var-globe-africa: \f57c; -$fa-var-rainbow: \f75b; -$fa-var-circle-notch: \f1ce; -$fa-var-tablet-screen-button: \f3fa; -$fa-var-tablet-alt: \f3fa; -$fa-var-paw: \f1b0; -$fa-var-cloud: \f0c2; -$fa-var-trowel-bricks: \e58a; -$fa-var-face-flushed: \f579; -$fa-var-flushed: \f579; -$fa-var-hospital-user: \f80d; -$fa-var-tent-arrow-left-right: \e57f; -$fa-var-gavel: \f0e3; -$fa-var-legal: \f0e3; -$fa-var-binoculars: \f1e5; -$fa-var-microphone-slash: \f131; -$fa-var-box-tissue: \e05b; -$fa-var-motorcycle: \f21c; -$fa-var-bell-concierge: \f562; -$fa-var-concierge-bell: \f562; -$fa-var-pen-ruler: \f5ae; -$fa-var-pencil-ruler: \f5ae; -$fa-var-people-arrows: \e068; -$fa-var-people-arrows-left-right: \e068; -$fa-var-mars-and-venus-burst: \e523; -$fa-var-square-caret-right: \f152; -$fa-var-caret-square-right: \f152; -$fa-var-scissors: \f0c4; -$fa-var-cut: \f0c4; -$fa-var-sun-plant-wilt: \e57a; -$fa-var-toilets-portable: \e584; -$fa-var-hockey-puck: \f453; -$fa-var-table: \f0ce; -$fa-var-magnifying-glass-arrow-right: \e521; -$fa-var-tachograph-digital: \f566; -$fa-var-digital-tachograph: \f566; -$fa-var-users-slash: \e073; -$fa-var-clover: \e139; -$fa-var-reply: \f3e5; -$fa-var-mail-reply: \f3e5; -$fa-var-star-and-crescent: \f699; -$fa-var-house-fire: \e50c; -$fa-var-square-minus: \f146; -$fa-var-minus-square: \f146; -$fa-var-helicopter: \f533; -$fa-var-compass: \f14e; -$fa-var-square-caret-down: \f150; -$fa-var-caret-square-down: \f150; -$fa-var-file-circle-question: \e4ef; -$fa-var-laptop-code: \f5fc; -$fa-var-swatchbook: \f5c3; -$fa-var-prescription-bottle: \f485; -$fa-var-bars: \f0c9; -$fa-var-navicon: \f0c9; -$fa-var-people-group: \e533; -$fa-var-hourglass-end: \f253; -$fa-var-hourglass-3: \f253; -$fa-var-heart-crack: \f7a9; -$fa-var-heart-broken: \f7a9; -$fa-var-square-up-right: \f360; -$fa-var-external-link-square-alt: \f360; -$fa-var-face-kiss-beam: \f597; -$fa-var-kiss-beam: \f597; -$fa-var-film: \f008; -$fa-var-ruler-horizontal: \f547; -$fa-var-people-robbery: \e536; -$fa-var-lightbulb: \f0eb; -$fa-var-caret-left: \f0d9; -$fa-var-circle-exclamation: \f06a; -$fa-var-exclamation-circle: \f06a; -$fa-var-school-circle-xmark: \e56d; -$fa-var-arrow-right-from-bracket: \f08b; -$fa-var-sign-out: \f08b; -$fa-var-circle-chevron-down: \f13a; -$fa-var-chevron-circle-down: \f13a; -$fa-var-unlock-keyhole: \f13e; -$fa-var-unlock-alt: \f13e; -$fa-var-cloud-showers-heavy: \f740; -$fa-var-headphones-simple: \f58f; -$fa-var-headphones-alt: \f58f; -$fa-var-sitemap: \f0e8; -$fa-var-circle-dollar-to-slot: \f4b9; -$fa-var-donate: \f4b9; -$fa-var-memory: \f538; -$fa-var-road-spikes: \e568; -$fa-var-fire-burner: \e4f1; -$fa-var-flag: \f024; -$fa-var-hanukiah: \f6e6; -$fa-var-feather: \f52d; -$fa-var-volume-low: \f027; -$fa-var-volume-down: \f027; -$fa-var-comment-slash: \f4b3; -$fa-var-cloud-sun-rain: \f743; -$fa-var-compress: \f066; -$fa-var-wheat-awn: \e2cd; -$fa-var-wheat-alt: \e2cd; -$fa-var-ankh: \f644; -$fa-var-hands-holding-child: \e4fa; -$fa-var-asterisk: \2a; -$fa-var-square-check: \f14a; -$fa-var-check-square: \f14a; -$fa-var-peseta-sign: \e221; -$fa-var-heading: \f1dc; -$fa-var-header: \f1dc; -$fa-var-ghost: \f6e2; -$fa-var-list: \f03a; -$fa-var-list-squares: \f03a; -$fa-var-square-phone-flip: \f87b; -$fa-var-phone-square-alt: \f87b; -$fa-var-cart-plus: \f217; -$fa-var-gamepad: \f11b; -$fa-var-circle-dot: \f192; -$fa-var-dot-circle: \f192; -$fa-var-face-dizzy: \f567; -$fa-var-dizzy: \f567; -$fa-var-egg: \f7fb; -$fa-var-house-medical-circle-xmark: \e513; -$fa-var-campground: \f6bb; -$fa-var-folder-plus: \f65e; -$fa-var-futbol: \f1e3; -$fa-var-futbol-ball: \f1e3; -$fa-var-soccer-ball: \f1e3; -$fa-var-paintbrush: \f1fc; -$fa-var-paint-brush: \f1fc; -$fa-var-lock: \f023; -$fa-var-gas-pump: \f52f; -$fa-var-hot-tub-person: \f593; -$fa-var-hot-tub: \f593; -$fa-var-map-location: \f59f; -$fa-var-map-marked: \f59f; -$fa-var-house-flood-water: \e50e; -$fa-var-tree: \f1bb; -$fa-var-bridge-lock: \e4cc; -$fa-var-sack-dollar: \f81d; -$fa-var-pen-to-square: \f044; -$fa-var-edit: \f044; -$fa-var-car-side: \f5e4; -$fa-var-share-nodes: \f1e0; -$fa-var-share-alt: \f1e0; -$fa-var-heart-circle-minus: \e4ff; -$fa-var-hourglass-half: \f252; -$fa-var-hourglass-2: \f252; -$fa-var-microscope: \f610; -$fa-var-sink: \e06d; -$fa-var-bag-shopping: \f290; -$fa-var-shopping-bag: \f290; -$fa-var-arrow-down-z-a: \f881; -$fa-var-sort-alpha-desc: \f881; -$fa-var-sort-alpha-down-alt: \f881; -$fa-var-mitten: \f7b5; -$fa-var-person-rays: \e54d; -$fa-var-users: \f0c0; -$fa-var-eye-slash: \f070; -$fa-var-flask-vial: \e4f3; -$fa-var-hand: \f256; -$fa-var-hand-paper: \f256; -$fa-var-om: \f679; -$fa-var-worm: \e599; -$fa-var-house-circle-xmark: \e50b; -$fa-var-plug: \f1e6; -$fa-var-chevron-up: \f077; -$fa-var-hand-spock: \f259; -$fa-var-stopwatch: \f2f2; -$fa-var-face-kiss: \f596; -$fa-var-kiss: \f596; -$fa-var-bridge-circle-xmark: \e4cb; -$fa-var-face-grin-tongue: \f589; -$fa-var-grin-tongue: \f589; -$fa-var-chess-bishop: \f43a; -$fa-var-face-grin-wink: \f58c; -$fa-var-grin-wink: \f58c; -$fa-var-ear-deaf: \f2a4; -$fa-var-deaf: \f2a4; -$fa-var-deafness: \f2a4; -$fa-var-hard-of-hearing: \f2a4; -$fa-var-road-circle-check: \e564; -$fa-var-dice-five: \f523; -$fa-var-square-rss: \f143; -$fa-var-rss-square: \f143; -$fa-var-land-mine-on: \e51b; -$fa-var-i-cursor: \f246; -$fa-var-stamp: \f5bf; -$fa-var-stairs: \e289; -$fa-var-i: \49; -$fa-var-hryvnia-sign: \f6f2; -$fa-var-hryvnia: \f6f2; -$fa-var-pills: \f484; -$fa-var-face-grin-wide: \f581; -$fa-var-grin-alt: \f581; -$fa-var-tooth: \f5c9; -$fa-var-v: \56; -$fa-var-bicycle: \f206; -$fa-var-staff-snake: \e579; -$fa-var-rod-asclepius: \e579; -$fa-var-rod-snake: \e579; -$fa-var-staff-aesculapius: \e579; -$fa-var-head-side-cough-slash: \e062; -$fa-var-truck-medical: \f0f9; -$fa-var-ambulance: \f0f9; -$fa-var-wheat-awn-circle-exclamation: \e598; -$fa-var-snowman: \f7d0; -$fa-var-mortar-pestle: \f5a7; -$fa-var-road-barrier: \e562; -$fa-var-school: \f549; -$fa-var-igloo: \f7ae; -$fa-var-joint: \f595; -$fa-var-angle-right: \f105; -$fa-var-horse: \f6f0; -$fa-var-q: \51; -$fa-var-g: \47; -$fa-var-notes-medical: \f481; -$fa-var-temperature-half: \f2c9; -$fa-var-temperature-2: \f2c9; -$fa-var-thermometer-2: \f2c9; -$fa-var-thermometer-half: \f2c9; -$fa-var-dong-sign: \e169; -$fa-var-capsules: \f46b; -$fa-var-poo-storm: \f75a; -$fa-var-poo-bolt: \f75a; -$fa-var-face-frown-open: \f57a; -$fa-var-frown-open: \f57a; -$fa-var-hand-point-up: \f0a6; -$fa-var-money-bill: \f0d6; -$fa-var-bookmark: \f02e; -$fa-var-align-justify: \f039; -$fa-var-umbrella-beach: \f5ca; -$fa-var-helmet-un: \e503; -$fa-var-bullseye: \f140; -$fa-var-bacon: \f7e5; -$fa-var-hand-point-down: \f0a7; -$fa-var-arrow-up-from-bracket: \e09a; -$fa-var-folder: \f07b; -$fa-var-folder-blank: \f07b; -$fa-var-file-waveform: \f478; -$fa-var-file-medical-alt: \f478; -$fa-var-radiation: \f7b9; -$fa-var-chart-simple: \e473; -$fa-var-mars-stroke: \f229; -$fa-var-vial: \f492; -$fa-var-gauge: \f624; -$fa-var-dashboard: \f624; -$fa-var-gauge-med: \f624; -$fa-var-tachometer-alt-average: \f624; -$fa-var-wand-magic-sparkles: \e2ca; -$fa-var-magic-wand-sparkles: \e2ca; -$fa-var-e: \45; -$fa-var-pen-clip: \f305; -$fa-var-pen-alt: \f305; -$fa-var-bridge-circle-exclamation: \e4ca; -$fa-var-user: \f007; -$fa-var-school-circle-check: \e56b; -$fa-var-dumpster: \f793; -$fa-var-van-shuttle: \f5b6; -$fa-var-shuttle-van: \f5b6; -$fa-var-building-user: \e4da; -$fa-var-square-caret-left: \f191; -$fa-var-caret-square-left: \f191; -$fa-var-highlighter: \f591; -$fa-var-key: \f084; -$fa-var-bullhorn: \f0a1; -$fa-var-globe: \f0ac; -$fa-var-synagogue: \f69b; -$fa-var-person-half-dress: \e548; -$fa-var-road-bridge: \e563; -$fa-var-location-arrow: \f124; -$fa-var-c: \43; -$fa-var-tablet-button: \f10a; -$fa-var-building-lock: \e4d6; -$fa-var-pizza-slice: \f818; -$fa-var-money-bill-wave: \f53a; -$fa-var-chart-area: \f1fe; -$fa-var-area-chart: \f1fe; -$fa-var-house-flag: \e50d; -$fa-var-person-circle-minus: \e540; -$fa-var-ban: \f05e; -$fa-var-cancel: \f05e; -$fa-var-camera-rotate: \e0d8; -$fa-var-spray-can-sparkles: \f5d0; -$fa-var-air-freshener: \f5d0; -$fa-var-star: \f005; -$fa-var-repeat: \f363; -$fa-var-cross: \f654; -$fa-var-box: \f466; -$fa-var-venus-mars: \f228; -$fa-var-arrow-pointer: \f245; -$fa-var-mouse-pointer: \f245; -$fa-var-maximize: \f31e; -$fa-var-expand-arrows-alt: \f31e; -$fa-var-charging-station: \f5e7; -$fa-var-shapes: \f61f; -$fa-var-triangle-circle-square: \f61f; -$fa-var-shuffle: \f074; -$fa-var-random: \f074; -$fa-var-person-running: \f70c; -$fa-var-running: \f70c; -$fa-var-mobile-retro: \e527; -$fa-var-grip-lines-vertical: \f7a5; -$fa-var-spider: \f717; -$fa-var-hands-bound: \e4f9; -$fa-var-file-invoice-dollar: \f571; -$fa-var-plane-circle-exclamation: \e556; -$fa-var-x-ray: \f497; -$fa-var-spell-check: \f891; -$fa-var-slash: \f715; -$fa-var-computer-mouse: \f8cc; -$fa-var-mouse: \f8cc; -$fa-var-arrow-right-to-bracket: \f090; -$fa-var-sign-in: \f090; -$fa-var-shop-slash: \e070; -$fa-var-store-alt-slash: \e070; -$fa-var-server: \f233; -$fa-var-virus-covid-slash: \e4a9; -$fa-var-shop-lock: \e4a5; -$fa-var-hourglass-start: \f251; -$fa-var-hourglass-1: \f251; -$fa-var-blender-phone: \f6b6; -$fa-var-building-wheat: \e4db; -$fa-var-person-breastfeeding: \e53a; -$fa-var-right-to-bracket: \f2f6; -$fa-var-sign-in-alt: \f2f6; -$fa-var-venus: \f221; -$fa-var-passport: \f5ab; -$fa-var-heart-pulse: \f21e; -$fa-var-heartbeat: \f21e; -$fa-var-people-carry-box: \f4ce; -$fa-var-people-carry: \f4ce; -$fa-var-temperature-high: \f769; -$fa-var-microchip: \f2db; -$fa-var-crown: \f521; -$fa-var-weight-hanging: \f5cd; -$fa-var-xmarks-lines: \e59a; -$fa-var-file-prescription: \f572; -$fa-var-weight-scale: \f496; -$fa-var-weight: \f496; -$fa-var-user-group: \f500; -$fa-var-user-friends: \f500; -$fa-var-arrow-up-a-z: \f15e; -$fa-var-sort-alpha-up: \f15e; -$fa-var-chess-knight: \f441; -$fa-var-face-laugh-squint: \f59b; -$fa-var-laugh-squint: \f59b; -$fa-var-wheelchair: \f193; -$fa-var-circle-arrow-up: \f0aa; -$fa-var-arrow-circle-up: \f0aa; -$fa-var-toggle-on: \f205; -$fa-var-person-walking: \f554; -$fa-var-walking: \f554; -$fa-var-l: \4c; -$fa-var-fire: \f06d; -$fa-var-bed-pulse: \f487; -$fa-var-procedures: \f487; -$fa-var-shuttle-space: \f197; -$fa-var-space-shuttle: \f197; -$fa-var-face-laugh: \f599; -$fa-var-laugh: \f599; -$fa-var-folder-open: \f07c; -$fa-var-heart-circle-plus: \e500; -$fa-var-code-fork: \e13b; -$fa-var-city: \f64f; -$fa-var-microphone-lines: \f3c9; -$fa-var-microphone-alt: \f3c9; -$fa-var-pepper-hot: \f816; -$fa-var-unlock: \f09c; -$fa-var-colon-sign: \e140; -$fa-var-headset: \f590; -$fa-var-store-slash: \e071; -$fa-var-road-circle-xmark: \e566; -$fa-var-user-minus: \f503; -$fa-var-mars-stroke-up: \f22a; -$fa-var-mars-stroke-v: \f22a; -$fa-var-champagne-glasses: \f79f; -$fa-var-glass-cheers: \f79f; -$fa-var-clipboard: \f328; -$fa-var-house-circle-exclamation: \e50a; -$fa-var-file-arrow-up: \f574; -$fa-var-file-upload: \f574; -$fa-var-wifi: \f1eb; -$fa-var-wifi-3: \f1eb; -$fa-var-wifi-strong: \f1eb; -$fa-var-bath: \f2cd; -$fa-var-bathtub: \f2cd; -$fa-var-underline: \f0cd; -$fa-var-user-pen: \f4ff; -$fa-var-user-edit: \f4ff; -$fa-var-signature: \f5b7; -$fa-var-stroopwafel: \f551; -$fa-var-bold: \f032; -$fa-var-anchor-lock: \e4ad; -$fa-var-building-ngo: \e4d7; -$fa-var-manat-sign: \e1d5; -$fa-var-not-equal: \f53e; -$fa-var-border-top-left: \f853; -$fa-var-border-style: \f853; -$fa-var-map-location-dot: \f5a0; -$fa-var-map-marked-alt: \f5a0; -$fa-var-jedi: \f669; -$fa-var-square-poll-vertical: \f681; -$fa-var-poll: \f681; -$fa-var-mug-hot: \f7b6; -$fa-var-car-battery: \f5df; -$fa-var-battery-car: \f5df; -$fa-var-gift: \f06b; -$fa-var-dice-two: \f528; -$fa-var-chess-queen: \f445; -$fa-var-glasses: \f530; -$fa-var-chess-board: \f43c; -$fa-var-building-circle-check: \e4d2; -$fa-var-person-chalkboard: \e53d; -$fa-var-mars-stroke-right: \f22b; -$fa-var-mars-stroke-h: \f22b; -$fa-var-hand-back-fist: \f255; -$fa-var-hand-rock: \f255; -$fa-var-square-caret-up: \f151; -$fa-var-caret-square-up: \f151; -$fa-var-cloud-showers-water: \e4e4; -$fa-var-chart-bar: \f080; -$fa-var-bar-chart: \f080; -$fa-var-hands-bubbles: \e05e; -$fa-var-hands-wash: \e05e; -$fa-var-less-than-equal: \f537; -$fa-var-train: \f238; -$fa-var-eye-low-vision: \f2a8; -$fa-var-low-vision: \f2a8; -$fa-var-crow: \f520; -$fa-var-sailboat: \e445; -$fa-var-window-restore: \f2d2; -$fa-var-square-plus: \f0fe; -$fa-var-plus-square: \f0fe; -$fa-var-torii-gate: \f6a1; -$fa-var-frog: \f52e; -$fa-var-bucket: \e4cf; -$fa-var-image: \f03e; -$fa-var-microphone: \f130; -$fa-var-cow: \f6c8; -$fa-var-caret-up: \f0d8; -$fa-var-screwdriver: \f54a; -$fa-var-folder-closed: \e185; -$fa-var-house-tsunami: \e515; -$fa-var-square-nfi: \e576; -$fa-var-arrow-up-from-ground-water: \e4b5; -$fa-var-martini-glass: \f57b; -$fa-var-glass-martini-alt: \f57b; -$fa-var-rotate-left: \f2ea; -$fa-var-rotate-back: \f2ea; -$fa-var-rotate-backward: \f2ea; -$fa-var-undo-alt: \f2ea; -$fa-var-table-columns: \f0db; -$fa-var-columns: \f0db; -$fa-var-lemon: \f094; -$fa-var-head-side-mask: \e063; -$fa-var-handshake: \f2b5; -$fa-var-gem: \f3a5; -$fa-var-dolly: \f472; -$fa-var-dolly-box: \f472; -$fa-var-smoking: \f48d; -$fa-var-minimize: \f78c; -$fa-var-compress-arrows-alt: \f78c; -$fa-var-monument: \f5a6; -$fa-var-snowplow: \f7d2; -$fa-var-angles-right: \f101; -$fa-var-angle-double-right: \f101; -$fa-var-cannabis: \f55f; -$fa-var-circle-play: \f144; -$fa-var-play-circle: \f144; -$fa-var-tablets: \f490; -$fa-var-ethernet: \f796; -$fa-var-euro-sign: \f153; -$fa-var-eur: \f153; -$fa-var-euro: \f153; -$fa-var-chair: \f6c0; -$fa-var-circle-check: \f058; -$fa-var-check-circle: \f058; -$fa-var-circle-stop: \f28d; -$fa-var-stop-circle: \f28d; -$fa-var-compass-drafting: \f568; -$fa-var-drafting-compass: \f568; -$fa-var-plate-wheat: \e55a; -$fa-var-icicles: \f7ad; -$fa-var-person-shelter: \e54f; -$fa-var-neuter: \f22c; -$fa-var-id-badge: \f2c1; -$fa-var-marker: \f5a1; -$fa-var-face-laugh-beam: \f59a; -$fa-var-laugh-beam: \f59a; -$fa-var-helicopter-symbol: \e502; -$fa-var-universal-access: \f29a; -$fa-var-circle-chevron-up: \f139; -$fa-var-chevron-circle-up: \f139; -$fa-var-lari-sign: \e1c8; -$fa-var-volcano: \f770; -$fa-var-person-walking-dashed-line-arrow-right: \e553; -$fa-var-sterling-sign: \f154; -$fa-var-gbp: \f154; -$fa-var-pound-sign: \f154; -$fa-var-viruses: \e076; -$fa-var-square-person-confined: \e577; -$fa-var-user-tie: \f508; -$fa-var-arrow-down-long: \f175; -$fa-var-long-arrow-down: \f175; -$fa-var-tent-arrow-down-to-line: \e57e; -$fa-var-certificate: \f0a3; -$fa-var-reply-all: \f122; -$fa-var-mail-reply-all: \f122; -$fa-var-suitcase: \f0f2; -$fa-var-person-skating: \f7c5; -$fa-var-skating: \f7c5; -$fa-var-filter-circle-dollar: \f662; -$fa-var-funnel-dollar: \f662; -$fa-var-camera-retro: \f083; -$fa-var-circle-arrow-down: \f0ab; -$fa-var-arrow-circle-down: \f0ab; -$fa-var-file-import: \f56f; -$fa-var-arrow-right-to-file: \f56f; -$fa-var-square-arrow-up-right: \f14c; -$fa-var-external-link-square: \f14c; -$fa-var-box-open: \f49e; -$fa-var-scroll: \f70e; -$fa-var-spa: \f5bb; -$fa-var-location-pin-lock: \e51f; -$fa-var-pause: \f04c; -$fa-var-hill-avalanche: \e507; -$fa-var-temperature-empty: \f2cb; -$fa-var-temperature-0: \f2cb; -$fa-var-thermometer-0: \f2cb; -$fa-var-thermometer-empty: \f2cb; -$fa-var-bomb: \f1e2; -$fa-var-registered: \f25d; -$fa-var-address-card: \f2bb; -$fa-var-contact-card: \f2bb; -$fa-var-vcard: \f2bb; -$fa-var-scale-unbalanced-flip: \f516; -$fa-var-balance-scale-right: \f516; -$fa-var-subscript: \f12c; -$fa-var-diamond-turn-right: \f5eb; -$fa-var-directions: \f5eb; -$fa-var-burst: \e4dc; -$fa-var-house-laptop: \e066; -$fa-var-laptop-house: \e066; -$fa-var-face-tired: \f5c8; -$fa-var-tired: \f5c8; -$fa-var-money-bills: \e1f3; -$fa-var-smog: \f75f; -$fa-var-crutch: \f7f7; -$fa-var-cloud-arrow-up: \f0ee; -$fa-var-cloud-upload: \f0ee; -$fa-var-cloud-upload-alt: \f0ee; -$fa-var-palette: \f53f; -$fa-var-arrows-turn-right: \e4c0; -$fa-var-vest: \e085; -$fa-var-ferry: \e4ea; -$fa-var-arrows-down-to-people: \e4b9; -$fa-var-seedling: \f4d8; -$fa-var-sprout: \f4d8; -$fa-var-left-right: \f337; -$fa-var-arrows-alt-h: \f337; -$fa-var-boxes-packing: \e4c7; -$fa-var-circle-arrow-left: \f0a8; -$fa-var-arrow-circle-left: \f0a8; -$fa-var-group-arrows-rotate: \e4f6; -$fa-var-bowl-food: \e4c6; -$fa-var-candy-cane: \f786; -$fa-var-arrow-down-wide-short: \f160; -$fa-var-sort-amount-asc: \f160; -$fa-var-sort-amount-down: \f160; -$fa-var-cloud-bolt: \f76c; -$fa-var-thunderstorm: \f76c; -$fa-var-text-slash: \f87d; -$fa-var-remove-format: \f87d; -$fa-var-face-smile-wink: \f4da; -$fa-var-smile-wink: \f4da; -$fa-var-file-word: \f1c2; -$fa-var-file-powerpoint: \f1c4; -$fa-var-arrows-left-right: \f07e; -$fa-var-arrows-h: \f07e; -$fa-var-house-lock: \e510; -$fa-var-cloud-arrow-down: \f0ed; -$fa-var-cloud-download: \f0ed; -$fa-var-cloud-download-alt: \f0ed; -$fa-var-children: \e4e1; -$fa-var-chalkboard: \f51b; -$fa-var-blackboard: \f51b; -$fa-var-user-large-slash: \f4fa; -$fa-var-user-alt-slash: \f4fa; -$fa-var-envelope-open: \f2b6; -$fa-var-handshake-simple-slash: \e05f; -$fa-var-handshake-alt-slash: \e05f; -$fa-var-mattress-pillow: \e525; -$fa-var-guarani-sign: \e19a; -$fa-var-arrows-rotate: \f021; -$fa-var-refresh: \f021; -$fa-var-sync: \f021; -$fa-var-fire-extinguisher: \f134; -$fa-var-cruzeiro-sign: \e152; -$fa-var-greater-than-equal: \f532; -$fa-var-shield-halved: \f3ed; -$fa-var-shield-alt: \f3ed; -$fa-var-book-atlas: \f558; -$fa-var-atlas: \f558; -$fa-var-virus: \e074; -$fa-var-envelope-circle-check: \e4e8; -$fa-var-layer-group: \f5fd; -$fa-var-arrows-to-dot: \e4be; -$fa-var-archway: \f557; -$fa-var-heart-circle-check: \e4fd; -$fa-var-house-chimney-crack: \f6f1; -$fa-var-house-damage: \f6f1; -$fa-var-file-zipper: \f1c6; -$fa-var-file-archive: \f1c6; -$fa-var-square: \f0c8; -$fa-var-martini-glass-empty: \f000; -$fa-var-glass-martini: \f000; -$fa-var-couch: \f4b8; -$fa-var-cedi-sign: \e0df; -$fa-var-italic: \f033; -$fa-var-church: \f51d; -$fa-var-comments-dollar: \f653; -$fa-var-democrat: \f747; -$fa-var-z: \5a; -$fa-var-person-skiing: \f7c9; -$fa-var-skiing: \f7c9; -$fa-var-road-lock: \e567; -$fa-var-a: \41; -$fa-var-temperature-arrow-down: \e03f; -$fa-var-temperature-down: \e03f; -$fa-var-feather-pointed: \f56b; -$fa-var-feather-alt: \f56b; -$fa-var-p: \50; -$fa-var-snowflake: \f2dc; -$fa-var-newspaper: \f1ea; -$fa-var-rectangle-ad: \f641; -$fa-var-ad: \f641; -$fa-var-circle-arrow-right: \f0a9; -$fa-var-arrow-circle-right: \f0a9; -$fa-var-filter-circle-xmark: \e17b; -$fa-var-locust: \e520; -$fa-var-sort: \f0dc; -$fa-var-unsorted: \f0dc; -$fa-var-list-ol: \f0cb; -$fa-var-list-1-2: \f0cb; -$fa-var-list-numeric: \f0cb; -$fa-var-person-dress-burst: \e544; -$fa-var-money-check-dollar: \f53d; -$fa-var-money-check-alt: \f53d; -$fa-var-vector-square: \f5cb; -$fa-var-bread-slice: \f7ec; -$fa-var-language: \f1ab; -$fa-var-face-kiss-wink-heart: \f598; -$fa-var-kiss-wink-heart: \f598; -$fa-var-filter: \f0b0; -$fa-var-question: \3f; -$fa-var-file-signature: \f573; -$fa-var-up-down-left-right: \f0b2; -$fa-var-arrows-alt: \f0b2; -$fa-var-house-chimney-user: \e065; -$fa-var-hand-holding-heart: \f4be; -$fa-var-puzzle-piece: \f12e; -$fa-var-money-check: \f53c; -$fa-var-star-half-stroke: \f5c0; -$fa-var-star-half-alt: \f5c0; -$fa-var-code: \f121; -$fa-var-whiskey-glass: \f7a0; -$fa-var-glass-whiskey: \f7a0; -$fa-var-building-circle-exclamation: \e4d3; -$fa-var-magnifying-glass-chart: \e522; -$fa-var-arrow-up-right-from-square: \f08e; -$fa-var-external-link: \f08e; -$fa-var-cubes-stacked: \e4e6; -$fa-var-won-sign: \f159; -$fa-var-krw: \f159; -$fa-var-won: \f159; -$fa-var-virus-covid: \e4a8; -$fa-var-austral-sign: \e0a9; -$fa-var-f: \46; -$fa-var-leaf: \f06c; -$fa-var-road: \f018; -$fa-var-taxi: \f1ba; -$fa-var-cab: \f1ba; -$fa-var-person-circle-plus: \e541; -$fa-var-chart-pie: \f200; -$fa-var-pie-chart: \f200; -$fa-var-bolt-lightning: \e0b7; -$fa-var-sack-xmark: \e56a; -$fa-var-file-excel: \f1c3; -$fa-var-file-contract: \f56c; -$fa-var-fish-fins: \e4f2; -$fa-var-building-flag: \e4d5; -$fa-var-face-grin-beam: \f582; -$fa-var-grin-beam: \f582; -$fa-var-object-ungroup: \f248; -$fa-var-poop: \f619; -$fa-var-location-pin: \f041; -$fa-var-map-marker: \f041; -$fa-var-kaaba: \f66b; -$fa-var-toilet-paper: \f71e; -$fa-var-helmet-safety: \f807; -$fa-var-hard-hat: \f807; -$fa-var-hat-hard: \f807; -$fa-var-eject: \f052; -$fa-var-circle-right: \f35a; -$fa-var-arrow-alt-circle-right: \f35a; -$fa-var-plane-circle-check: \e555; -$fa-var-face-rolling-eyes: \f5a5; -$fa-var-meh-rolling-eyes: \f5a5; -$fa-var-object-group: \f247; -$fa-var-chart-line: \f201; -$fa-var-line-chart: \f201; -$fa-var-mask-ventilator: \e524; -$fa-var-arrow-right: \f061; -$fa-var-signs-post: \f277; -$fa-var-map-signs: \f277; -$fa-var-cash-register: \f788; -$fa-var-person-circle-question: \e542; -$fa-var-h: \48; -$fa-var-tarp: \e57b; -$fa-var-screwdriver-wrench: \f7d9; -$fa-var-tools: \f7d9; -$fa-var-arrows-to-eye: \e4bf; -$fa-var-plug-circle-bolt: \e55b; -$fa-var-heart: \f004; -$fa-var-mars-and-venus: \f224; -$fa-var-house-user: \e1b0; -$fa-var-home-user: \e1b0; -$fa-var-dumpster-fire: \f794; -$fa-var-house-crack: \e3b1; -$fa-var-martini-glass-citrus: \f561; -$fa-var-cocktail: \f561; -$fa-var-face-surprise: \f5c2; -$fa-var-surprise: \f5c2; -$fa-var-bottle-water: \e4c5; -$fa-var-circle-pause: \f28b; -$fa-var-pause-circle: \f28b; -$fa-var-toilet-paper-slash: \e072; -$fa-var-apple-whole: \f5d1; -$fa-var-apple-alt: \f5d1; -$fa-var-kitchen-set: \e51a; -$fa-var-r: \52; -$fa-var-temperature-quarter: \f2ca; -$fa-var-temperature-1: \f2ca; -$fa-var-thermometer-1: \f2ca; -$fa-var-thermometer-quarter: \f2ca; -$fa-var-cube: \f1b2; -$fa-var-bitcoin-sign: \e0b4; -$fa-var-shield-dog: \e573; -$fa-var-solar-panel: \f5ba; -$fa-var-lock-open: \f3c1; -$fa-var-elevator: \e16d; -$fa-var-money-bill-transfer: \e528; -$fa-var-money-bill-trend-up: \e529; -$fa-var-house-flood-water-circle-arrow-right: \e50f; -$fa-var-square-poll-horizontal: \f682; -$fa-var-poll-h: \f682; -$fa-var-circle: \f111; -$fa-var-backward-fast: \f049; -$fa-var-fast-backward: \f049; -$fa-var-recycle: \f1b8; -$fa-var-user-astronaut: \f4fb; -$fa-var-plane-slash: \e069; -$fa-var-trademark: \f25c; -$fa-var-basketball: \f434; -$fa-var-basketball-ball: \f434; -$fa-var-satellite-dish: \f7c0; -$fa-var-circle-up: \f35b; -$fa-var-arrow-alt-circle-up: \f35b; -$fa-var-mobile-screen-button: \f3cd; -$fa-var-mobile-alt: \f3cd; -$fa-var-volume-high: \f028; -$fa-var-volume-up: \f028; -$fa-var-users-rays: \e593; -$fa-var-wallet: \f555; -$fa-var-clipboard-check: \f46c; -$fa-var-file-audio: \f1c7; -$fa-var-burger: \f805; -$fa-var-hamburger: \f805; -$fa-var-wrench: \f0ad; -$fa-var-bugs: \e4d0; -$fa-var-rupee-sign: \f156; -$fa-var-rupee: \f156; -$fa-var-file-image: \f1c5; -$fa-var-circle-question: \f059; -$fa-var-question-circle: \f059; -$fa-var-plane-departure: \f5b0; -$fa-var-handshake-slash: \e060; -$fa-var-book-bookmark: \e0bb; -$fa-var-code-branch: \f126; -$fa-var-hat-cowboy: \f8c0; -$fa-var-bridge: \e4c8; -$fa-var-phone-flip: \f879; -$fa-var-phone-alt: \f879; -$fa-var-truck-front: \e2b7; -$fa-var-cat: \f6be; -$fa-var-anchor-circle-exclamation: \e4ab; -$fa-var-truck-field: \e58d; -$fa-var-route: \f4d7; -$fa-var-clipboard-question: \e4e3; -$fa-var-panorama: \e209; -$fa-var-comment-medical: \f7f5; -$fa-var-teeth-open: \f62f; -$fa-var-file-circle-minus: \e4ed; -$fa-var-tags: \f02c; -$fa-var-wine-glass: \f4e3; -$fa-var-forward-fast: \f050; -$fa-var-fast-forward: \f050; -$fa-var-face-meh-blank: \f5a4; -$fa-var-meh-blank: \f5a4; -$fa-var-square-parking: \f540; -$fa-var-parking: \f540; -$fa-var-house-signal: \e012; -$fa-var-bars-progress: \f828; -$fa-var-tasks-alt: \f828; -$fa-var-faucet-drip: \e006; -$fa-var-cart-flatbed: \f474; -$fa-var-dolly-flatbed: \f474; -$fa-var-ban-smoking: \f54d; -$fa-var-smoking-ban: \f54d; -$fa-var-terminal: \f120; -$fa-var-mobile-button: \f10b; -$fa-var-house-medical-flag: \e514; -$fa-var-basket-shopping: \f291; -$fa-var-shopping-basket: \f291; -$fa-var-tape: \f4db; -$fa-var-bus-simple: \f55e; -$fa-var-bus-alt: \f55e; -$fa-var-eye: \f06e; -$fa-var-face-sad-cry: \f5b3; -$fa-var-sad-cry: \f5b3; -$fa-var-audio-description: \f29e; -$fa-var-person-military-to-person: \e54c; -$fa-var-file-shield: \e4f0; -$fa-var-user-slash: \f506; -$fa-var-pen: \f304; -$fa-var-tower-observation: \e586; -$fa-var-file-code: \f1c9; -$fa-var-signal: \f012; -$fa-var-signal-5: \f012; -$fa-var-signal-perfect: \f012; -$fa-var-bus: \f207; -$fa-var-heart-circle-xmark: \e501; -$fa-var-house-chimney: \e3af; -$fa-var-home-lg: \e3af; -$fa-var-window-maximize: \f2d0; -$fa-var-face-frown: \f119; -$fa-var-frown: \f119; -$fa-var-prescription: \f5b1; -$fa-var-shop: \f54f; -$fa-var-store-alt: \f54f; -$fa-var-floppy-disk: \f0c7; -$fa-var-save: \f0c7; -$fa-var-vihara: \f6a7; -$fa-var-scale-unbalanced: \f515; -$fa-var-balance-scale-left: \f515; -$fa-var-sort-up: \f0de; -$fa-var-sort-asc: \f0de; -$fa-var-comment-dots: \f4ad; -$fa-var-commenting: \f4ad; -$fa-var-plant-wilt: \e5aa; -$fa-var-diamond: \f219; -$fa-var-face-grin-squint: \f585; -$fa-var-grin-squint: \f585; -$fa-var-hand-holding-dollar: \f4c0; -$fa-var-hand-holding-usd: \f4c0; -$fa-var-bacterium: \e05a; -$fa-var-hand-pointer: \f25a; -$fa-var-drum-steelpan: \f56a; -$fa-var-hand-scissors: \f257; -$fa-var-hands-praying: \f684; -$fa-var-praying-hands: \f684; -$fa-var-arrow-rotate-right: \f01e; -$fa-var-arrow-right-rotate: \f01e; -$fa-var-arrow-rotate-forward: \f01e; -$fa-var-redo: \f01e; -$fa-var-biohazard: \f780; -$fa-var-location-crosshairs: \f601; -$fa-var-location: \f601; -$fa-var-mars-double: \f227; -$fa-var-child-dress: \e59c; -$fa-var-users-between-lines: \e591; -$fa-var-lungs-virus: \e067; -$fa-var-face-grin-tears: \f588; -$fa-var-grin-tears: \f588; -$fa-var-phone: \f095; -$fa-var-calendar-xmark: \f273; -$fa-var-calendar-times: \f273; -$fa-var-child-reaching: \e59d; -$fa-var-head-side-virus: \e064; -$fa-var-user-gear: \f4fe; -$fa-var-user-cog: \f4fe; -$fa-var-arrow-up-1-9: \f163; -$fa-var-sort-numeric-up: \f163; -$fa-var-door-closed: \f52a; -$fa-var-shield-virus: \e06c; -$fa-var-dice-six: \f526; -$fa-var-mosquito-net: \e52c; -$fa-var-bridge-water: \e4ce; -$fa-var-person-booth: \f756; -$fa-var-text-width: \f035; -$fa-var-hat-wizard: \f6e8; -$fa-var-pen-fancy: \f5ac; -$fa-var-person-digging: \f85e; -$fa-var-digging: \f85e; -$fa-var-trash: \f1f8; -$fa-var-gauge-simple: \f629; -$fa-var-gauge-simple-med: \f629; -$fa-var-tachometer-average: \f629; -$fa-var-book-medical: \f7e6; -$fa-var-poo: \f2fe; -$fa-var-quote-right: \f10e; -$fa-var-quote-right-alt: \f10e; -$fa-var-shirt: \f553; -$fa-var-t-shirt: \f553; -$fa-var-tshirt: \f553; -$fa-var-cubes: \f1b3; -$fa-var-divide: \f529; -$fa-var-tenge-sign: \f7d7; -$fa-var-tenge: \f7d7; -$fa-var-headphones: \f025; -$fa-var-hands-holding: \f4c2; -$fa-var-hands-clapping: \e1a8; -$fa-var-republican: \f75e; -$fa-var-arrow-left: \f060; -$fa-var-person-circle-xmark: \e543; -$fa-var-ruler: \f545; -$fa-var-align-left: \f036; -$fa-var-dice-d6: \f6d1; -$fa-var-restroom: \f7bd; -$fa-var-j: \4a; -$fa-var-users-viewfinder: \e595; -$fa-var-file-video: \f1c8; -$fa-var-up-right-from-square: \f35d; -$fa-var-external-link-alt: \f35d; -$fa-var-table-cells: \f00a; -$fa-var-th: \f00a; -$fa-var-file-pdf: \f1c1; -$fa-var-book-bible: \f647; -$fa-var-bible: \f647; -$fa-var-o: \4f; -$fa-var-suitcase-medical: \f0fa; -$fa-var-medkit: \f0fa; -$fa-var-user-secret: \f21b; -$fa-var-otter: \f700; -$fa-var-person-dress: \f182; -$fa-var-female: \f182; -$fa-var-comment-dollar: \f651; -$fa-var-business-time: \f64a; -$fa-var-briefcase-clock: \f64a; -$fa-var-table-cells-large: \f009; -$fa-var-th-large: \f009; -$fa-var-book-tanakh: \f827; -$fa-var-tanakh: \f827; -$fa-var-phone-volume: \f2a0; -$fa-var-volume-control-phone: \f2a0; -$fa-var-hat-cowboy-side: \f8c1; -$fa-var-clipboard-user: \f7f3; -$fa-var-child: \f1ae; -$fa-var-lira-sign: \f195; -$fa-var-satellite: \f7bf; -$fa-var-plane-lock: \e558; -$fa-var-tag: \f02b; -$fa-var-comment: \f075; -$fa-var-cake-candles: \f1fd; -$fa-var-birthday-cake: \f1fd; -$fa-var-cake: \f1fd; -$fa-var-envelope: \f0e0; -$fa-var-angles-up: \f102; -$fa-var-angle-double-up: \f102; -$fa-var-paperclip: \f0c6; -$fa-var-arrow-right-to-city: \e4b3; -$fa-var-ribbon: \f4d6; -$fa-var-lungs: \f604; -$fa-var-arrow-up-9-1: \f887; -$fa-var-sort-numeric-up-alt: \f887; -$fa-var-litecoin-sign: \e1d3; -$fa-var-border-none: \f850; -$fa-var-circle-nodes: \e4e2; -$fa-var-parachute-box: \f4cd; -$fa-var-indent: \f03c; -$fa-var-truck-field-un: \e58e; -$fa-var-hourglass: \f254; -$fa-var-hourglass-empty: \f254; -$fa-var-mountain: \f6fc; -$fa-var-user-doctor: \f0f0; -$fa-var-user-md: \f0f0; -$fa-var-circle-info: \f05a; -$fa-var-info-circle: \f05a; -$fa-var-cloud-meatball: \f73b; -$fa-var-camera: \f030; -$fa-var-camera-alt: \f030; -$fa-var-square-virus: \e578; -$fa-var-meteor: \f753; -$fa-var-car-on: \e4dd; -$fa-var-sleigh: \f7cc; -$fa-var-arrow-down-1-9: \f162; -$fa-var-sort-numeric-asc: \f162; -$fa-var-sort-numeric-down: \f162; -$fa-var-hand-holding-droplet: \f4c1; -$fa-var-hand-holding-water: \f4c1; -$fa-var-water: \f773; -$fa-var-calendar-check: \f274; -$fa-var-braille: \f2a1; -$fa-var-prescription-bottle-medical: \f486; -$fa-var-prescription-bottle-alt: \f486; -$fa-var-landmark: \f66f; -$fa-var-truck: \f0d1; -$fa-var-crosshairs: \f05b; -$fa-var-person-cane: \e53c; -$fa-var-tent: \e57d; -$fa-var-vest-patches: \e086; -$fa-var-check-double: \f560; -$fa-var-arrow-down-a-z: \f15d; -$fa-var-sort-alpha-asc: \f15d; -$fa-var-sort-alpha-down: \f15d; -$fa-var-money-bill-wheat: \e52a; -$fa-var-cookie: \f563; -$fa-var-arrow-rotate-left: \f0e2; -$fa-var-arrow-left-rotate: \f0e2; -$fa-var-arrow-rotate-back: \f0e2; -$fa-var-arrow-rotate-backward: \f0e2; -$fa-var-undo: \f0e2; -$fa-var-hard-drive: \f0a0; -$fa-var-hdd: \f0a0; -$fa-var-face-grin-squint-tears: \f586; -$fa-var-grin-squint-tears: \f586; -$fa-var-dumbbell: \f44b; -$fa-var-rectangle-list: \f022; -$fa-var-list-alt: \f022; -$fa-var-tarp-droplet: \e57c; -$fa-var-house-medical-circle-check: \e511; -$fa-var-person-skiing-nordic: \f7ca; -$fa-var-skiing-nordic: \f7ca; -$fa-var-calendar-plus: \f271; -$fa-var-plane-arrival: \f5af; -$fa-var-circle-left: \f359; -$fa-var-arrow-alt-circle-left: \f359; -$fa-var-train-subway: \f239; -$fa-var-subway: \f239; -$fa-var-chart-gantt: \e0e4; -$fa-var-indian-rupee-sign: \e1bc; -$fa-var-indian-rupee: \e1bc; -$fa-var-inr: \e1bc; -$fa-var-crop-simple: \f565; -$fa-var-crop-alt: \f565; -$fa-var-money-bill-1: \f3d1; -$fa-var-money-bill-alt: \f3d1; -$fa-var-left-long: \f30a; -$fa-var-long-arrow-alt-left: \f30a; -$fa-var-dna: \f471; -$fa-var-virus-slash: \e075; -$fa-var-minus: \f068; -$fa-var-subtract: \f068; -$fa-var-child-rifle: \e4e0; -$fa-var-chess: \f439; -$fa-var-arrow-left-long: \f177; -$fa-var-long-arrow-left: \f177; -$fa-var-plug-circle-check: \e55c; -$fa-var-street-view: \f21d; -$fa-var-franc-sign: \e18f; -$fa-var-volume-off: \f026; -$fa-var-hands-asl-interpreting: \f2a3; -$fa-var-american-sign-language-interpreting: \f2a3; -$fa-var-asl-interpreting: \f2a3; -$fa-var-hands-american-sign-language-interpreting: \f2a3; -$fa-var-gear: \f013; -$fa-var-cog: \f013; -$fa-var-droplet-slash: \f5c7; -$fa-var-tint-slash: \f5c7; -$fa-var-mosque: \f678; -$fa-var-mosquito: \e52b; -$fa-var-star-of-david: \f69a; -$fa-var-person-military-rifle: \e54b; -$fa-var-cart-shopping: \f07a; -$fa-var-shopping-cart: \f07a; -$fa-var-vials: \f493; -$fa-var-plug-circle-plus: \e55f; -$fa-var-place-of-worship: \f67f; -$fa-var-grip-vertical: \f58e; -$fa-var-arrow-turn-up: \f148; -$fa-var-level-up: \f148; -$fa-var-u: \55; -$fa-var-square-root-variable: \f698; -$fa-var-square-root-alt: \f698; -$fa-var-clock: \f017; -$fa-var-clock-four: \f017; -$fa-var-backward-step: \f048; -$fa-var-step-backward: \f048; -$fa-var-pallet: \f482; -$fa-var-faucet: \e005; -$fa-var-baseball-bat-ball: \f432; -$fa-var-s: \53; -$fa-var-timeline: \e29c; -$fa-var-keyboard: \f11c; -$fa-var-caret-down: \f0d7; -$fa-var-house-chimney-medical: \f7f2; -$fa-var-clinic-medical: \f7f2; -$fa-var-temperature-three-quarters: \f2c8; -$fa-var-temperature-3: \f2c8; -$fa-var-thermometer-3: \f2c8; -$fa-var-thermometer-three-quarters: \f2c8; -$fa-var-mobile-screen: \f3cf; -$fa-var-mobile-android-alt: \f3cf; -$fa-var-plane-up: \e22d; -$fa-var-piggy-bank: \f4d3; -$fa-var-battery-half: \f242; -$fa-var-battery-3: \f242; -$fa-var-mountain-city: \e52e; -$fa-var-coins: \f51e; -$fa-var-khanda: \f66d; -$fa-var-sliders: \f1de; -$fa-var-sliders-h: \f1de; -$fa-var-folder-tree: \f802; -$fa-var-network-wired: \f6ff; -$fa-var-map-pin: \f276; -$fa-var-hamsa: \f665; -$fa-var-cent-sign: \e3f5; -$fa-var-flask: \f0c3; -$fa-var-person-pregnant: \e31e; -$fa-var-wand-sparkles: \f72b; -$fa-var-ellipsis-vertical: \f142; -$fa-var-ellipsis-v: \f142; -$fa-var-ticket: \f145; -$fa-var-power-off: \f011; -$fa-var-right-long: \f30b; -$fa-var-long-arrow-alt-right: \f30b; -$fa-var-flag-usa: \f74d; -$fa-var-laptop-file: \e51d; -$fa-var-tty: \f1e4; -$fa-var-teletype: \f1e4; -$fa-var-diagram-next: \e476; -$fa-var-person-rifle: \e54e; -$fa-var-house-medical-circle-exclamation: \e512; -$fa-var-closed-captioning: \f20a; -$fa-var-person-hiking: \f6ec; -$fa-var-hiking: \f6ec; -$fa-var-venus-double: \f226; -$fa-var-images: \f302; -$fa-var-calculator: \f1ec; -$fa-var-people-pulling: \e535; -$fa-var-n: \4e; -$fa-var-cable-car: \f7da; -$fa-var-tram: \f7da; -$fa-var-cloud-rain: \f73d; -$fa-var-building-circle-xmark: \e4d4; -$fa-var-ship: \f21a; -$fa-var-arrows-down-to-line: \e4b8; -$fa-var-download: \f019; -$fa-var-face-grin: \f580; -$fa-var-grin: \f580; -$fa-var-delete-left: \f55a; -$fa-var-backspace: \f55a; -$fa-var-eye-dropper: \f1fb; -$fa-var-eye-dropper-empty: \f1fb; -$fa-var-eyedropper: \f1fb; -$fa-var-file-circle-check: \e5a0; -$fa-var-forward: \f04e; -$fa-var-mobile: \f3ce; -$fa-var-mobile-android: \f3ce; -$fa-var-mobile-phone: \f3ce; -$fa-var-face-meh: \f11a; -$fa-var-meh: \f11a; -$fa-var-align-center: \f037; -$fa-var-book-skull: \f6b7; -$fa-var-book-dead: \f6b7; -$fa-var-id-card: \f2c2; -$fa-var-drivers-license: \f2c2; -$fa-var-outdent: \f03b; -$fa-var-dedent: \f03b; -$fa-var-heart-circle-exclamation: \e4fe; -$fa-var-house: \f015; -$fa-var-home: \f015; -$fa-var-home-alt: \f015; -$fa-var-home-lg-alt: \f015; -$fa-var-calendar-week: \f784; -$fa-var-laptop-medical: \f812; -$fa-var-b: \42; -$fa-var-file-medical: \f477; -$fa-var-dice-one: \f525; -$fa-var-kiwi-bird: \f535; -$fa-var-arrow-right-arrow-left: \f0ec; -$fa-var-exchange: \f0ec; -$fa-var-rotate-right: \f2f9; -$fa-var-redo-alt: \f2f9; -$fa-var-rotate-forward: \f2f9; -$fa-var-utensils: \f2e7; -$fa-var-cutlery: \f2e7; -$fa-var-arrow-up-wide-short: \f161; -$fa-var-sort-amount-up: \f161; -$fa-var-mill-sign: \e1ed; -$fa-var-bowl-rice: \e2eb; -$fa-var-skull: \f54c; -$fa-var-tower-broadcast: \f519; -$fa-var-broadcast-tower: \f519; -$fa-var-truck-pickup: \f63c; -$fa-var-up-long: \f30c; -$fa-var-long-arrow-alt-up: \f30c; -$fa-var-stop: \f04d; -$fa-var-code-merge: \f387; -$fa-var-upload: \f093; -$fa-var-hurricane: \f751; -$fa-var-mound: \e52d; -$fa-var-toilet-portable: \e583; -$fa-var-compact-disc: \f51f; -$fa-var-file-arrow-down: \f56d; -$fa-var-file-download: \f56d; -$fa-var-caravan: \f8ff; -$fa-var-shield-cat: \e572; -$fa-var-bolt: \f0e7; -$fa-var-zap: \f0e7; -$fa-var-glass-water: \e4f4; -$fa-var-oil-well: \e532; -$fa-var-vault: \e2c5; -$fa-var-mars: \f222; -$fa-var-toilet: \f7d8; -$fa-var-plane-circle-xmark: \e557; -$fa-var-yen-sign: \f157; -$fa-var-cny: \f157; -$fa-var-jpy: \f157; -$fa-var-rmb: \f157; -$fa-var-yen: \f157; -$fa-var-ruble-sign: \f158; -$fa-var-rouble: \f158; -$fa-var-rub: \f158; -$fa-var-ruble: \f158; -$fa-var-sun: \f185; -$fa-var-guitar: \f7a6; -$fa-var-face-laugh-wink: \f59c; -$fa-var-laugh-wink: \f59c; -$fa-var-horse-head: \f7ab; -$fa-var-bore-hole: \e4c3; -$fa-var-industry: \f275; -$fa-var-circle-down: \f358; -$fa-var-arrow-alt-circle-down: \f358; -$fa-var-arrows-turn-to-dots: \e4c1; -$fa-var-florin-sign: \e184; -$fa-var-arrow-down-short-wide: \f884; -$fa-var-sort-amount-desc: \f884; -$fa-var-sort-amount-down-alt: \f884; -$fa-var-less-than: \3c; -$fa-var-angle-down: \f107; -$fa-var-car-tunnel: \e4de; -$fa-var-head-side-cough: \e061; -$fa-var-grip-lines: \f7a4; -$fa-var-thumbs-down: \f165; -$fa-var-user-lock: \f502; -$fa-var-arrow-right-long: \f178; -$fa-var-long-arrow-right: \f178; -$fa-var-anchor-circle-xmark: \e4ac; -$fa-var-ellipsis: \f141; -$fa-var-ellipsis-h: \f141; -$fa-var-chess-pawn: \f443; -$fa-var-kit-medical: \f479; -$fa-var-first-aid: \f479; -$fa-var-person-through-window: \e5a9; -$fa-var-toolbox: \f552; -$fa-var-hands-holding-circle: \e4fb; -$fa-var-bug: \f188; -$fa-var-credit-card: \f09d; -$fa-var-credit-card-alt: \f09d; -$fa-var-car: \f1b9; -$fa-var-automobile: \f1b9; -$fa-var-hand-holding-hand: \e4f7; -$fa-var-book-open-reader: \f5da; -$fa-var-book-reader: \f5da; -$fa-var-mountain-sun: \e52f; -$fa-var-arrows-left-right-to-line: \e4ba; -$fa-var-dice-d20: \f6cf; -$fa-var-truck-droplet: \e58c; -$fa-var-file-circle-xmark: \e5a1; -$fa-var-temperature-arrow-up: \e040; -$fa-var-temperature-up: \e040; -$fa-var-medal: \f5a2; -$fa-var-bed: \f236; -$fa-var-square-h: \f0fd; -$fa-var-h-square: \f0fd; -$fa-var-podcast: \f2ce; -$fa-var-temperature-full: \f2c7; -$fa-var-temperature-4: \f2c7; -$fa-var-thermometer-4: \f2c7; -$fa-var-thermometer-full: \f2c7; -$fa-var-bell: \f0f3; -$fa-var-superscript: \f12b; -$fa-var-plug-circle-xmark: \e560; -$fa-var-star-of-life: \f621; -$fa-var-phone-slash: \f3dd; -$fa-var-paint-roller: \f5aa; -$fa-var-handshake-angle: \f4c4; -$fa-var-hands-helping: \f4c4; -$fa-var-location-dot: \f3c5; -$fa-var-map-marker-alt: \f3c5; -$fa-var-file: \f15b; -$fa-var-greater-than: \3e; -$fa-var-person-swimming: \f5c4; -$fa-var-swimmer: \f5c4; -$fa-var-arrow-down: \f063; -$fa-var-droplet: \f043; -$fa-var-tint: \f043; -$fa-var-eraser: \f12d; -$fa-var-earth-americas: \f57d; -$fa-var-earth: \f57d; -$fa-var-earth-america: \f57d; -$fa-var-globe-americas: \f57d; -$fa-var-person-burst: \e53b; -$fa-var-dove: \f4ba; -$fa-var-battery-empty: \f244; -$fa-var-battery-0: \f244; -$fa-var-socks: \f696; -$fa-var-inbox: \f01c; -$fa-var-section: \e447; -$fa-var-gauge-high: \f625; -$fa-var-tachometer-alt: \f625; -$fa-var-tachometer-alt-fast: \f625; -$fa-var-envelope-open-text: \f658; -$fa-var-hospital: \f0f8; -$fa-var-hospital-alt: \f0f8; -$fa-var-hospital-wide: \f0f8; -$fa-var-wine-bottle: \f72f; -$fa-var-chess-rook: \f447; -$fa-var-bars-staggered: \f550; -$fa-var-reorder: \f550; -$fa-var-stream: \f550; -$fa-var-dharmachakra: \f655; -$fa-var-hotdog: \f80f; -$fa-var-person-walking-with-cane: \f29d; -$fa-var-blind: \f29d; -$fa-var-drum: \f569; -$fa-var-ice-cream: \f810; -$fa-var-heart-circle-bolt: \e4fc; -$fa-var-fax: \f1ac; -$fa-var-paragraph: \f1dd; -$fa-var-check-to-slot: \f772; -$fa-var-vote-yea: \f772; -$fa-var-star-half: \f089; -$fa-var-boxes-stacked: \f468; -$fa-var-boxes: \f468; -$fa-var-boxes-alt: \f468; -$fa-var-link: \f0c1; -$fa-var-chain: \f0c1; -$fa-var-ear-listen: \f2a2; -$fa-var-assistive-listening-systems: \f2a2; -$fa-var-tree-city: \e587; -$fa-var-play: \f04b; -$fa-var-font: \f031; -$fa-var-rupiah-sign: \e23d; -$fa-var-magnifying-glass: \f002; -$fa-var-search: \f002; -$fa-var-table-tennis-paddle-ball: \f45d; -$fa-var-ping-pong-paddle-ball: \f45d; -$fa-var-table-tennis: \f45d; -$fa-var-person-dots-from-line: \f470; -$fa-var-diagnoses: \f470; -$fa-var-trash-can-arrow-up: \f82a; -$fa-var-trash-restore-alt: \f82a; -$fa-var-naira-sign: \e1f6; -$fa-var-cart-arrow-down: \f218; -$fa-var-walkie-talkie: \f8ef; -$fa-var-file-pen: \f31c; -$fa-var-file-edit: \f31c; -$fa-var-receipt: \f543; -$fa-var-square-pen: \f14b; -$fa-var-pen-square: \f14b; -$fa-var-pencil-square: \f14b; -$fa-var-suitcase-rolling: \f5c1; -$fa-var-person-circle-exclamation: \e53f; -$fa-var-chevron-down: \f078; -$fa-var-battery-full: \f240; -$fa-var-battery: \f240; -$fa-var-battery-5: \f240; -$fa-var-skull-crossbones: \f714; -$fa-var-code-compare: \e13a; -$fa-var-list-ul: \f0ca; -$fa-var-list-dots: \f0ca; -$fa-var-school-lock: \e56f; -$fa-var-tower-cell: \e585; -$fa-var-down-long: \f309; -$fa-var-long-arrow-alt-down: \f309; -$fa-var-ranking-star: \e561; -$fa-var-chess-king: \f43f; -$fa-var-person-harassing: \e549; -$fa-var-brazilian-real-sign: \e46c; -$fa-var-landmark-dome: \f752; -$fa-var-landmark-alt: \f752; -$fa-var-arrow-up: \f062; -$fa-var-tv: \f26c; -$fa-var-television: \f26c; -$fa-var-tv-alt: \f26c; -$fa-var-shrimp: \e448; -$fa-var-list-check: \f0ae; -$fa-var-tasks: \f0ae; -$fa-var-jug-detergent: \e519; -$fa-var-circle-user: \f2bd; -$fa-var-user-circle: \f2bd; -$fa-var-user-shield: \f505; -$fa-var-wind: \f72e; -$fa-var-car-burst: \f5e1; -$fa-var-car-crash: \f5e1; -$fa-var-y: \59; -$fa-var-person-snowboarding: \f7ce; -$fa-var-snowboarding: \f7ce; -$fa-var-truck-fast: \f48b; -$fa-var-shipping-fast: \f48b; -$fa-var-fish: \f578; -$fa-var-user-graduate: \f501; -$fa-var-circle-half-stroke: \f042; -$fa-var-adjust: \f042; -$fa-var-clapperboard: \e131; -$fa-var-circle-radiation: \f7ba; -$fa-var-radiation-alt: \f7ba; -$fa-var-baseball: \f433; -$fa-var-baseball-ball: \f433; -$fa-var-jet-fighter-up: \e518; -$fa-var-diagram-project: \f542; -$fa-var-project-diagram: \f542; -$fa-var-copy: \f0c5; -$fa-var-volume-xmark: \f6a9; -$fa-var-volume-mute: \f6a9; -$fa-var-volume-times: \f6a9; -$fa-var-hand-sparkles: \e05d; -$fa-var-grip: \f58d; -$fa-var-grip-horizontal: \f58d; -$fa-var-share-from-square: \f14d; -$fa-var-share-square: \f14d; -$fa-var-gun: \e19b; -$fa-var-square-phone: \f098; -$fa-var-phone-square: \f098; -$fa-var-plus: \2b; -$fa-var-add: \2b; -$fa-var-expand: \f065; -$fa-var-computer: \e4e5; -$fa-var-xmark: \f00d; -$fa-var-close: \f00d; -$fa-var-multiply: \f00d; -$fa-var-remove: \f00d; -$fa-var-times: \f00d; -$fa-var-arrows-up-down-left-right: \f047; -$fa-var-arrows: \f047; -$fa-var-chalkboard-user: \f51c; -$fa-var-chalkboard-teacher: \f51c; -$fa-var-peso-sign: \e222; -$fa-var-building-shield: \e4d8; -$fa-var-baby: \f77c; -$fa-var-users-line: \e592; -$fa-var-quote-left: \f10d; -$fa-var-quote-left-alt: \f10d; -$fa-var-tractor: \f722; -$fa-var-trash-arrow-up: \f829; -$fa-var-trash-restore: \f829; -$fa-var-arrow-down-up-lock: \e4b0; -$fa-var-lines-leaning: \e51e; -$fa-var-ruler-combined: \f546; -$fa-var-copyright: \f1f9; -$fa-var-equals: \3d; -$fa-var-blender: \f517; -$fa-var-teeth: \f62e; -$fa-var-shekel-sign: \f20b; -$fa-var-ils: \f20b; -$fa-var-shekel: \f20b; -$fa-var-sheqel: \f20b; -$fa-var-sheqel-sign: \f20b; -$fa-var-map: \f279; -$fa-var-rocket: \f135; -$fa-var-photo-film: \f87c; -$fa-var-photo-video: \f87c; -$fa-var-folder-minus: \f65d; -$fa-var-store: \f54e; -$fa-var-arrow-trend-up: \e098; -$fa-var-plug-circle-minus: \e55e; -$fa-var-sign-hanging: \f4d9; -$fa-var-sign: \f4d9; -$fa-var-bezier-curve: \f55b; -$fa-var-bell-slash: \f1f6; -$fa-var-tablet: \f3fb; -$fa-var-tablet-android: \f3fb; -$fa-var-school-flag: \e56e; -$fa-var-fill: \f575; -$fa-var-angle-up: \f106; -$fa-var-drumstick-bite: \f6d7; -$fa-var-holly-berry: \f7aa; -$fa-var-chevron-left: \f053; -$fa-var-bacteria: \e059; -$fa-var-hand-lizard: \f258; -$fa-var-disease: \f7fa; -$fa-var-briefcase-medical: \f469; -$fa-var-genderless: \f22d; -$fa-var-chevron-right: \f054; -$fa-var-retweet: \f079; -$fa-var-car-rear: \f5de; -$fa-var-car-alt: \f5de; -$fa-var-pump-soap: \e06b; -$fa-var-video-slash: \f4e2; -$fa-var-battery-quarter: \f243; -$fa-var-battery-2: \f243; -$fa-var-radio: \f8d7; -$fa-var-baby-carriage: \f77d; -$fa-var-carriage-baby: \f77d; -$fa-var-traffic-light: \f637; -$fa-var-thermometer: \f491; -$fa-var-vr-cardboard: \f729; -$fa-var-hand-middle-finger: \f806; -$fa-var-percent: \25; -$fa-var-percentage: \25; -$fa-var-truck-moving: \f4df; -$fa-var-glass-water-droplet: \e4f5; -$fa-var-display: \e163; -$fa-var-face-smile: \f118; -$fa-var-smile: \f118; -$fa-var-thumbtack: \f08d; -$fa-var-thumb-tack: \f08d; -$fa-var-trophy: \f091; -$fa-var-person-praying: \f683; -$fa-var-pray: \f683; -$fa-var-hammer: \f6e3; -$fa-var-hand-peace: \f25b; -$fa-var-rotate: \f2f1; -$fa-var-sync-alt: \f2f1; -$fa-var-spinner: \f110; -$fa-var-robot: \f544; -$fa-var-peace: \f67c; -$fa-var-gears: \f085; -$fa-var-cogs: \f085; -$fa-var-warehouse: \f494; -$fa-var-arrow-up-right-dots: \e4b7; -$fa-var-splotch: \f5bc; -$fa-var-face-grin-hearts: \f584; -$fa-var-grin-hearts: \f584; -$fa-var-dice-four: \f524; -$fa-var-sim-card: \f7c4; -$fa-var-transgender: \f225; -$fa-var-transgender-alt: \f225; -$fa-var-mercury: \f223; -$fa-var-arrow-turn-down: \f149; -$fa-var-level-down: \f149; -$fa-var-person-falling-burst: \e547; -$fa-var-award: \f559; -$fa-var-ticket-simple: \f3ff; -$fa-var-ticket-alt: \f3ff; -$fa-var-building: \f1ad; -$fa-var-angles-left: \f100; -$fa-var-angle-double-left: \f100; -$fa-var-qrcode: \f029; -$fa-var-clock-rotate-left: \f1da; -$fa-var-history: \f1da; -$fa-var-face-grin-beam-sweat: \f583; -$fa-var-grin-beam-sweat: \f583; -$fa-var-file-export: \f56e; -$fa-var-arrow-right-from-file: \f56e; -$fa-var-shield: \f132; -$fa-var-shield-blank: \f132; -$fa-var-arrow-up-short-wide: \f885; -$fa-var-sort-amount-up-alt: \f885; -$fa-var-house-medical: \e3b2; -$fa-var-golf-ball-tee: \f450; -$fa-var-golf-ball: \f450; -$fa-var-circle-chevron-left: \f137; -$fa-var-chevron-circle-left: \f137; -$fa-var-house-chimney-window: \e00d; -$fa-var-pen-nib: \f5ad; -$fa-var-tent-arrow-turn-left: \e580; -$fa-var-tents: \e582; -$fa-var-wand-magic: \f0d0; -$fa-var-magic: \f0d0; -$fa-var-dog: \f6d3; -$fa-var-carrot: \f787; -$fa-var-moon: \f186; -$fa-var-wine-glass-empty: \f5ce; -$fa-var-wine-glass-alt: \f5ce; -$fa-var-cheese: \f7ef; -$fa-var-yin-yang: \f6ad; -$fa-var-music: \f001; -$fa-var-code-commit: \f386; -$fa-var-temperature-low: \f76b; -$fa-var-person-biking: \f84a; -$fa-var-biking: \f84a; -$fa-var-broom: \f51a; -$fa-var-shield-heart: \e574; -$fa-var-gopuram: \f664; -$fa-var-earth-oceania: \e47b; -$fa-var-globe-oceania: \e47b; -$fa-var-square-xmark: \f2d3; -$fa-var-times-square: \f2d3; -$fa-var-xmark-square: \f2d3; -$fa-var-hashtag: \23; -$fa-var-up-right-and-down-left-from-center: \f424; -$fa-var-expand-alt: \f424; -$fa-var-oil-can: \f613; -$fa-var-t: \54; -$fa-var-hippo: \f6ed; -$fa-var-chart-column: \e0e3; -$fa-var-infinity: \f534; -$fa-var-vial-circle-check: \e596; -$fa-var-person-arrow-down-to-line: \e538; -$fa-var-voicemail: \f897; -$fa-var-fan: \f863; -$fa-var-person-walking-luggage: \e554; -$fa-var-up-down: \f338; -$fa-var-arrows-alt-v: \f338; -$fa-var-cloud-moon-rain: \f73c; -$fa-var-calendar: \f133; -$fa-var-trailer: \e041; -$fa-var-bahai: \f666; -$fa-var-haykal: \f666; -$fa-var-sd-card: \f7c2; -$fa-var-dragon: \f6d5; -$fa-var-shoe-prints: \f54b; -$fa-var-circle-plus: \f055; -$fa-var-plus-circle: \f055; -$fa-var-face-grin-tongue-wink: \f58b; -$fa-var-grin-tongue-wink: \f58b; -$fa-var-hand-holding: \f4bd; -$fa-var-plug-circle-exclamation: \e55d; -$fa-var-link-slash: \f127; -$fa-var-chain-broken: \f127; -$fa-var-chain-slash: \f127; -$fa-var-unlink: \f127; -$fa-var-clone: \f24d; -$fa-var-person-walking-arrow-loop-left: \e551; -$fa-var-arrow-up-z-a: \f882; -$fa-var-sort-alpha-up-alt: \f882; -$fa-var-fire-flame-curved: \f7e4; -$fa-var-fire-alt: \f7e4; -$fa-var-tornado: \f76f; -$fa-var-file-circle-plus: \e494; -$fa-var-book-quran: \f687; -$fa-var-quran: \f687; -$fa-var-anchor: \f13d; -$fa-var-border-all: \f84c; -$fa-var-face-angry: \f556; -$fa-var-angry: \f556; -$fa-var-cookie-bite: \f564; -$fa-var-arrow-trend-down: \e097; -$fa-var-rss: \f09e; -$fa-var-feed: \f09e; -$fa-var-draw-polygon: \f5ee; -$fa-var-scale-balanced: \f24e; -$fa-var-balance-scale: \f24e; -$fa-var-gauge-simple-high: \f62a; -$fa-var-tachometer: \f62a; -$fa-var-tachometer-fast: \f62a; -$fa-var-shower: \f2cc; -$fa-var-desktop: \f390; -$fa-var-desktop-alt: \f390; -$fa-var-m: \4d; -$fa-var-table-list: \f00b; -$fa-var-th-list: \f00b; -$fa-var-comment-sms: \f7cd; -$fa-var-sms: \f7cd; -$fa-var-book: \f02d; -$fa-var-user-plus: \f234; -$fa-var-check: \f00c; -$fa-var-battery-three-quarters: \f241; -$fa-var-battery-4: \f241; -$fa-var-house-circle-check: \e509; -$fa-var-angle-left: \f104; -$fa-var-diagram-successor: \e47a; -$fa-var-truck-arrow-right: \e58b; -$fa-var-arrows-split-up-and-left: \e4bc; -$fa-var-hand-fist: \f6de; -$fa-var-fist-raised: \f6de; -$fa-var-cloud-moon: \f6c3; -$fa-var-briefcase: \f0b1; -$fa-var-person-falling: \e546; -$fa-var-image-portrait: \f3e0; -$fa-var-portrait: \f3e0; -$fa-var-user-tag: \f507; -$fa-var-rug: \e569; -$fa-var-earth-europe: \f7a2; -$fa-var-globe-europe: \f7a2; -$fa-var-cart-flatbed-suitcase: \f59d; -$fa-var-luggage-cart: \f59d; -$fa-var-rectangle-xmark: \f410; -$fa-var-rectangle-times: \f410; -$fa-var-times-rectangle: \f410; -$fa-var-window-close: \f410; -$fa-var-baht-sign: \e0ac; -$fa-var-book-open: \f518; -$fa-var-book-journal-whills: \f66a; -$fa-var-journal-whills: \f66a; -$fa-var-handcuffs: \e4f8; -$fa-var-triangle-exclamation: \f071; -$fa-var-exclamation-triangle: \f071; -$fa-var-warning: \f071; -$fa-var-database: \f1c0; -$fa-var-share: \f064; -$fa-var-arrow-turn-right: \f064; -$fa-var-mail-forward: \f064; -$fa-var-bottle-droplet: \e4c4; -$fa-var-mask-face: \e1d7; -$fa-var-hill-rockslide: \e508; -$fa-var-right-left: \f362; -$fa-var-exchange-alt: \f362; -$fa-var-paper-plane: \f1d8; -$fa-var-road-circle-exclamation: \e565; -$fa-var-dungeon: \f6d9; -$fa-var-align-right: \f038; -$fa-var-money-bill-1-wave: \f53b; -$fa-var-money-bill-wave-alt: \f53b; -$fa-var-life-ring: \f1cd; -$fa-var-hands: \f2a7; -$fa-var-sign-language: \f2a7; -$fa-var-signing: \f2a7; -$fa-var-calendar-day: \f783; -$fa-var-water-ladder: \f5c5; -$fa-var-ladder-water: \f5c5; -$fa-var-swimming-pool: \f5c5; -$fa-var-arrows-up-down: \f07d; -$fa-var-arrows-v: \f07d; -$fa-var-face-grimace: \f57f; -$fa-var-grimace: \f57f; -$fa-var-wheelchair-move: \e2ce; -$fa-var-wheelchair-alt: \e2ce; -$fa-var-turn-down: \f3be; -$fa-var-level-down-alt: \f3be; -$fa-var-person-walking-arrow-right: \e552; -$fa-var-square-envelope: \f199; -$fa-var-envelope-square: \f199; -$fa-var-dice: \f522; -$fa-var-bowling-ball: \f436; -$fa-var-brain: \f5dc; -$fa-var-bandage: \f462; -$fa-var-band-aid: \f462; -$fa-var-calendar-minus: \f272; -$fa-var-circle-xmark: \f057; -$fa-var-times-circle: \f057; -$fa-var-xmark-circle: \f057; -$fa-var-gifts: \f79c; -$fa-var-hotel: \f594; -$fa-var-earth-asia: \f57e; -$fa-var-globe-asia: \f57e; -$fa-var-id-card-clip: \f47f; -$fa-var-id-card-alt: \f47f; -$fa-var-magnifying-glass-plus: \f00e; -$fa-var-search-plus: \f00e; -$fa-var-thumbs-up: \f164; -$fa-var-user-clock: \f4fd; -$fa-var-hand-dots: \f461; -$fa-var-allergies: \f461; -$fa-var-file-invoice: \f570; -$fa-var-window-minimize: \f2d1; -$fa-var-mug-saucer: \f0f4; -$fa-var-coffee: \f0f4; -$fa-var-brush: \f55d; -$fa-var-mask: \f6fa; -$fa-var-magnifying-glass-minus: \f010; -$fa-var-search-minus: \f010; -$fa-var-ruler-vertical: \f548; -$fa-var-user-large: \f406; -$fa-var-user-alt: \f406; -$fa-var-train-tram: \e5b4; -$fa-var-user-nurse: \f82f; -$fa-var-syringe: \f48e; -$fa-var-cloud-sun: \f6c4; -$fa-var-stopwatch-20: \e06f; -$fa-var-square-full: \f45c; -$fa-var-magnet: \f076; -$fa-var-jar: \e516; -$fa-var-note-sticky: \f249; -$fa-var-sticky-note: \f249; -$fa-var-bug-slash: \e490; -$fa-var-arrow-up-from-water-pump: \e4b6; -$fa-var-bone: \f5d7; -$fa-var-user-injured: \f728; -$fa-var-face-sad-tear: \f5b4; -$fa-var-sad-tear: \f5b4; -$fa-var-plane: \f072; -$fa-var-tent-arrows-down: \e581; -$fa-var-exclamation: \21; -$fa-var-arrows-spin: \e4bb; -$fa-var-print: \f02f; -$fa-var-turkish-lira-sign: \e2bb; -$fa-var-try: \e2bb; -$fa-var-turkish-lira: \e2bb; -$fa-var-dollar-sign: \24; -$fa-var-dollar: \24; -$fa-var-usd: \24; -$fa-var-x: \58; -$fa-var-magnifying-glass-dollar: \f688; -$fa-var-search-dollar: \f688; -$fa-var-users-gear: \f509; -$fa-var-users-cog: \f509; -$fa-var-person-military-pointing: \e54a; -$fa-var-building-columns: \f19c; -$fa-var-bank: \f19c; -$fa-var-institution: \f19c; -$fa-var-museum: \f19c; -$fa-var-university: \f19c; -$fa-var-umbrella: \f0e9; -$fa-var-trowel: \e589; -$fa-var-d: \44; -$fa-var-stapler: \e5af; -$fa-var-masks-theater: \f630; -$fa-var-theater-masks: \f630; -$fa-var-kip-sign: \e1c4; -$fa-var-hand-point-left: \f0a5; -$fa-var-handshake-simple: \f4c6; -$fa-var-handshake-alt: \f4c6; -$fa-var-jet-fighter: \f0fb; -$fa-var-fighter-jet: \f0fb; -$fa-var-square-share-nodes: \f1e1; -$fa-var-share-alt-square: \f1e1; -$fa-var-barcode: \f02a; -$fa-var-plus-minus: \e43c; -$fa-var-video: \f03d; -$fa-var-video-camera: \f03d; -$fa-var-graduation-cap: \f19d; -$fa-var-mortar-board: \f19d; -$fa-var-hand-holding-medical: \e05c; -$fa-var-person-circle-check: \e53e; -$fa-var-turn-up: \f3bf; -$fa-var-level-up-alt: \f3bf; - -$fa-var-monero: \f3d0; -$fa-var-hooli: \f427; -$fa-var-yelp: \f1e9; -$fa-var-cc-visa: \f1f0; -$fa-var-lastfm: \f202; -$fa-var-shopware: \f5b5; -$fa-var-creative-commons-nc: \f4e8; -$fa-var-aws: \f375; -$fa-var-redhat: \f7bc; -$fa-var-yoast: \f2b1; -$fa-var-cloudflare: \e07d; -$fa-var-ups: \f7e0; -$fa-var-wpexplorer: \f2de; -$fa-var-dyalog: \f399; -$fa-var-bity: \f37a; -$fa-var-stackpath: \f842; -$fa-var-buysellads: \f20d; -$fa-var-first-order: \f2b0; -$fa-var-modx: \f285; -$fa-var-guilded: \e07e; -$fa-var-vnv: \f40b; -$fa-var-square-js: \f3b9; -$fa-var-js-square: \f3b9; -$fa-var-microsoft: \f3ca; -$fa-var-qq: \f1d6; -$fa-var-orcid: \f8d2; -$fa-var-java: \f4e4; -$fa-var-invision: \f7b0; -$fa-var-creative-commons-pd-alt: \f4ed; -$fa-var-centercode: \f380; -$fa-var-glide-g: \f2a6; -$fa-var-drupal: \f1a9; -$fa-var-hire-a-helper: \f3b0; -$fa-var-creative-commons-by: \f4e7; -$fa-var-unity: \e049; -$fa-var-whmcs: \f40d; -$fa-var-rocketchat: \f3e8; -$fa-var-vk: \f189; -$fa-var-untappd: \f405; -$fa-var-mailchimp: \f59e; -$fa-var-css3-alt: \f38b; -$fa-var-square-reddit: \f1a2; -$fa-var-reddit-square: \f1a2; -$fa-var-vimeo-v: \f27d; -$fa-var-contao: \f26d; -$fa-var-square-font-awesome: \e5ad; -$fa-var-deskpro: \f38f; -$fa-var-sistrix: \f3ee; -$fa-var-square-instagram: \e055; -$fa-var-instagram-square: \e055; -$fa-var-battle-net: \f835; -$fa-var-the-red-yeti: \f69d; -$fa-var-square-hacker-news: \f3af; -$fa-var-hacker-news-square: \f3af; -$fa-var-edge: \f282; -$fa-var-napster: \f3d2; -$fa-var-square-snapchat: \f2ad; -$fa-var-snapchat-square: \f2ad; -$fa-var-google-plus-g: \f0d5; -$fa-var-artstation: \f77a; -$fa-var-markdown: \f60f; -$fa-var-sourcetree: \f7d3; -$fa-var-google-plus: \f2b3; -$fa-var-diaspora: \f791; -$fa-var-foursquare: \f180; -$fa-var-stack-overflow: \f16c; -$fa-var-github-alt: \f113; -$fa-var-phoenix-squadron: \f511; -$fa-var-pagelines: \f18c; -$fa-var-algolia: \f36c; -$fa-var-red-river: \f3e3; -$fa-var-creative-commons-sa: \f4ef; -$fa-var-safari: \f267; -$fa-var-google: \f1a0; -$fa-var-square-font-awesome-stroke: \f35c; -$fa-var-font-awesome-alt: \f35c; -$fa-var-atlassian: \f77b; -$fa-var-linkedin-in: \f0e1; -$fa-var-digital-ocean: \f391; -$fa-var-nimblr: \f5a8; -$fa-var-chromecast: \f838; -$fa-var-evernote: \f839; -$fa-var-hacker-news: \f1d4; -$fa-var-creative-commons-sampling: \f4f0; -$fa-var-adversal: \f36a; -$fa-var-creative-commons: \f25e; -$fa-var-watchman-monitoring: \e087; -$fa-var-fonticons: \f280; -$fa-var-weixin: \f1d7; -$fa-var-shirtsinbulk: \f214; -$fa-var-codepen: \f1cb; -$fa-var-git-alt: \f841; -$fa-var-lyft: \f3c3; -$fa-var-rev: \f5b2; -$fa-var-windows: \f17a; -$fa-var-wizards-of-the-coast: \f730; -$fa-var-square-viadeo: \f2aa; -$fa-var-viadeo-square: \f2aa; -$fa-var-meetup: \f2e0; -$fa-var-centos: \f789; -$fa-var-adn: \f170; -$fa-var-cloudsmith: \f384; -$fa-var-pied-piper-alt: \f1a8; -$fa-var-square-dribbble: \f397; -$fa-var-dribbble-square: \f397; -$fa-var-codiepie: \f284; -$fa-var-node: \f419; -$fa-var-mix: \f3cb; -$fa-var-steam: \f1b6; -$fa-var-cc-apple-pay: \f416; -$fa-var-scribd: \f28a; -$fa-var-openid: \f19b; -$fa-var-instalod: \e081; -$fa-var-expeditedssl: \f23e; -$fa-var-sellcast: \f2da; -$fa-var-square-twitter: \f081; -$fa-var-twitter-square: \f081; -$fa-var-r-project: \f4f7; -$fa-var-delicious: \f1a5; -$fa-var-freebsd: \f3a4; -$fa-var-vuejs: \f41f; -$fa-var-accusoft: \f369; -$fa-var-ioxhost: \f208; -$fa-var-fonticons-fi: \f3a2; -$fa-var-app-store: \f36f; -$fa-var-cc-mastercard: \f1f1; -$fa-var-itunes-note: \f3b5; -$fa-var-golang: \e40f; -$fa-var-kickstarter: \f3bb; -$fa-var-grav: \f2d6; -$fa-var-weibo: \f18a; -$fa-var-uncharted: \e084; -$fa-var-firstdraft: \f3a1; -$fa-var-square-youtube: \f431; -$fa-var-youtube-square: \f431; -$fa-var-wikipedia-w: \f266; -$fa-var-wpressr: \f3e4; -$fa-var-rendact: \f3e4; -$fa-var-angellist: \f209; -$fa-var-galactic-republic: \f50c; -$fa-var-nfc-directional: \e530; -$fa-var-skype: \f17e; -$fa-var-joget: \f3b7; -$fa-var-fedora: \f798; -$fa-var-stripe-s: \f42a; -$fa-var-meta: \e49b; -$fa-var-laravel: \f3bd; -$fa-var-hotjar: \f3b1; -$fa-var-bluetooth-b: \f294; -$fa-var-sticker-mule: \f3f7; -$fa-var-creative-commons-zero: \f4f3; -$fa-var-hips: \f452; -$fa-var-behance: \f1b4; -$fa-var-reddit: \f1a1; -$fa-var-discord: \f392; -$fa-var-chrome: \f268; -$fa-var-app-store-ios: \f370; -$fa-var-cc-discover: \f1f2; -$fa-var-wpbeginner: \f297; -$fa-var-confluence: \f78d; -$fa-var-mdb: \f8ca; -$fa-var-dochub: \f394; -$fa-var-accessible-icon: \f368; -$fa-var-ebay: \f4f4; -$fa-var-amazon: \f270; -$fa-var-unsplash: \e07c; -$fa-var-yarn: \f7e3; -$fa-var-square-steam: \f1b7; -$fa-var-steam-square: \f1b7; -$fa-var-500px: \f26e; -$fa-var-square-vimeo: \f194; -$fa-var-vimeo-square: \f194; -$fa-var-asymmetrik: \f372; -$fa-var-font-awesome: \f2b4; -$fa-var-font-awesome-flag: \f2b4; -$fa-var-font-awesome-logo-full: \f2b4; -$fa-var-gratipay: \f184; -$fa-var-apple: \f179; -$fa-var-hive: \e07f; -$fa-var-gitkraken: \f3a6; -$fa-var-keybase: \f4f5; -$fa-var-apple-pay: \f415; -$fa-var-padlet: \e4a0; -$fa-var-amazon-pay: \f42c; -$fa-var-square-github: \f092; -$fa-var-github-square: \f092; -$fa-var-stumbleupon: \f1a4; -$fa-var-fedex: \f797; -$fa-var-phoenix-framework: \f3dc; -$fa-var-shopify: \e057; -$fa-var-neos: \f612; -$fa-var-hackerrank: \f5f7; -$fa-var-researchgate: \f4f8; -$fa-var-swift: \f8e1; -$fa-var-angular: \f420; -$fa-var-speakap: \f3f3; -$fa-var-angrycreative: \f36e; -$fa-var-y-combinator: \f23b; -$fa-var-empire: \f1d1; -$fa-var-envira: \f299; -$fa-var-square-gitlab: \e5ae; -$fa-var-gitlab-square: \e5ae; -$fa-var-studiovinari: \f3f8; -$fa-var-pied-piper: \f2ae; -$fa-var-wordpress: \f19a; -$fa-var-product-hunt: \f288; -$fa-var-firefox: \f269; -$fa-var-linode: \f2b8; -$fa-var-goodreads: \f3a8; -$fa-var-square-odnoklassniki: \f264; -$fa-var-odnoklassniki-square: \f264; -$fa-var-jsfiddle: \f1cc; -$fa-var-sith: \f512; -$fa-var-themeisle: \f2b2; -$fa-var-page4: \f3d7; -$fa-var-hashnode: \e499; -$fa-var-react: \f41b; -$fa-var-cc-paypal: \f1f4; -$fa-var-squarespace: \f5be; -$fa-var-cc-stripe: \f1f5; -$fa-var-creative-commons-share: \f4f2; -$fa-var-bitcoin: \f379; -$fa-var-keycdn: \f3ba; -$fa-var-opera: \f26a; -$fa-var-itch-io: \f83a; -$fa-var-umbraco: \f8e8; -$fa-var-galactic-senate: \f50d; -$fa-var-ubuntu: \f7df; -$fa-var-draft2digital: \f396; -$fa-var-stripe: \f429; -$fa-var-houzz: \f27c; -$fa-var-gg: \f260; -$fa-var-dhl: \f790; -$fa-var-square-pinterest: \f0d3; -$fa-var-pinterest-square: \f0d3; -$fa-var-xing: \f168; -$fa-var-blackberry: \f37b; -$fa-var-creative-commons-pd: \f4ec; -$fa-var-playstation: \f3df; -$fa-var-quinscape: \f459; -$fa-var-less: \f41d; -$fa-var-blogger-b: \f37d; -$fa-var-opencart: \f23d; -$fa-var-vine: \f1ca; -$fa-var-paypal: \f1ed; -$fa-var-gitlab: \f296; -$fa-var-typo3: \f42b; -$fa-var-reddit-alien: \f281; -$fa-var-yahoo: \f19e; -$fa-var-dailymotion: \e052; -$fa-var-affiliatetheme: \f36b; -$fa-var-pied-piper-pp: \f1a7; -$fa-var-bootstrap: \f836; -$fa-var-odnoklassniki: \f263; -$fa-var-nfc-symbol: \e531; -$fa-var-ethereum: \f42e; -$fa-var-speaker-deck: \f83c; -$fa-var-creative-commons-nc-eu: \f4e9; -$fa-var-patreon: \f3d9; -$fa-var-avianex: \f374; -$fa-var-ello: \f5f1; -$fa-var-gofore: \f3a7; -$fa-var-bimobject: \f378; -$fa-var-facebook-f: \f39e; -$fa-var-square-google-plus: \f0d4; -$fa-var-google-plus-square: \f0d4; -$fa-var-mandalorian: \f50f; -$fa-var-first-order-alt: \f50a; -$fa-var-osi: \f41a; -$fa-var-google-wallet: \f1ee; -$fa-var-d-and-d-beyond: \f6ca; -$fa-var-periscope: \f3da; -$fa-var-fulcrum: \f50b; -$fa-var-cloudscale: \f383; -$fa-var-forumbee: \f211; -$fa-var-mizuni: \f3cc; -$fa-var-schlix: \f3ea; -$fa-var-square-xing: \f169; -$fa-var-xing-square: \f169; -$fa-var-bandcamp: \f2d5; -$fa-var-wpforms: \f298; -$fa-var-cloudversify: \f385; -$fa-var-usps: \f7e1; -$fa-var-megaport: \f5a3; -$fa-var-magento: \f3c4; -$fa-var-spotify: \f1bc; -$fa-var-optin-monster: \f23c; -$fa-var-fly: \f417; -$fa-var-aviato: \f421; -$fa-var-itunes: \f3b4; -$fa-var-cuttlefish: \f38c; -$fa-var-blogger: \f37c; -$fa-var-flickr: \f16e; -$fa-var-viber: \f409; -$fa-var-soundcloud: \f1be; -$fa-var-digg: \f1a6; -$fa-var-tencent-weibo: \f1d5; -$fa-var-symfony: \f83d; -$fa-var-maxcdn: \f136; -$fa-var-etsy: \f2d7; -$fa-var-facebook-messenger: \f39f; -$fa-var-audible: \f373; -$fa-var-think-peaks: \f731; -$fa-var-bilibili: \e3d9; -$fa-var-erlang: \f39d; -$fa-var-cotton-bureau: \f89e; -$fa-var-dashcube: \f210; -$fa-var-42-group: \e080; -$fa-var-innosoft: \e080; -$fa-var-stack-exchange: \f18d; -$fa-var-elementor: \f430; -$fa-var-square-pied-piper: \e01e; -$fa-var-pied-piper-square: \e01e; -$fa-var-creative-commons-nd: \f4eb; -$fa-var-palfed: \f3d8; -$fa-var-superpowers: \f2dd; -$fa-var-resolving: \f3e7; -$fa-var-xbox: \f412; -$fa-var-searchengin: \f3eb; -$fa-var-tiktok: \e07b; -$fa-var-square-facebook: \f082; -$fa-var-facebook-square: \f082; -$fa-var-renren: \f18b; -$fa-var-linux: \f17c; -$fa-var-glide: \f2a5; -$fa-var-linkedin: \f08c; -$fa-var-hubspot: \f3b2; -$fa-var-deploydog: \f38e; -$fa-var-twitch: \f1e8; -$fa-var-ravelry: \f2d9; -$fa-var-mixer: \e056; -$fa-var-square-lastfm: \f203; -$fa-var-lastfm-square: \f203; -$fa-var-vimeo: \f40a; -$fa-var-mendeley: \f7b3; -$fa-var-uniregistry: \f404; -$fa-var-figma: \f799; -$fa-var-creative-commons-remix: \f4ee; -$fa-var-cc-amazon-pay: \f42d; -$fa-var-dropbox: \f16b; -$fa-var-instagram: \f16d; -$fa-var-cmplid: \e360; -$fa-var-facebook: \f09a; -$fa-var-gripfire: \f3ac; -$fa-var-jedi-order: \f50e; -$fa-var-uikit: \f403; -$fa-var-fort-awesome-alt: \f3a3; -$fa-var-phabricator: \f3db; -$fa-var-ussunnah: \f407; -$fa-var-earlybirds: \f39a; -$fa-var-trade-federation: \f513; -$fa-var-autoprefixer: \f41c; -$fa-var-whatsapp: \f232; -$fa-var-slideshare: \f1e7; -$fa-var-google-play: \f3ab; -$fa-var-viadeo: \f2a9; -$fa-var-line: \f3c0; -$fa-var-google-drive: \f3aa; -$fa-var-servicestack: \f3ec; -$fa-var-simplybuilt: \f215; -$fa-var-bitbucket: \f171; -$fa-var-imdb: \f2d8; -$fa-var-deezer: \e077; -$fa-var-raspberry-pi: \f7bb; -$fa-var-jira: \f7b1; -$fa-var-docker: \f395; -$fa-var-screenpal: \e570; -$fa-var-bluetooth: \f293; -$fa-var-gitter: \f426; -$fa-var-d-and-d: \f38d; -$fa-var-microblog: \e01a; -$fa-var-cc-diners-club: \f24c; -$fa-var-gg-circle: \f261; -$fa-var-pied-piper-hat: \f4e5; -$fa-var-kickstarter-k: \f3bc; -$fa-var-yandex: \f413; -$fa-var-readme: \f4d5; -$fa-var-html5: \f13b; -$fa-var-sellsy: \f213; -$fa-var-sass: \f41e; -$fa-var-wirsindhandwerk: \e2d0; -$fa-var-wsh: \e2d0; -$fa-var-buromobelexperte: \f37f; -$fa-var-salesforce: \f83b; -$fa-var-octopus-deploy: \e082; -$fa-var-medapps: \f3c6; -$fa-var-ns8: \f3d5; -$fa-var-pinterest-p: \f231; -$fa-var-apper: \f371; -$fa-var-fort-awesome: \f286; -$fa-var-waze: \f83f; -$fa-var-cc-jcb: \f24b; -$fa-var-snapchat: \f2ab; -$fa-var-snapchat-ghost: \f2ab; -$fa-var-fantasy-flight-games: \f6dc; -$fa-var-rust: \e07a; -$fa-var-wix: \f5cf; -$fa-var-square-behance: \f1b5; -$fa-var-behance-square: \f1b5; -$fa-var-supple: \f3f9; -$fa-var-rebel: \f1d0; -$fa-var-css3: \f13c; -$fa-var-staylinked: \f3f5; -$fa-var-kaggle: \f5fa; -$fa-var-space-awesome: \e5ac; -$fa-var-deviantart: \f1bd; -$fa-var-cpanel: \f388; -$fa-var-goodreads-g: \f3a9; -$fa-var-square-git: \f1d2; -$fa-var-git-square: \f1d2; -$fa-var-square-tumblr: \f174; -$fa-var-tumblr-square: \f174; -$fa-var-trello: \f181; -$fa-var-creative-commons-nc-jp: \f4ea; -$fa-var-get-pocket: \f265; -$fa-var-perbyte: \e083; -$fa-var-grunt: \f3ad; -$fa-var-weebly: \f5cc; -$fa-var-connectdevelop: \f20e; -$fa-var-leanpub: \f212; -$fa-var-black-tie: \f27e; -$fa-var-themeco: \f5c6; -$fa-var-python: \f3e2; -$fa-var-android: \f17b; -$fa-var-bots: \e340; -$fa-var-free-code-camp: \f2c5; -$fa-var-hornbill: \f592; -$fa-var-js: \f3b8; -$fa-var-ideal: \e013; -$fa-var-git: \f1d3; -$fa-var-dev: \f6cc; -$fa-var-sketch: \f7c6; -$fa-var-yandex-international: \f414; -$fa-var-cc-amex: \f1f3; -$fa-var-uber: \f402; -$fa-var-github: \f09b; -$fa-var-php: \f457; -$fa-var-alipay: \f642; -$fa-var-youtube: \f167; -$fa-var-skyatlas: \f216; -$fa-var-firefox-browser: \e007; -$fa-var-replyd: \f3e6; -$fa-var-suse: \f7d6; -$fa-var-jenkins: \f3b6; -$fa-var-twitter: \f099; -$fa-var-rockrms: \f3e9; -$fa-var-pinterest: \f0d2; -$fa-var-buffer: \f837; -$fa-var-npm: \f3d4; -$fa-var-yammer: \f840; -$fa-var-btc: \f15a; -$fa-var-dribbble: \f17d; -$fa-var-stumbleupon-circle: \f1a3; -$fa-var-internet-explorer: \f26b; -$fa-var-telegram: \f2c6; -$fa-var-telegram-plane: \f2c6; -$fa-var-old-republic: \f510; -$fa-var-square-whatsapp: \f40c; -$fa-var-whatsapp-square: \f40c; -$fa-var-node-js: \f3d3; -$fa-var-edge-legacy: \e078; -$fa-var-slack: \f198; -$fa-var-slack-hash: \f198; -$fa-var-medrt: \f3c8; -$fa-var-usb: \f287; -$fa-var-tumblr: \f173; -$fa-var-vaadin: \f408; -$fa-var-quora: \f2c4; -$fa-var-reacteurope: \f75d; -$fa-var-medium: \f23a; -$fa-var-medium-m: \f23a; -$fa-var-amilia: \f36d; -$fa-var-mixcloud: \f289; -$fa-var-flipboard: \f44d; -$fa-var-viacoin: \f237; -$fa-var-critical-role: \f6c9; -$fa-var-sitrox: \e44a; -$fa-var-discourse: \f393; -$fa-var-joomla: \f1aa; -$fa-var-mastodon: \f4f6; -$fa-var-airbnb: \f834; -$fa-var-wolf-pack-battalion: \f514; -$fa-var-buy-n-large: \f8a6; -$fa-var-gulp: \f3ae; -$fa-var-creative-commons-sampling-plus: \f4f1; -$fa-var-strava: \f428; -$fa-var-ember: \f423; -$fa-var-canadian-maple-leaf: \f785; -$fa-var-teamspeak: \f4f9; -$fa-var-pushed: \f3e1; -$fa-var-wordpress-simple: \f411; -$fa-var-nutritionix: \f3d6; -$fa-var-wodu: \e088; -$fa-var-google-pay: \e079; -$fa-var-intercom: \f7af; -$fa-var-zhihu: \f63f; -$fa-var-korvue: \f42f; -$fa-var-pix: \e43a; -$fa-var-steam-symbol: \f3f6; - -$fa-icons: ( - "0": $fa-var-0, - "1": $fa-var-1, - "2": $fa-var-2, - "3": $fa-var-3, - "4": $fa-var-4, - "5": $fa-var-5, - "6": $fa-var-6, - "7": $fa-var-7, - "8": $fa-var-8, - "9": $fa-var-9, - "fill-drip": $fa-var-fill-drip, - "arrows-to-circle": $fa-var-arrows-to-circle, - "circle-chevron-right": $fa-var-circle-chevron-right, - "chevron-circle-right": $fa-var-chevron-circle-right, - "at": $fa-var-at, - "trash-can": $fa-var-trash-can, - "trash-alt": $fa-var-trash-alt, - "text-height": $fa-var-text-height, - "user-xmark": $fa-var-user-xmark, - "user-times": $fa-var-user-times, - "stethoscope": $fa-var-stethoscope, - "message": $fa-var-message, - "comment-alt": $fa-var-comment-alt, - "info": $fa-var-info, - "down-left-and-up-right-to-center": $fa-var-down-left-and-up-right-to-center, - "compress-alt": $fa-var-compress-alt, - "explosion": $fa-var-explosion, - "file-lines": $fa-var-file-lines, - "file-alt": $fa-var-file-alt, - "file-text": $fa-var-file-text, - "wave-square": $fa-var-wave-square, - "ring": $fa-var-ring, - "building-un": $fa-var-building-un, - "dice-three": $fa-var-dice-three, - "calendar-days": $fa-var-calendar-days, - "calendar-alt": $fa-var-calendar-alt, - "anchor-circle-check": $fa-var-anchor-circle-check, - "building-circle-arrow-right": $fa-var-building-circle-arrow-right, - "volleyball": $fa-var-volleyball, - "volleyball-ball": $fa-var-volleyball-ball, - "arrows-up-to-line": $fa-var-arrows-up-to-line, - "sort-down": $fa-var-sort-down, - "sort-desc": $fa-var-sort-desc, - "circle-minus": $fa-var-circle-minus, - "minus-circle": $fa-var-minus-circle, - "door-open": $fa-var-door-open, - "right-from-bracket": $fa-var-right-from-bracket, - "sign-out-alt": $fa-var-sign-out-alt, - "atom": $fa-var-atom, - "soap": $fa-var-soap, - "icons": $fa-var-icons, - "heart-music-camera-bolt": $fa-var-heart-music-camera-bolt, - "microphone-lines-slash": $fa-var-microphone-lines-slash, - "microphone-alt-slash": $fa-var-microphone-alt-slash, - "bridge-circle-check": $fa-var-bridge-circle-check, - "pump-medical": $fa-var-pump-medical, - "fingerprint": $fa-var-fingerprint, - "hand-point-right": $fa-var-hand-point-right, - "magnifying-glass-location": $fa-var-magnifying-glass-location, - "search-location": $fa-var-search-location, - "forward-step": $fa-var-forward-step, - "step-forward": $fa-var-step-forward, - "face-smile-beam": $fa-var-face-smile-beam, - "smile-beam": $fa-var-smile-beam, - "flag-checkered": $fa-var-flag-checkered, - "football": $fa-var-football, - "football-ball": $fa-var-football-ball, - "school-circle-exclamation": $fa-var-school-circle-exclamation, - "crop": $fa-var-crop, - "angles-down": $fa-var-angles-down, - "angle-double-down": $fa-var-angle-double-down, - "users-rectangle": $fa-var-users-rectangle, - "people-roof": $fa-var-people-roof, - "people-line": $fa-var-people-line, - "beer-mug-empty": $fa-var-beer-mug-empty, - "beer": $fa-var-beer, - "diagram-predecessor": $fa-var-diagram-predecessor, - "arrow-up-long": $fa-var-arrow-up-long, - "long-arrow-up": $fa-var-long-arrow-up, - "fire-flame-simple": $fa-var-fire-flame-simple, - "burn": $fa-var-burn, - "person": $fa-var-person, - "male": $fa-var-male, - "laptop": $fa-var-laptop, - "file-csv": $fa-var-file-csv, - "menorah": $fa-var-menorah, - "truck-plane": $fa-var-truck-plane, - "record-vinyl": $fa-var-record-vinyl, - "face-grin-stars": $fa-var-face-grin-stars, - "grin-stars": $fa-var-grin-stars, - "bong": $fa-var-bong, - "spaghetti-monster-flying": $fa-var-spaghetti-monster-flying, - "pastafarianism": $fa-var-pastafarianism, - "arrow-down-up-across-line": $fa-var-arrow-down-up-across-line, - "spoon": $fa-var-spoon, - "utensil-spoon": $fa-var-utensil-spoon, - "jar-wheat": $fa-var-jar-wheat, - "envelopes-bulk": $fa-var-envelopes-bulk, - "mail-bulk": $fa-var-mail-bulk, - "file-circle-exclamation": $fa-var-file-circle-exclamation, - "circle-h": $fa-var-circle-h, - "hospital-symbol": $fa-var-hospital-symbol, - "pager": $fa-var-pager, - "address-book": $fa-var-address-book, - "contact-book": $fa-var-contact-book, - "strikethrough": $fa-var-strikethrough, - "k": $fa-var-k, - "landmark-flag": $fa-var-landmark-flag, - "pencil": $fa-var-pencil, - "pencil-alt": $fa-var-pencil-alt, - "backward": $fa-var-backward, - "caret-right": $fa-var-caret-right, - "comments": $fa-var-comments, - "paste": $fa-var-paste, - "file-clipboard": $fa-var-file-clipboard, - "code-pull-request": $fa-var-code-pull-request, - "clipboard-list": $fa-var-clipboard-list, - "truck-ramp-box": $fa-var-truck-ramp-box, - "truck-loading": $fa-var-truck-loading, - "user-check": $fa-var-user-check, - "vial-virus": $fa-var-vial-virus, - "sheet-plastic": $fa-var-sheet-plastic, - "blog": $fa-var-blog, - "user-ninja": $fa-var-user-ninja, - "person-arrow-up-from-line": $fa-var-person-arrow-up-from-line, - "scroll-torah": $fa-var-scroll-torah, - "torah": $fa-var-torah, - "broom-ball": $fa-var-broom-ball, - "quidditch": $fa-var-quidditch, - "quidditch-broom-ball": $fa-var-quidditch-broom-ball, - "toggle-off": $fa-var-toggle-off, - "box-archive": $fa-var-box-archive, - "archive": $fa-var-archive, - "person-drowning": $fa-var-person-drowning, - "arrow-down-9-1": $fa-var-arrow-down-9-1, - "sort-numeric-desc": $fa-var-sort-numeric-desc, - "sort-numeric-down-alt": $fa-var-sort-numeric-down-alt, - "face-grin-tongue-squint": $fa-var-face-grin-tongue-squint, - "grin-tongue-squint": $fa-var-grin-tongue-squint, - "spray-can": $fa-var-spray-can, - "truck-monster": $fa-var-truck-monster, - "w": $fa-var-w, - "earth-africa": $fa-var-earth-africa, - "globe-africa": $fa-var-globe-africa, - "rainbow": $fa-var-rainbow, - "circle-notch": $fa-var-circle-notch, - "tablet-screen-button": $fa-var-tablet-screen-button, - "tablet-alt": $fa-var-tablet-alt, - "paw": $fa-var-paw, - "cloud": $fa-var-cloud, - "trowel-bricks": $fa-var-trowel-bricks, - "face-flushed": $fa-var-face-flushed, - "flushed": $fa-var-flushed, - "hospital-user": $fa-var-hospital-user, - "tent-arrow-left-right": $fa-var-tent-arrow-left-right, - "gavel": $fa-var-gavel, - "legal": $fa-var-legal, - "binoculars": $fa-var-binoculars, - "microphone-slash": $fa-var-microphone-slash, - "box-tissue": $fa-var-box-tissue, - "motorcycle": $fa-var-motorcycle, - "bell-concierge": $fa-var-bell-concierge, - "concierge-bell": $fa-var-concierge-bell, - "pen-ruler": $fa-var-pen-ruler, - "pencil-ruler": $fa-var-pencil-ruler, - "people-arrows": $fa-var-people-arrows, - "people-arrows-left-right": $fa-var-people-arrows-left-right, - "mars-and-venus-burst": $fa-var-mars-and-venus-burst, - "square-caret-right": $fa-var-square-caret-right, - "caret-square-right": $fa-var-caret-square-right, - "scissors": $fa-var-scissors, - "cut": $fa-var-cut, - "sun-plant-wilt": $fa-var-sun-plant-wilt, - "toilets-portable": $fa-var-toilets-portable, - "hockey-puck": $fa-var-hockey-puck, - "table": $fa-var-table, - "magnifying-glass-arrow-right": $fa-var-magnifying-glass-arrow-right, - "tachograph-digital": $fa-var-tachograph-digital, - "digital-tachograph": $fa-var-digital-tachograph, - "users-slash": $fa-var-users-slash, - "clover": $fa-var-clover, - "reply": $fa-var-reply, - "mail-reply": $fa-var-mail-reply, - "star-and-crescent": $fa-var-star-and-crescent, - "house-fire": $fa-var-house-fire, - "square-minus": $fa-var-square-minus, - "minus-square": $fa-var-minus-square, - "helicopter": $fa-var-helicopter, - "compass": $fa-var-compass, - "square-caret-down": $fa-var-square-caret-down, - "caret-square-down": $fa-var-caret-square-down, - "file-circle-question": $fa-var-file-circle-question, - "laptop-code": $fa-var-laptop-code, - "swatchbook": $fa-var-swatchbook, - "prescription-bottle": $fa-var-prescription-bottle, - "bars": $fa-var-bars, - "navicon": $fa-var-navicon, - "people-group": $fa-var-people-group, - "hourglass-end": $fa-var-hourglass-end, - "hourglass-3": $fa-var-hourglass-3, - "heart-crack": $fa-var-heart-crack, - "heart-broken": $fa-var-heart-broken, - "square-up-right": $fa-var-square-up-right, - "external-link-square-alt": $fa-var-external-link-square-alt, - "face-kiss-beam": $fa-var-face-kiss-beam, - "kiss-beam": $fa-var-kiss-beam, - "film": $fa-var-film, - "ruler-horizontal": $fa-var-ruler-horizontal, - "people-robbery": $fa-var-people-robbery, - "lightbulb": $fa-var-lightbulb, - "caret-left": $fa-var-caret-left, - "circle-exclamation": $fa-var-circle-exclamation, - "exclamation-circle": $fa-var-exclamation-circle, - "school-circle-xmark": $fa-var-school-circle-xmark, - "arrow-right-from-bracket": $fa-var-arrow-right-from-bracket, - "sign-out": $fa-var-sign-out, - "circle-chevron-down": $fa-var-circle-chevron-down, - "chevron-circle-down": $fa-var-chevron-circle-down, - "unlock-keyhole": $fa-var-unlock-keyhole, - "unlock-alt": $fa-var-unlock-alt, - "cloud-showers-heavy": $fa-var-cloud-showers-heavy, - "headphones-simple": $fa-var-headphones-simple, - "headphones-alt": $fa-var-headphones-alt, - "sitemap": $fa-var-sitemap, - "circle-dollar-to-slot": $fa-var-circle-dollar-to-slot, - "donate": $fa-var-donate, - "memory": $fa-var-memory, - "road-spikes": $fa-var-road-spikes, - "fire-burner": $fa-var-fire-burner, - "flag": $fa-var-flag, - "hanukiah": $fa-var-hanukiah, - "feather": $fa-var-feather, - "volume-low": $fa-var-volume-low, - "volume-down": $fa-var-volume-down, - "comment-slash": $fa-var-comment-slash, - "cloud-sun-rain": $fa-var-cloud-sun-rain, - "compress": $fa-var-compress, - "wheat-awn": $fa-var-wheat-awn, - "wheat-alt": $fa-var-wheat-alt, - "ankh": $fa-var-ankh, - "hands-holding-child": $fa-var-hands-holding-child, - "asterisk": $fa-var-asterisk, - "square-check": $fa-var-square-check, - "check-square": $fa-var-check-square, - "peseta-sign": $fa-var-peseta-sign, - "heading": $fa-var-heading, - "header": $fa-var-header, - "ghost": $fa-var-ghost, - "list": $fa-var-list, - "list-squares": $fa-var-list-squares, - "square-phone-flip": $fa-var-square-phone-flip, - "phone-square-alt": $fa-var-phone-square-alt, - "cart-plus": $fa-var-cart-plus, - "gamepad": $fa-var-gamepad, - "circle-dot": $fa-var-circle-dot, - "dot-circle": $fa-var-dot-circle, - "face-dizzy": $fa-var-face-dizzy, - "dizzy": $fa-var-dizzy, - "egg": $fa-var-egg, - "house-medical-circle-xmark": $fa-var-house-medical-circle-xmark, - "campground": $fa-var-campground, - "folder-plus": $fa-var-folder-plus, - "futbol": $fa-var-futbol, - "futbol-ball": $fa-var-futbol-ball, - "soccer-ball": $fa-var-soccer-ball, - "paintbrush": $fa-var-paintbrush, - "paint-brush": $fa-var-paint-brush, - "lock": $fa-var-lock, - "gas-pump": $fa-var-gas-pump, - "hot-tub-person": $fa-var-hot-tub-person, - "hot-tub": $fa-var-hot-tub, - "map-location": $fa-var-map-location, - "map-marked": $fa-var-map-marked, - "house-flood-water": $fa-var-house-flood-water, - "tree": $fa-var-tree, - "bridge-lock": $fa-var-bridge-lock, - "sack-dollar": $fa-var-sack-dollar, - "pen-to-square": $fa-var-pen-to-square, - "edit": $fa-var-edit, - "car-side": $fa-var-car-side, - "share-nodes": $fa-var-share-nodes, - "share-alt": $fa-var-share-alt, - "heart-circle-minus": $fa-var-heart-circle-minus, - "hourglass-half": $fa-var-hourglass-half, - "hourglass-2": $fa-var-hourglass-2, - "microscope": $fa-var-microscope, - "sink": $fa-var-sink, - "bag-shopping": $fa-var-bag-shopping, - "shopping-bag": $fa-var-shopping-bag, - "arrow-down-z-a": $fa-var-arrow-down-z-a, - "sort-alpha-desc": $fa-var-sort-alpha-desc, - "sort-alpha-down-alt": $fa-var-sort-alpha-down-alt, - "mitten": $fa-var-mitten, - "person-rays": $fa-var-person-rays, - "users": $fa-var-users, - "eye-slash": $fa-var-eye-slash, - "flask-vial": $fa-var-flask-vial, - "hand": $fa-var-hand, - "hand-paper": $fa-var-hand-paper, - "om": $fa-var-om, - "worm": $fa-var-worm, - "house-circle-xmark": $fa-var-house-circle-xmark, - "plug": $fa-var-plug, - "chevron-up": $fa-var-chevron-up, - "hand-spock": $fa-var-hand-spock, - "stopwatch": $fa-var-stopwatch, - "face-kiss": $fa-var-face-kiss, - "kiss": $fa-var-kiss, - "bridge-circle-xmark": $fa-var-bridge-circle-xmark, - "face-grin-tongue": $fa-var-face-grin-tongue, - "grin-tongue": $fa-var-grin-tongue, - "chess-bishop": $fa-var-chess-bishop, - "face-grin-wink": $fa-var-face-grin-wink, - "grin-wink": $fa-var-grin-wink, - "ear-deaf": $fa-var-ear-deaf, - "deaf": $fa-var-deaf, - "deafness": $fa-var-deafness, - "hard-of-hearing": $fa-var-hard-of-hearing, - "road-circle-check": $fa-var-road-circle-check, - "dice-five": $fa-var-dice-five, - "square-rss": $fa-var-square-rss, - "rss-square": $fa-var-rss-square, - "land-mine-on": $fa-var-land-mine-on, - "i-cursor": $fa-var-i-cursor, - "stamp": $fa-var-stamp, - "stairs": $fa-var-stairs, - "i": $fa-var-i, - "hryvnia-sign": $fa-var-hryvnia-sign, - "hryvnia": $fa-var-hryvnia, - "pills": $fa-var-pills, - "face-grin-wide": $fa-var-face-grin-wide, - "grin-alt": $fa-var-grin-alt, - "tooth": $fa-var-tooth, - "v": $fa-var-v, - "bicycle": $fa-var-bicycle, - "staff-snake": $fa-var-staff-snake, - "rod-asclepius": $fa-var-rod-asclepius, - "rod-snake": $fa-var-rod-snake, - "staff-aesculapius": $fa-var-staff-aesculapius, - "head-side-cough-slash": $fa-var-head-side-cough-slash, - "truck-medical": $fa-var-truck-medical, - "ambulance": $fa-var-ambulance, - "wheat-awn-circle-exclamation": $fa-var-wheat-awn-circle-exclamation, - "snowman": $fa-var-snowman, - "mortar-pestle": $fa-var-mortar-pestle, - "road-barrier": $fa-var-road-barrier, - "school": $fa-var-school, - "igloo": $fa-var-igloo, - "joint": $fa-var-joint, - "angle-right": $fa-var-angle-right, - "horse": $fa-var-horse, - "q": $fa-var-q, - "g": $fa-var-g, - "notes-medical": $fa-var-notes-medical, - "temperature-half": $fa-var-temperature-half, - "temperature-2": $fa-var-temperature-2, - "thermometer-2": $fa-var-thermometer-2, - "thermometer-half": $fa-var-thermometer-half, - "dong-sign": $fa-var-dong-sign, - "capsules": $fa-var-capsules, - "poo-storm": $fa-var-poo-storm, - "poo-bolt": $fa-var-poo-bolt, - "face-frown-open": $fa-var-face-frown-open, - "frown-open": $fa-var-frown-open, - "hand-point-up": $fa-var-hand-point-up, - "money-bill": $fa-var-money-bill, - "bookmark": $fa-var-bookmark, - "align-justify": $fa-var-align-justify, - "umbrella-beach": $fa-var-umbrella-beach, - "helmet-un": $fa-var-helmet-un, - "bullseye": $fa-var-bullseye, - "bacon": $fa-var-bacon, - "hand-point-down": $fa-var-hand-point-down, - "arrow-up-from-bracket": $fa-var-arrow-up-from-bracket, - "folder": $fa-var-folder, - "folder-blank": $fa-var-folder-blank, - "file-waveform": $fa-var-file-waveform, - "file-medical-alt": $fa-var-file-medical-alt, - "radiation": $fa-var-radiation, - "chart-simple": $fa-var-chart-simple, - "mars-stroke": $fa-var-mars-stroke, - "vial": $fa-var-vial, - "gauge": $fa-var-gauge, - "dashboard": $fa-var-dashboard, - "gauge-med": $fa-var-gauge-med, - "tachometer-alt-average": $fa-var-tachometer-alt-average, - "wand-magic-sparkles": $fa-var-wand-magic-sparkles, - "magic-wand-sparkles": $fa-var-magic-wand-sparkles, - "e": $fa-var-e, - "pen-clip": $fa-var-pen-clip, - "pen-alt": $fa-var-pen-alt, - "bridge-circle-exclamation": $fa-var-bridge-circle-exclamation, - "user": $fa-var-user, - "school-circle-check": $fa-var-school-circle-check, - "dumpster": $fa-var-dumpster, - "van-shuttle": $fa-var-van-shuttle, - "shuttle-van": $fa-var-shuttle-van, - "building-user": $fa-var-building-user, - "square-caret-left": $fa-var-square-caret-left, - "caret-square-left": $fa-var-caret-square-left, - "highlighter": $fa-var-highlighter, - "key": $fa-var-key, - "bullhorn": $fa-var-bullhorn, - "globe": $fa-var-globe, - "synagogue": $fa-var-synagogue, - "person-half-dress": $fa-var-person-half-dress, - "road-bridge": $fa-var-road-bridge, - "location-arrow": $fa-var-location-arrow, - "c": $fa-var-c, - "tablet-button": $fa-var-tablet-button, - "building-lock": $fa-var-building-lock, - "pizza-slice": $fa-var-pizza-slice, - "money-bill-wave": $fa-var-money-bill-wave, - "chart-area": $fa-var-chart-area, - "area-chart": $fa-var-area-chart, - "house-flag": $fa-var-house-flag, - "person-circle-minus": $fa-var-person-circle-minus, - "ban": $fa-var-ban, - "cancel": $fa-var-cancel, - "camera-rotate": $fa-var-camera-rotate, - "spray-can-sparkles": $fa-var-spray-can-sparkles, - "air-freshener": $fa-var-air-freshener, - "star": $fa-var-star, - "repeat": $fa-var-repeat, - "cross": $fa-var-cross, - "box": $fa-var-box, - "venus-mars": $fa-var-venus-mars, - "arrow-pointer": $fa-var-arrow-pointer, - "mouse-pointer": $fa-var-mouse-pointer, - "maximize": $fa-var-maximize, - "expand-arrows-alt": $fa-var-expand-arrows-alt, - "charging-station": $fa-var-charging-station, - "shapes": $fa-var-shapes, - "triangle-circle-square": $fa-var-triangle-circle-square, - "shuffle": $fa-var-shuffle, - "random": $fa-var-random, - "person-running": $fa-var-person-running, - "running": $fa-var-running, - "mobile-retro": $fa-var-mobile-retro, - "grip-lines-vertical": $fa-var-grip-lines-vertical, - "spider": $fa-var-spider, - "hands-bound": $fa-var-hands-bound, - "file-invoice-dollar": $fa-var-file-invoice-dollar, - "plane-circle-exclamation": $fa-var-plane-circle-exclamation, - "x-ray": $fa-var-x-ray, - "spell-check": $fa-var-spell-check, - "slash": $fa-var-slash, - "computer-mouse": $fa-var-computer-mouse, - "mouse": $fa-var-mouse, - "arrow-right-to-bracket": $fa-var-arrow-right-to-bracket, - "sign-in": $fa-var-sign-in, - "shop-slash": $fa-var-shop-slash, - "store-alt-slash": $fa-var-store-alt-slash, - "server": $fa-var-server, - "virus-covid-slash": $fa-var-virus-covid-slash, - "shop-lock": $fa-var-shop-lock, - "hourglass-start": $fa-var-hourglass-start, - "hourglass-1": $fa-var-hourglass-1, - "blender-phone": $fa-var-blender-phone, - "building-wheat": $fa-var-building-wheat, - "person-breastfeeding": $fa-var-person-breastfeeding, - "right-to-bracket": $fa-var-right-to-bracket, - "sign-in-alt": $fa-var-sign-in-alt, - "venus": $fa-var-venus, - "passport": $fa-var-passport, - "heart-pulse": $fa-var-heart-pulse, - "heartbeat": $fa-var-heartbeat, - "people-carry-box": $fa-var-people-carry-box, - "people-carry": $fa-var-people-carry, - "temperature-high": $fa-var-temperature-high, - "microchip": $fa-var-microchip, - "crown": $fa-var-crown, - "weight-hanging": $fa-var-weight-hanging, - "xmarks-lines": $fa-var-xmarks-lines, - "file-prescription": $fa-var-file-prescription, - "weight-scale": $fa-var-weight-scale, - "weight": $fa-var-weight, - "user-group": $fa-var-user-group, - "user-friends": $fa-var-user-friends, - "arrow-up-a-z": $fa-var-arrow-up-a-z, - "sort-alpha-up": $fa-var-sort-alpha-up, - "chess-knight": $fa-var-chess-knight, - "face-laugh-squint": $fa-var-face-laugh-squint, - "laugh-squint": $fa-var-laugh-squint, - "wheelchair": $fa-var-wheelchair, - "circle-arrow-up": $fa-var-circle-arrow-up, - "arrow-circle-up": $fa-var-arrow-circle-up, - "toggle-on": $fa-var-toggle-on, - "person-walking": $fa-var-person-walking, - "walking": $fa-var-walking, - "l": $fa-var-l, - "fire": $fa-var-fire, - "bed-pulse": $fa-var-bed-pulse, - "procedures": $fa-var-procedures, - "shuttle-space": $fa-var-shuttle-space, - "space-shuttle": $fa-var-space-shuttle, - "face-laugh": $fa-var-face-laugh, - "laugh": $fa-var-laugh, - "folder-open": $fa-var-folder-open, - "heart-circle-plus": $fa-var-heart-circle-plus, - "code-fork": $fa-var-code-fork, - "city": $fa-var-city, - "microphone-lines": $fa-var-microphone-lines, - "microphone-alt": $fa-var-microphone-alt, - "pepper-hot": $fa-var-pepper-hot, - "unlock": $fa-var-unlock, - "colon-sign": $fa-var-colon-sign, - "headset": $fa-var-headset, - "store-slash": $fa-var-store-slash, - "road-circle-xmark": $fa-var-road-circle-xmark, - "user-minus": $fa-var-user-minus, - "mars-stroke-up": $fa-var-mars-stroke-up, - "mars-stroke-v": $fa-var-mars-stroke-v, - "champagne-glasses": $fa-var-champagne-glasses, - "glass-cheers": $fa-var-glass-cheers, - "clipboard": $fa-var-clipboard, - "house-circle-exclamation": $fa-var-house-circle-exclamation, - "file-arrow-up": $fa-var-file-arrow-up, - "file-upload": $fa-var-file-upload, - "wifi": $fa-var-wifi, - "wifi-3": $fa-var-wifi-3, - "wifi-strong": $fa-var-wifi-strong, - "bath": $fa-var-bath, - "bathtub": $fa-var-bathtub, - "underline": $fa-var-underline, - "user-pen": $fa-var-user-pen, - "user-edit": $fa-var-user-edit, - "signature": $fa-var-signature, - "stroopwafel": $fa-var-stroopwafel, - "bold": $fa-var-bold, - "anchor-lock": $fa-var-anchor-lock, - "building-ngo": $fa-var-building-ngo, - "manat-sign": $fa-var-manat-sign, - "not-equal": $fa-var-not-equal, - "border-top-left": $fa-var-border-top-left, - "border-style": $fa-var-border-style, - "map-location-dot": $fa-var-map-location-dot, - "map-marked-alt": $fa-var-map-marked-alt, - "jedi": $fa-var-jedi, - "square-poll-vertical": $fa-var-square-poll-vertical, - "poll": $fa-var-poll, - "mug-hot": $fa-var-mug-hot, - "car-battery": $fa-var-car-battery, - "battery-car": $fa-var-battery-car, - "gift": $fa-var-gift, - "dice-two": $fa-var-dice-two, - "chess-queen": $fa-var-chess-queen, - "glasses": $fa-var-glasses, - "chess-board": $fa-var-chess-board, - "building-circle-check": $fa-var-building-circle-check, - "person-chalkboard": $fa-var-person-chalkboard, - "mars-stroke-right": $fa-var-mars-stroke-right, - "mars-stroke-h": $fa-var-mars-stroke-h, - "hand-back-fist": $fa-var-hand-back-fist, - "hand-rock": $fa-var-hand-rock, - "square-caret-up": $fa-var-square-caret-up, - "caret-square-up": $fa-var-caret-square-up, - "cloud-showers-water": $fa-var-cloud-showers-water, - "chart-bar": $fa-var-chart-bar, - "bar-chart": $fa-var-bar-chart, - "hands-bubbles": $fa-var-hands-bubbles, - "hands-wash": $fa-var-hands-wash, - "less-than-equal": $fa-var-less-than-equal, - "train": $fa-var-train, - "eye-low-vision": $fa-var-eye-low-vision, - "low-vision": $fa-var-low-vision, - "crow": $fa-var-crow, - "sailboat": $fa-var-sailboat, - "window-restore": $fa-var-window-restore, - "square-plus": $fa-var-square-plus, - "plus-square": $fa-var-plus-square, - "torii-gate": $fa-var-torii-gate, - "frog": $fa-var-frog, - "bucket": $fa-var-bucket, - "image": $fa-var-image, - "microphone": $fa-var-microphone, - "cow": $fa-var-cow, - "caret-up": $fa-var-caret-up, - "screwdriver": $fa-var-screwdriver, - "folder-closed": $fa-var-folder-closed, - "house-tsunami": $fa-var-house-tsunami, - "square-nfi": $fa-var-square-nfi, - "arrow-up-from-ground-water": $fa-var-arrow-up-from-ground-water, - "martini-glass": $fa-var-martini-glass, - "glass-martini-alt": $fa-var-glass-martini-alt, - "rotate-left": $fa-var-rotate-left, - "rotate-back": $fa-var-rotate-back, - "rotate-backward": $fa-var-rotate-backward, - "undo-alt": $fa-var-undo-alt, - "table-columns": $fa-var-table-columns, - "columns": $fa-var-columns, - "lemon": $fa-var-lemon, - "head-side-mask": $fa-var-head-side-mask, - "handshake": $fa-var-handshake, - "gem": $fa-var-gem, - "dolly": $fa-var-dolly, - "dolly-box": $fa-var-dolly-box, - "smoking": $fa-var-smoking, - "minimize": $fa-var-minimize, - "compress-arrows-alt": $fa-var-compress-arrows-alt, - "monument": $fa-var-monument, - "snowplow": $fa-var-snowplow, - "angles-right": $fa-var-angles-right, - "angle-double-right": $fa-var-angle-double-right, - "cannabis": $fa-var-cannabis, - "circle-play": $fa-var-circle-play, - "play-circle": $fa-var-play-circle, - "tablets": $fa-var-tablets, - "ethernet": $fa-var-ethernet, - "euro-sign": $fa-var-euro-sign, - "eur": $fa-var-eur, - "euro": $fa-var-euro, - "chair": $fa-var-chair, - "circle-check": $fa-var-circle-check, - "check-circle": $fa-var-check-circle, - "circle-stop": $fa-var-circle-stop, - "stop-circle": $fa-var-stop-circle, - "compass-drafting": $fa-var-compass-drafting, - "drafting-compass": $fa-var-drafting-compass, - "plate-wheat": $fa-var-plate-wheat, - "icicles": $fa-var-icicles, - "person-shelter": $fa-var-person-shelter, - "neuter": $fa-var-neuter, - "id-badge": $fa-var-id-badge, - "marker": $fa-var-marker, - "face-laugh-beam": $fa-var-face-laugh-beam, - "laugh-beam": $fa-var-laugh-beam, - "helicopter-symbol": $fa-var-helicopter-symbol, - "universal-access": $fa-var-universal-access, - "circle-chevron-up": $fa-var-circle-chevron-up, - "chevron-circle-up": $fa-var-chevron-circle-up, - "lari-sign": $fa-var-lari-sign, - "volcano": $fa-var-volcano, - "person-walking-dashed-line-arrow-right": $fa-var-person-walking-dashed-line-arrow-right, - "sterling-sign": $fa-var-sterling-sign, - "gbp": $fa-var-gbp, - "pound-sign": $fa-var-pound-sign, - "viruses": $fa-var-viruses, - "square-person-confined": $fa-var-square-person-confined, - "user-tie": $fa-var-user-tie, - "arrow-down-long": $fa-var-arrow-down-long, - "long-arrow-down": $fa-var-long-arrow-down, - "tent-arrow-down-to-line": $fa-var-tent-arrow-down-to-line, - "certificate": $fa-var-certificate, - "reply-all": $fa-var-reply-all, - "mail-reply-all": $fa-var-mail-reply-all, - "suitcase": $fa-var-suitcase, - "person-skating": $fa-var-person-skating, - "skating": $fa-var-skating, - "filter-circle-dollar": $fa-var-filter-circle-dollar, - "funnel-dollar": $fa-var-funnel-dollar, - "camera-retro": $fa-var-camera-retro, - "circle-arrow-down": $fa-var-circle-arrow-down, - "arrow-circle-down": $fa-var-arrow-circle-down, - "file-import": $fa-var-file-import, - "arrow-right-to-file": $fa-var-arrow-right-to-file, - "square-arrow-up-right": $fa-var-square-arrow-up-right, - "external-link-square": $fa-var-external-link-square, - "box-open": $fa-var-box-open, - "scroll": $fa-var-scroll, - "spa": $fa-var-spa, - "location-pin-lock": $fa-var-location-pin-lock, - "pause": $fa-var-pause, - "hill-avalanche": $fa-var-hill-avalanche, - "temperature-empty": $fa-var-temperature-empty, - "temperature-0": $fa-var-temperature-0, - "thermometer-0": $fa-var-thermometer-0, - "thermometer-empty": $fa-var-thermometer-empty, - "bomb": $fa-var-bomb, - "registered": $fa-var-registered, - "address-card": $fa-var-address-card, - "contact-card": $fa-var-contact-card, - "vcard": $fa-var-vcard, - "scale-unbalanced-flip": $fa-var-scale-unbalanced-flip, - "balance-scale-right": $fa-var-balance-scale-right, - "subscript": $fa-var-subscript, - "diamond-turn-right": $fa-var-diamond-turn-right, - "directions": $fa-var-directions, - "burst": $fa-var-burst, - "house-laptop": $fa-var-house-laptop, - "laptop-house": $fa-var-laptop-house, - "face-tired": $fa-var-face-tired, - "tired": $fa-var-tired, - "money-bills": $fa-var-money-bills, - "smog": $fa-var-smog, - "crutch": $fa-var-crutch, - "cloud-arrow-up": $fa-var-cloud-arrow-up, - "cloud-upload": $fa-var-cloud-upload, - "cloud-upload-alt": $fa-var-cloud-upload-alt, - "palette": $fa-var-palette, - "arrows-turn-right": $fa-var-arrows-turn-right, - "vest": $fa-var-vest, - "ferry": $fa-var-ferry, - "arrows-down-to-people": $fa-var-arrows-down-to-people, - "seedling": $fa-var-seedling, - "sprout": $fa-var-sprout, - "left-right": $fa-var-left-right, - "arrows-alt-h": $fa-var-arrows-alt-h, - "boxes-packing": $fa-var-boxes-packing, - "circle-arrow-left": $fa-var-circle-arrow-left, - "arrow-circle-left": $fa-var-arrow-circle-left, - "group-arrows-rotate": $fa-var-group-arrows-rotate, - "bowl-food": $fa-var-bowl-food, - "candy-cane": $fa-var-candy-cane, - "arrow-down-wide-short": $fa-var-arrow-down-wide-short, - "sort-amount-asc": $fa-var-sort-amount-asc, - "sort-amount-down": $fa-var-sort-amount-down, - "cloud-bolt": $fa-var-cloud-bolt, - "thunderstorm": $fa-var-thunderstorm, - "text-slash": $fa-var-text-slash, - "remove-format": $fa-var-remove-format, - "face-smile-wink": $fa-var-face-smile-wink, - "smile-wink": $fa-var-smile-wink, - "file-word": $fa-var-file-word, - "file-powerpoint": $fa-var-file-powerpoint, - "arrows-left-right": $fa-var-arrows-left-right, - "arrows-h": $fa-var-arrows-h, - "house-lock": $fa-var-house-lock, - "cloud-arrow-down": $fa-var-cloud-arrow-down, - "cloud-download": $fa-var-cloud-download, - "cloud-download-alt": $fa-var-cloud-download-alt, - "children": $fa-var-children, - "chalkboard": $fa-var-chalkboard, - "blackboard": $fa-var-blackboard, - "user-large-slash": $fa-var-user-large-slash, - "user-alt-slash": $fa-var-user-alt-slash, - "envelope-open": $fa-var-envelope-open, - "handshake-simple-slash": $fa-var-handshake-simple-slash, - "handshake-alt-slash": $fa-var-handshake-alt-slash, - "mattress-pillow": $fa-var-mattress-pillow, - "guarani-sign": $fa-var-guarani-sign, - "arrows-rotate": $fa-var-arrows-rotate, - "refresh": $fa-var-refresh, - "sync": $fa-var-sync, - "fire-extinguisher": $fa-var-fire-extinguisher, - "cruzeiro-sign": $fa-var-cruzeiro-sign, - "greater-than-equal": $fa-var-greater-than-equal, - "shield-halved": $fa-var-shield-halved, - "shield-alt": $fa-var-shield-alt, - "book-atlas": $fa-var-book-atlas, - "atlas": $fa-var-atlas, - "virus": $fa-var-virus, - "envelope-circle-check": $fa-var-envelope-circle-check, - "layer-group": $fa-var-layer-group, - "arrows-to-dot": $fa-var-arrows-to-dot, - "archway": $fa-var-archway, - "heart-circle-check": $fa-var-heart-circle-check, - "house-chimney-crack": $fa-var-house-chimney-crack, - "house-damage": $fa-var-house-damage, - "file-zipper": $fa-var-file-zipper, - "file-archive": $fa-var-file-archive, - "square": $fa-var-square, - "martini-glass-empty": $fa-var-martini-glass-empty, - "glass-martini": $fa-var-glass-martini, - "couch": $fa-var-couch, - "cedi-sign": $fa-var-cedi-sign, - "italic": $fa-var-italic, - "church": $fa-var-church, - "comments-dollar": $fa-var-comments-dollar, - "democrat": $fa-var-democrat, - "z": $fa-var-z, - "person-skiing": $fa-var-person-skiing, - "skiing": $fa-var-skiing, - "road-lock": $fa-var-road-lock, - "a": $fa-var-a, - "temperature-arrow-down": $fa-var-temperature-arrow-down, - "temperature-down": $fa-var-temperature-down, - "feather-pointed": $fa-var-feather-pointed, - "feather-alt": $fa-var-feather-alt, - "p": $fa-var-p, - "snowflake": $fa-var-snowflake, - "newspaper": $fa-var-newspaper, - "rectangle-ad": $fa-var-rectangle-ad, - "ad": $fa-var-ad, - "circle-arrow-right": $fa-var-circle-arrow-right, - "arrow-circle-right": $fa-var-arrow-circle-right, - "filter-circle-xmark": $fa-var-filter-circle-xmark, - "locust": $fa-var-locust, - "sort": $fa-var-sort, - "unsorted": $fa-var-unsorted, - "list-ol": $fa-var-list-ol, - "list-1-2": $fa-var-list-1-2, - "list-numeric": $fa-var-list-numeric, - "person-dress-burst": $fa-var-person-dress-burst, - "money-check-dollar": $fa-var-money-check-dollar, - "money-check-alt": $fa-var-money-check-alt, - "vector-square": $fa-var-vector-square, - "bread-slice": $fa-var-bread-slice, - "language": $fa-var-language, - "face-kiss-wink-heart": $fa-var-face-kiss-wink-heart, - "kiss-wink-heart": $fa-var-kiss-wink-heart, - "filter": $fa-var-filter, - "question": $fa-var-question, - "file-signature": $fa-var-file-signature, - "up-down-left-right": $fa-var-up-down-left-right, - "arrows-alt": $fa-var-arrows-alt, - "house-chimney-user": $fa-var-house-chimney-user, - "hand-holding-heart": $fa-var-hand-holding-heart, - "puzzle-piece": $fa-var-puzzle-piece, - "money-check": $fa-var-money-check, - "star-half-stroke": $fa-var-star-half-stroke, - "star-half-alt": $fa-var-star-half-alt, - "code": $fa-var-code, - "whiskey-glass": $fa-var-whiskey-glass, - "glass-whiskey": $fa-var-glass-whiskey, - "building-circle-exclamation": $fa-var-building-circle-exclamation, - "magnifying-glass-chart": $fa-var-magnifying-glass-chart, - "arrow-up-right-from-square": $fa-var-arrow-up-right-from-square, - "external-link": $fa-var-external-link, - "cubes-stacked": $fa-var-cubes-stacked, - "won-sign": $fa-var-won-sign, - "krw": $fa-var-krw, - "won": $fa-var-won, - "virus-covid": $fa-var-virus-covid, - "austral-sign": $fa-var-austral-sign, - "f": $fa-var-f, - "leaf": $fa-var-leaf, - "road": $fa-var-road, - "taxi": $fa-var-taxi, - "cab": $fa-var-cab, - "person-circle-plus": $fa-var-person-circle-plus, - "chart-pie": $fa-var-chart-pie, - "pie-chart": $fa-var-pie-chart, - "bolt-lightning": $fa-var-bolt-lightning, - "sack-xmark": $fa-var-sack-xmark, - "file-excel": $fa-var-file-excel, - "file-contract": $fa-var-file-contract, - "fish-fins": $fa-var-fish-fins, - "building-flag": $fa-var-building-flag, - "face-grin-beam": $fa-var-face-grin-beam, - "grin-beam": $fa-var-grin-beam, - "object-ungroup": $fa-var-object-ungroup, - "poop": $fa-var-poop, - "location-pin": $fa-var-location-pin, - "map-marker": $fa-var-map-marker, - "kaaba": $fa-var-kaaba, - "toilet-paper": $fa-var-toilet-paper, - "helmet-safety": $fa-var-helmet-safety, - "hard-hat": $fa-var-hard-hat, - "hat-hard": $fa-var-hat-hard, - "eject": $fa-var-eject, - "circle-right": $fa-var-circle-right, - "arrow-alt-circle-right": $fa-var-arrow-alt-circle-right, - "plane-circle-check": $fa-var-plane-circle-check, - "face-rolling-eyes": $fa-var-face-rolling-eyes, - "meh-rolling-eyes": $fa-var-meh-rolling-eyes, - "object-group": $fa-var-object-group, - "chart-line": $fa-var-chart-line, - "line-chart": $fa-var-line-chart, - "mask-ventilator": $fa-var-mask-ventilator, - "arrow-right": $fa-var-arrow-right, - "signs-post": $fa-var-signs-post, - "map-signs": $fa-var-map-signs, - "cash-register": $fa-var-cash-register, - "person-circle-question": $fa-var-person-circle-question, - "h": $fa-var-h, - "tarp": $fa-var-tarp, - "screwdriver-wrench": $fa-var-screwdriver-wrench, - "tools": $fa-var-tools, - "arrows-to-eye": $fa-var-arrows-to-eye, - "plug-circle-bolt": $fa-var-plug-circle-bolt, - "heart": $fa-var-heart, - "mars-and-venus": $fa-var-mars-and-venus, - "house-user": $fa-var-house-user, - "home-user": $fa-var-home-user, - "dumpster-fire": $fa-var-dumpster-fire, - "house-crack": $fa-var-house-crack, - "martini-glass-citrus": $fa-var-martini-glass-citrus, - "cocktail": $fa-var-cocktail, - "face-surprise": $fa-var-face-surprise, - "surprise": $fa-var-surprise, - "bottle-water": $fa-var-bottle-water, - "circle-pause": $fa-var-circle-pause, - "pause-circle": $fa-var-pause-circle, - "toilet-paper-slash": $fa-var-toilet-paper-slash, - "apple-whole": $fa-var-apple-whole, - "apple-alt": $fa-var-apple-alt, - "kitchen-set": $fa-var-kitchen-set, - "r": $fa-var-r, - "temperature-quarter": $fa-var-temperature-quarter, - "temperature-1": $fa-var-temperature-1, - "thermometer-1": $fa-var-thermometer-1, - "thermometer-quarter": $fa-var-thermometer-quarter, - "cube": $fa-var-cube, - "bitcoin-sign": $fa-var-bitcoin-sign, - "shield-dog": $fa-var-shield-dog, - "solar-panel": $fa-var-solar-panel, - "lock-open": $fa-var-lock-open, - "elevator": $fa-var-elevator, - "money-bill-transfer": $fa-var-money-bill-transfer, - "money-bill-trend-up": $fa-var-money-bill-trend-up, - "house-flood-water-circle-arrow-right": $fa-var-house-flood-water-circle-arrow-right, - "square-poll-horizontal": $fa-var-square-poll-horizontal, - "poll-h": $fa-var-poll-h, - "circle": $fa-var-circle, - "backward-fast": $fa-var-backward-fast, - "fast-backward": $fa-var-fast-backward, - "recycle": $fa-var-recycle, - "user-astronaut": $fa-var-user-astronaut, - "plane-slash": $fa-var-plane-slash, - "trademark": $fa-var-trademark, - "basketball": $fa-var-basketball, - "basketball-ball": $fa-var-basketball-ball, - "satellite-dish": $fa-var-satellite-dish, - "circle-up": $fa-var-circle-up, - "arrow-alt-circle-up": $fa-var-arrow-alt-circle-up, - "mobile-screen-button": $fa-var-mobile-screen-button, - "mobile-alt": $fa-var-mobile-alt, - "volume-high": $fa-var-volume-high, - "volume-up": $fa-var-volume-up, - "users-rays": $fa-var-users-rays, - "wallet": $fa-var-wallet, - "clipboard-check": $fa-var-clipboard-check, - "file-audio": $fa-var-file-audio, - "burger": $fa-var-burger, - "hamburger": $fa-var-hamburger, - "wrench": $fa-var-wrench, - "bugs": $fa-var-bugs, - "rupee-sign": $fa-var-rupee-sign, - "rupee": $fa-var-rupee, - "file-image": $fa-var-file-image, - "circle-question": $fa-var-circle-question, - "question-circle": $fa-var-question-circle, - "plane-departure": $fa-var-plane-departure, - "handshake-slash": $fa-var-handshake-slash, - "book-bookmark": $fa-var-book-bookmark, - "code-branch": $fa-var-code-branch, - "hat-cowboy": $fa-var-hat-cowboy, - "bridge": $fa-var-bridge, - "phone-flip": $fa-var-phone-flip, - "phone-alt": $fa-var-phone-alt, - "truck-front": $fa-var-truck-front, - "cat": $fa-var-cat, - "anchor-circle-exclamation": $fa-var-anchor-circle-exclamation, - "truck-field": $fa-var-truck-field, - "route": $fa-var-route, - "clipboard-question": $fa-var-clipboard-question, - "panorama": $fa-var-panorama, - "comment-medical": $fa-var-comment-medical, - "teeth-open": $fa-var-teeth-open, - "file-circle-minus": $fa-var-file-circle-minus, - "tags": $fa-var-tags, - "wine-glass": $fa-var-wine-glass, - "forward-fast": $fa-var-forward-fast, - "fast-forward": $fa-var-fast-forward, - "face-meh-blank": $fa-var-face-meh-blank, - "meh-blank": $fa-var-meh-blank, - "square-parking": $fa-var-square-parking, - "parking": $fa-var-parking, - "house-signal": $fa-var-house-signal, - "bars-progress": $fa-var-bars-progress, - "tasks-alt": $fa-var-tasks-alt, - "faucet-drip": $fa-var-faucet-drip, - "cart-flatbed": $fa-var-cart-flatbed, - "dolly-flatbed": $fa-var-dolly-flatbed, - "ban-smoking": $fa-var-ban-smoking, - "smoking-ban": $fa-var-smoking-ban, - "terminal": $fa-var-terminal, - "mobile-button": $fa-var-mobile-button, - "house-medical-flag": $fa-var-house-medical-flag, - "basket-shopping": $fa-var-basket-shopping, - "shopping-basket": $fa-var-shopping-basket, - "tape": $fa-var-tape, - "bus-simple": $fa-var-bus-simple, - "bus-alt": $fa-var-bus-alt, - "eye": $fa-var-eye, - "face-sad-cry": $fa-var-face-sad-cry, - "sad-cry": $fa-var-sad-cry, - "audio-description": $fa-var-audio-description, - "person-military-to-person": $fa-var-person-military-to-person, - "file-shield": $fa-var-file-shield, - "user-slash": $fa-var-user-slash, - "pen": $fa-var-pen, - "tower-observation": $fa-var-tower-observation, - "file-code": $fa-var-file-code, - "signal": $fa-var-signal, - "signal-5": $fa-var-signal-5, - "signal-perfect": $fa-var-signal-perfect, - "bus": $fa-var-bus, - "heart-circle-xmark": $fa-var-heart-circle-xmark, - "house-chimney": $fa-var-house-chimney, - "home-lg": $fa-var-home-lg, - "window-maximize": $fa-var-window-maximize, - "face-frown": $fa-var-face-frown, - "frown": $fa-var-frown, - "prescription": $fa-var-prescription, - "shop": $fa-var-shop, - "store-alt": $fa-var-store-alt, - "floppy-disk": $fa-var-floppy-disk, - "save": $fa-var-save, - "vihara": $fa-var-vihara, - "scale-unbalanced": $fa-var-scale-unbalanced, - "balance-scale-left": $fa-var-balance-scale-left, - "sort-up": $fa-var-sort-up, - "sort-asc": $fa-var-sort-asc, - "comment-dots": $fa-var-comment-dots, - "commenting": $fa-var-commenting, - "plant-wilt": $fa-var-plant-wilt, - "diamond": $fa-var-diamond, - "face-grin-squint": $fa-var-face-grin-squint, - "grin-squint": $fa-var-grin-squint, - "hand-holding-dollar": $fa-var-hand-holding-dollar, - "hand-holding-usd": $fa-var-hand-holding-usd, - "bacterium": $fa-var-bacterium, - "hand-pointer": $fa-var-hand-pointer, - "drum-steelpan": $fa-var-drum-steelpan, - "hand-scissors": $fa-var-hand-scissors, - "hands-praying": $fa-var-hands-praying, - "praying-hands": $fa-var-praying-hands, - "arrow-rotate-right": $fa-var-arrow-rotate-right, - "arrow-right-rotate": $fa-var-arrow-right-rotate, - "arrow-rotate-forward": $fa-var-arrow-rotate-forward, - "redo": $fa-var-redo, - "biohazard": $fa-var-biohazard, - "location-crosshairs": $fa-var-location-crosshairs, - "location": $fa-var-location, - "mars-double": $fa-var-mars-double, - "child-dress": $fa-var-child-dress, - "users-between-lines": $fa-var-users-between-lines, - "lungs-virus": $fa-var-lungs-virus, - "face-grin-tears": $fa-var-face-grin-tears, - "grin-tears": $fa-var-grin-tears, - "phone": $fa-var-phone, - "calendar-xmark": $fa-var-calendar-xmark, - "calendar-times": $fa-var-calendar-times, - "child-reaching": $fa-var-child-reaching, - "head-side-virus": $fa-var-head-side-virus, - "user-gear": $fa-var-user-gear, - "user-cog": $fa-var-user-cog, - "arrow-up-1-9": $fa-var-arrow-up-1-9, - "sort-numeric-up": $fa-var-sort-numeric-up, - "door-closed": $fa-var-door-closed, - "shield-virus": $fa-var-shield-virus, - "dice-six": $fa-var-dice-six, - "mosquito-net": $fa-var-mosquito-net, - "bridge-water": $fa-var-bridge-water, - "person-booth": $fa-var-person-booth, - "text-width": $fa-var-text-width, - "hat-wizard": $fa-var-hat-wizard, - "pen-fancy": $fa-var-pen-fancy, - "person-digging": $fa-var-person-digging, - "digging": $fa-var-digging, - "trash": $fa-var-trash, - "gauge-simple": $fa-var-gauge-simple, - "gauge-simple-med": $fa-var-gauge-simple-med, - "tachometer-average": $fa-var-tachometer-average, - "book-medical": $fa-var-book-medical, - "poo": $fa-var-poo, - "quote-right": $fa-var-quote-right, - "quote-right-alt": $fa-var-quote-right-alt, - "shirt": $fa-var-shirt, - "t-shirt": $fa-var-t-shirt, - "tshirt": $fa-var-tshirt, - "cubes": $fa-var-cubes, - "divide": $fa-var-divide, - "tenge-sign": $fa-var-tenge-sign, - "tenge": $fa-var-tenge, - "headphones": $fa-var-headphones, - "hands-holding": $fa-var-hands-holding, - "hands-clapping": $fa-var-hands-clapping, - "republican": $fa-var-republican, - "arrow-left": $fa-var-arrow-left, - "person-circle-xmark": $fa-var-person-circle-xmark, - "ruler": $fa-var-ruler, - "align-left": $fa-var-align-left, - "dice-d6": $fa-var-dice-d6, - "restroom": $fa-var-restroom, - "j": $fa-var-j, - "users-viewfinder": $fa-var-users-viewfinder, - "file-video": $fa-var-file-video, - "up-right-from-square": $fa-var-up-right-from-square, - "external-link-alt": $fa-var-external-link-alt, - "table-cells": $fa-var-table-cells, - "th": $fa-var-th, - "file-pdf": $fa-var-file-pdf, - "book-bible": $fa-var-book-bible, - "bible": $fa-var-bible, - "o": $fa-var-o, - "suitcase-medical": $fa-var-suitcase-medical, - "medkit": $fa-var-medkit, - "user-secret": $fa-var-user-secret, - "otter": $fa-var-otter, - "person-dress": $fa-var-person-dress, - "female": $fa-var-female, - "comment-dollar": $fa-var-comment-dollar, - "business-time": $fa-var-business-time, - "briefcase-clock": $fa-var-briefcase-clock, - "table-cells-large": $fa-var-table-cells-large, - "th-large": $fa-var-th-large, - "book-tanakh": $fa-var-book-tanakh, - "tanakh": $fa-var-tanakh, - "phone-volume": $fa-var-phone-volume, - "volume-control-phone": $fa-var-volume-control-phone, - "hat-cowboy-side": $fa-var-hat-cowboy-side, - "clipboard-user": $fa-var-clipboard-user, - "child": $fa-var-child, - "lira-sign": $fa-var-lira-sign, - "satellite": $fa-var-satellite, - "plane-lock": $fa-var-plane-lock, - "tag": $fa-var-tag, - "comment": $fa-var-comment, - "cake-candles": $fa-var-cake-candles, - "birthday-cake": $fa-var-birthday-cake, - "cake": $fa-var-cake, - "envelope": $fa-var-envelope, - "angles-up": $fa-var-angles-up, - "angle-double-up": $fa-var-angle-double-up, - "paperclip": $fa-var-paperclip, - "arrow-right-to-city": $fa-var-arrow-right-to-city, - "ribbon": $fa-var-ribbon, - "lungs": $fa-var-lungs, - "arrow-up-9-1": $fa-var-arrow-up-9-1, - "sort-numeric-up-alt": $fa-var-sort-numeric-up-alt, - "litecoin-sign": $fa-var-litecoin-sign, - "border-none": $fa-var-border-none, - "circle-nodes": $fa-var-circle-nodes, - "parachute-box": $fa-var-parachute-box, - "indent": $fa-var-indent, - "truck-field-un": $fa-var-truck-field-un, - "hourglass": $fa-var-hourglass, - "hourglass-empty": $fa-var-hourglass-empty, - "mountain": $fa-var-mountain, - "user-doctor": $fa-var-user-doctor, - "user-md": $fa-var-user-md, - "circle-info": $fa-var-circle-info, - "info-circle": $fa-var-info-circle, - "cloud-meatball": $fa-var-cloud-meatball, - "camera": $fa-var-camera, - "camera-alt": $fa-var-camera-alt, - "square-virus": $fa-var-square-virus, - "meteor": $fa-var-meteor, - "car-on": $fa-var-car-on, - "sleigh": $fa-var-sleigh, - "arrow-down-1-9": $fa-var-arrow-down-1-9, - "sort-numeric-asc": $fa-var-sort-numeric-asc, - "sort-numeric-down": $fa-var-sort-numeric-down, - "hand-holding-droplet": $fa-var-hand-holding-droplet, - "hand-holding-water": $fa-var-hand-holding-water, - "water": $fa-var-water, - "calendar-check": $fa-var-calendar-check, - "braille": $fa-var-braille, - "prescription-bottle-medical": $fa-var-prescription-bottle-medical, - "prescription-bottle-alt": $fa-var-prescription-bottle-alt, - "landmark": $fa-var-landmark, - "truck": $fa-var-truck, - "crosshairs": $fa-var-crosshairs, - "person-cane": $fa-var-person-cane, - "tent": $fa-var-tent, - "vest-patches": $fa-var-vest-patches, - "check-double": $fa-var-check-double, - "arrow-down-a-z": $fa-var-arrow-down-a-z, - "sort-alpha-asc": $fa-var-sort-alpha-asc, - "sort-alpha-down": $fa-var-sort-alpha-down, - "money-bill-wheat": $fa-var-money-bill-wheat, - "cookie": $fa-var-cookie, - "arrow-rotate-left": $fa-var-arrow-rotate-left, - "arrow-left-rotate": $fa-var-arrow-left-rotate, - "arrow-rotate-back": $fa-var-arrow-rotate-back, - "arrow-rotate-backward": $fa-var-arrow-rotate-backward, - "undo": $fa-var-undo, - "hard-drive": $fa-var-hard-drive, - "hdd": $fa-var-hdd, - "face-grin-squint-tears": $fa-var-face-grin-squint-tears, - "grin-squint-tears": $fa-var-grin-squint-tears, - "dumbbell": $fa-var-dumbbell, - "rectangle-list": $fa-var-rectangle-list, - "list-alt": $fa-var-list-alt, - "tarp-droplet": $fa-var-tarp-droplet, - "house-medical-circle-check": $fa-var-house-medical-circle-check, - "person-skiing-nordic": $fa-var-person-skiing-nordic, - "skiing-nordic": $fa-var-skiing-nordic, - "calendar-plus": $fa-var-calendar-plus, - "plane-arrival": $fa-var-plane-arrival, - "circle-left": $fa-var-circle-left, - "arrow-alt-circle-left": $fa-var-arrow-alt-circle-left, - "train-subway": $fa-var-train-subway, - "subway": $fa-var-subway, - "chart-gantt": $fa-var-chart-gantt, - "indian-rupee-sign": $fa-var-indian-rupee-sign, - "indian-rupee": $fa-var-indian-rupee, - "inr": $fa-var-inr, - "crop-simple": $fa-var-crop-simple, - "crop-alt": $fa-var-crop-alt, - "money-bill-1": $fa-var-money-bill-1, - "money-bill-alt": $fa-var-money-bill-alt, - "left-long": $fa-var-left-long, - "long-arrow-alt-left": $fa-var-long-arrow-alt-left, - "dna": $fa-var-dna, - "virus-slash": $fa-var-virus-slash, - "minus": $fa-var-minus, - "subtract": $fa-var-subtract, - "child-rifle": $fa-var-child-rifle, - "chess": $fa-var-chess, - "arrow-left-long": $fa-var-arrow-left-long, - "long-arrow-left": $fa-var-long-arrow-left, - "plug-circle-check": $fa-var-plug-circle-check, - "street-view": $fa-var-street-view, - "franc-sign": $fa-var-franc-sign, - "volume-off": $fa-var-volume-off, - "hands-asl-interpreting": $fa-var-hands-asl-interpreting, - "american-sign-language-interpreting": $fa-var-american-sign-language-interpreting, - "asl-interpreting": $fa-var-asl-interpreting, - "hands-american-sign-language-interpreting": $fa-var-hands-american-sign-language-interpreting, - "gear": $fa-var-gear, - "cog": $fa-var-cog, - "droplet-slash": $fa-var-droplet-slash, - "tint-slash": $fa-var-tint-slash, - "mosque": $fa-var-mosque, - "mosquito": $fa-var-mosquito, - "star-of-david": $fa-var-star-of-david, - "person-military-rifle": $fa-var-person-military-rifle, - "cart-shopping": $fa-var-cart-shopping, - "shopping-cart": $fa-var-shopping-cart, - "vials": $fa-var-vials, - "plug-circle-plus": $fa-var-plug-circle-plus, - "place-of-worship": $fa-var-place-of-worship, - "grip-vertical": $fa-var-grip-vertical, - "arrow-turn-up": $fa-var-arrow-turn-up, - "level-up": $fa-var-level-up, - "u": $fa-var-u, - "square-root-variable": $fa-var-square-root-variable, - "square-root-alt": $fa-var-square-root-alt, - "clock": $fa-var-clock, - "clock-four": $fa-var-clock-four, - "backward-step": $fa-var-backward-step, - "step-backward": $fa-var-step-backward, - "pallet": $fa-var-pallet, - "faucet": $fa-var-faucet, - "baseball-bat-ball": $fa-var-baseball-bat-ball, - "s": $fa-var-s, - "timeline": $fa-var-timeline, - "keyboard": $fa-var-keyboard, - "caret-down": $fa-var-caret-down, - "house-chimney-medical": $fa-var-house-chimney-medical, - "clinic-medical": $fa-var-clinic-medical, - "temperature-three-quarters": $fa-var-temperature-three-quarters, - "temperature-3": $fa-var-temperature-3, - "thermometer-3": $fa-var-thermometer-3, - "thermometer-three-quarters": $fa-var-thermometer-three-quarters, - "mobile-screen": $fa-var-mobile-screen, - "mobile-android-alt": $fa-var-mobile-android-alt, - "plane-up": $fa-var-plane-up, - "piggy-bank": $fa-var-piggy-bank, - "battery-half": $fa-var-battery-half, - "battery-3": $fa-var-battery-3, - "mountain-city": $fa-var-mountain-city, - "coins": $fa-var-coins, - "khanda": $fa-var-khanda, - "sliders": $fa-var-sliders, - "sliders-h": $fa-var-sliders-h, - "folder-tree": $fa-var-folder-tree, - "network-wired": $fa-var-network-wired, - "map-pin": $fa-var-map-pin, - "hamsa": $fa-var-hamsa, - "cent-sign": $fa-var-cent-sign, - "flask": $fa-var-flask, - "person-pregnant": $fa-var-person-pregnant, - "wand-sparkles": $fa-var-wand-sparkles, - "ellipsis-vertical": $fa-var-ellipsis-vertical, - "ellipsis-v": $fa-var-ellipsis-v, - "ticket": $fa-var-ticket, - "power-off": $fa-var-power-off, - "right-long": $fa-var-right-long, - "long-arrow-alt-right": $fa-var-long-arrow-alt-right, - "flag-usa": $fa-var-flag-usa, - "laptop-file": $fa-var-laptop-file, - "tty": $fa-var-tty, - "teletype": $fa-var-teletype, - "diagram-next": $fa-var-diagram-next, - "person-rifle": $fa-var-person-rifle, - "house-medical-circle-exclamation": $fa-var-house-medical-circle-exclamation, - "closed-captioning": $fa-var-closed-captioning, - "person-hiking": $fa-var-person-hiking, - "hiking": $fa-var-hiking, - "venus-double": $fa-var-venus-double, - "images": $fa-var-images, - "calculator": $fa-var-calculator, - "people-pulling": $fa-var-people-pulling, - "n": $fa-var-n, - "cable-car": $fa-var-cable-car, - "tram": $fa-var-tram, - "cloud-rain": $fa-var-cloud-rain, - "building-circle-xmark": $fa-var-building-circle-xmark, - "ship": $fa-var-ship, - "arrows-down-to-line": $fa-var-arrows-down-to-line, - "download": $fa-var-download, - "face-grin": $fa-var-face-grin, - "grin": $fa-var-grin, - "delete-left": $fa-var-delete-left, - "backspace": $fa-var-backspace, - "eye-dropper": $fa-var-eye-dropper, - "eye-dropper-empty": $fa-var-eye-dropper-empty, - "eyedropper": $fa-var-eyedropper, - "file-circle-check": $fa-var-file-circle-check, - "forward": $fa-var-forward, - "mobile": $fa-var-mobile, - "mobile-android": $fa-var-mobile-android, - "mobile-phone": $fa-var-mobile-phone, - "face-meh": $fa-var-face-meh, - "meh": $fa-var-meh, - "align-center": $fa-var-align-center, - "book-skull": $fa-var-book-skull, - "book-dead": $fa-var-book-dead, - "id-card": $fa-var-id-card, - "drivers-license": $fa-var-drivers-license, - "outdent": $fa-var-outdent, - "dedent": $fa-var-dedent, - "heart-circle-exclamation": $fa-var-heart-circle-exclamation, - "house": $fa-var-house, - "home": $fa-var-home, - "home-alt": $fa-var-home-alt, - "home-lg-alt": $fa-var-home-lg-alt, - "calendar-week": $fa-var-calendar-week, - "laptop-medical": $fa-var-laptop-medical, - "b": $fa-var-b, - "file-medical": $fa-var-file-medical, - "dice-one": $fa-var-dice-one, - "kiwi-bird": $fa-var-kiwi-bird, - "arrow-right-arrow-left": $fa-var-arrow-right-arrow-left, - "exchange": $fa-var-exchange, - "rotate-right": $fa-var-rotate-right, - "redo-alt": $fa-var-redo-alt, - "rotate-forward": $fa-var-rotate-forward, - "utensils": $fa-var-utensils, - "cutlery": $fa-var-cutlery, - "arrow-up-wide-short": $fa-var-arrow-up-wide-short, - "sort-amount-up": $fa-var-sort-amount-up, - "mill-sign": $fa-var-mill-sign, - "bowl-rice": $fa-var-bowl-rice, - "skull": $fa-var-skull, - "tower-broadcast": $fa-var-tower-broadcast, - "broadcast-tower": $fa-var-broadcast-tower, - "truck-pickup": $fa-var-truck-pickup, - "up-long": $fa-var-up-long, - "long-arrow-alt-up": $fa-var-long-arrow-alt-up, - "stop": $fa-var-stop, - "code-merge": $fa-var-code-merge, - "upload": $fa-var-upload, - "hurricane": $fa-var-hurricane, - "mound": $fa-var-mound, - "toilet-portable": $fa-var-toilet-portable, - "compact-disc": $fa-var-compact-disc, - "file-arrow-down": $fa-var-file-arrow-down, - "file-download": $fa-var-file-download, - "caravan": $fa-var-caravan, - "shield-cat": $fa-var-shield-cat, - "bolt": $fa-var-bolt, - "zap": $fa-var-zap, - "glass-water": $fa-var-glass-water, - "oil-well": $fa-var-oil-well, - "vault": $fa-var-vault, - "mars": $fa-var-mars, - "toilet": $fa-var-toilet, - "plane-circle-xmark": $fa-var-plane-circle-xmark, - "yen-sign": $fa-var-yen-sign, - "cny": $fa-var-cny, - "jpy": $fa-var-jpy, - "rmb": $fa-var-rmb, - "yen": $fa-var-yen, - "ruble-sign": $fa-var-ruble-sign, - "rouble": $fa-var-rouble, - "rub": $fa-var-rub, - "ruble": $fa-var-ruble, - "sun": $fa-var-sun, - "guitar": $fa-var-guitar, - "face-laugh-wink": $fa-var-face-laugh-wink, - "laugh-wink": $fa-var-laugh-wink, - "horse-head": $fa-var-horse-head, - "bore-hole": $fa-var-bore-hole, - "industry": $fa-var-industry, - "circle-down": $fa-var-circle-down, - "arrow-alt-circle-down": $fa-var-arrow-alt-circle-down, - "arrows-turn-to-dots": $fa-var-arrows-turn-to-dots, - "florin-sign": $fa-var-florin-sign, - "arrow-down-short-wide": $fa-var-arrow-down-short-wide, - "sort-amount-desc": $fa-var-sort-amount-desc, - "sort-amount-down-alt": $fa-var-sort-amount-down-alt, - "less-than": $fa-var-less-than, - "angle-down": $fa-var-angle-down, - "car-tunnel": $fa-var-car-tunnel, - "head-side-cough": $fa-var-head-side-cough, - "grip-lines": $fa-var-grip-lines, - "thumbs-down": $fa-var-thumbs-down, - "user-lock": $fa-var-user-lock, - "arrow-right-long": $fa-var-arrow-right-long, - "long-arrow-right": $fa-var-long-arrow-right, - "anchor-circle-xmark": $fa-var-anchor-circle-xmark, - "ellipsis": $fa-var-ellipsis, - "ellipsis-h": $fa-var-ellipsis-h, - "chess-pawn": $fa-var-chess-pawn, - "kit-medical": $fa-var-kit-medical, - "first-aid": $fa-var-first-aid, - "person-through-window": $fa-var-person-through-window, - "toolbox": $fa-var-toolbox, - "hands-holding-circle": $fa-var-hands-holding-circle, - "bug": $fa-var-bug, - "credit-card": $fa-var-credit-card, - "credit-card-alt": $fa-var-credit-card-alt, - "car": $fa-var-car, - "automobile": $fa-var-automobile, - "hand-holding-hand": $fa-var-hand-holding-hand, - "book-open-reader": $fa-var-book-open-reader, - "book-reader": $fa-var-book-reader, - "mountain-sun": $fa-var-mountain-sun, - "arrows-left-right-to-line": $fa-var-arrows-left-right-to-line, - "dice-d20": $fa-var-dice-d20, - "truck-droplet": $fa-var-truck-droplet, - "file-circle-xmark": $fa-var-file-circle-xmark, - "temperature-arrow-up": $fa-var-temperature-arrow-up, - "temperature-up": $fa-var-temperature-up, - "medal": $fa-var-medal, - "bed": $fa-var-bed, - "square-h": $fa-var-square-h, - "h-square": $fa-var-h-square, - "podcast": $fa-var-podcast, - "temperature-full": $fa-var-temperature-full, - "temperature-4": $fa-var-temperature-4, - "thermometer-4": $fa-var-thermometer-4, - "thermometer-full": $fa-var-thermometer-full, - "bell": $fa-var-bell, - "superscript": $fa-var-superscript, - "plug-circle-xmark": $fa-var-plug-circle-xmark, - "star-of-life": $fa-var-star-of-life, - "phone-slash": $fa-var-phone-slash, - "paint-roller": $fa-var-paint-roller, - "handshake-angle": $fa-var-handshake-angle, - "hands-helping": $fa-var-hands-helping, - "location-dot": $fa-var-location-dot, - "map-marker-alt": $fa-var-map-marker-alt, - "file": $fa-var-file, - "greater-than": $fa-var-greater-than, - "person-swimming": $fa-var-person-swimming, - "swimmer": $fa-var-swimmer, - "arrow-down": $fa-var-arrow-down, - "droplet": $fa-var-droplet, - "tint": $fa-var-tint, - "eraser": $fa-var-eraser, - "earth-americas": $fa-var-earth-americas, - "earth": $fa-var-earth, - "earth-america": $fa-var-earth-america, - "globe-americas": $fa-var-globe-americas, - "person-burst": $fa-var-person-burst, - "dove": $fa-var-dove, - "battery-empty": $fa-var-battery-empty, - "battery-0": $fa-var-battery-0, - "socks": $fa-var-socks, - "inbox": $fa-var-inbox, - "section": $fa-var-section, - "gauge-high": $fa-var-gauge-high, - "tachometer-alt": $fa-var-tachometer-alt, - "tachometer-alt-fast": $fa-var-tachometer-alt-fast, - "envelope-open-text": $fa-var-envelope-open-text, - "hospital": $fa-var-hospital, - "hospital-alt": $fa-var-hospital-alt, - "hospital-wide": $fa-var-hospital-wide, - "wine-bottle": $fa-var-wine-bottle, - "chess-rook": $fa-var-chess-rook, - "bars-staggered": $fa-var-bars-staggered, - "reorder": $fa-var-reorder, - "stream": $fa-var-stream, - "dharmachakra": $fa-var-dharmachakra, - "hotdog": $fa-var-hotdog, - "person-walking-with-cane": $fa-var-person-walking-with-cane, - "blind": $fa-var-blind, - "drum": $fa-var-drum, - "ice-cream": $fa-var-ice-cream, - "heart-circle-bolt": $fa-var-heart-circle-bolt, - "fax": $fa-var-fax, - "paragraph": $fa-var-paragraph, - "check-to-slot": $fa-var-check-to-slot, - "vote-yea": $fa-var-vote-yea, - "star-half": $fa-var-star-half, - "boxes-stacked": $fa-var-boxes-stacked, - "boxes": $fa-var-boxes, - "boxes-alt": $fa-var-boxes-alt, - "link": $fa-var-link, - "chain": $fa-var-chain, - "ear-listen": $fa-var-ear-listen, - "assistive-listening-systems": $fa-var-assistive-listening-systems, - "tree-city": $fa-var-tree-city, - "play": $fa-var-play, - "font": $fa-var-font, - "rupiah-sign": $fa-var-rupiah-sign, - "magnifying-glass": $fa-var-magnifying-glass, - "search": $fa-var-search, - "table-tennis-paddle-ball": $fa-var-table-tennis-paddle-ball, - "ping-pong-paddle-ball": $fa-var-ping-pong-paddle-ball, - "table-tennis": $fa-var-table-tennis, - "person-dots-from-line": $fa-var-person-dots-from-line, - "diagnoses": $fa-var-diagnoses, - "trash-can-arrow-up": $fa-var-trash-can-arrow-up, - "trash-restore-alt": $fa-var-trash-restore-alt, - "naira-sign": $fa-var-naira-sign, - "cart-arrow-down": $fa-var-cart-arrow-down, - "walkie-talkie": $fa-var-walkie-talkie, - "file-pen": $fa-var-file-pen, - "file-edit": $fa-var-file-edit, - "receipt": $fa-var-receipt, - "square-pen": $fa-var-square-pen, - "pen-square": $fa-var-pen-square, - "pencil-square": $fa-var-pencil-square, - "suitcase-rolling": $fa-var-suitcase-rolling, - "person-circle-exclamation": $fa-var-person-circle-exclamation, - "chevron-down": $fa-var-chevron-down, - "battery-full": $fa-var-battery-full, - "battery": $fa-var-battery, - "battery-5": $fa-var-battery-5, - "skull-crossbones": $fa-var-skull-crossbones, - "code-compare": $fa-var-code-compare, - "list-ul": $fa-var-list-ul, - "list-dots": $fa-var-list-dots, - "school-lock": $fa-var-school-lock, - "tower-cell": $fa-var-tower-cell, - "down-long": $fa-var-down-long, - "long-arrow-alt-down": $fa-var-long-arrow-alt-down, - "ranking-star": $fa-var-ranking-star, - "chess-king": $fa-var-chess-king, - "person-harassing": $fa-var-person-harassing, - "brazilian-real-sign": $fa-var-brazilian-real-sign, - "landmark-dome": $fa-var-landmark-dome, - "landmark-alt": $fa-var-landmark-alt, - "arrow-up": $fa-var-arrow-up, - "tv": $fa-var-tv, - "television": $fa-var-television, - "tv-alt": $fa-var-tv-alt, - "shrimp": $fa-var-shrimp, - "list-check": $fa-var-list-check, - "tasks": $fa-var-tasks, - "jug-detergent": $fa-var-jug-detergent, - "circle-user": $fa-var-circle-user, - "user-circle": $fa-var-user-circle, - "user-shield": $fa-var-user-shield, - "wind": $fa-var-wind, - "car-burst": $fa-var-car-burst, - "car-crash": $fa-var-car-crash, - "y": $fa-var-y, - "person-snowboarding": $fa-var-person-snowboarding, - "snowboarding": $fa-var-snowboarding, - "truck-fast": $fa-var-truck-fast, - "shipping-fast": $fa-var-shipping-fast, - "fish": $fa-var-fish, - "user-graduate": $fa-var-user-graduate, - "circle-half-stroke": $fa-var-circle-half-stroke, - "adjust": $fa-var-adjust, - "clapperboard": $fa-var-clapperboard, - "circle-radiation": $fa-var-circle-radiation, - "radiation-alt": $fa-var-radiation-alt, - "baseball": $fa-var-baseball, - "baseball-ball": $fa-var-baseball-ball, - "jet-fighter-up": $fa-var-jet-fighter-up, - "diagram-project": $fa-var-diagram-project, - "project-diagram": $fa-var-project-diagram, - "copy": $fa-var-copy, - "volume-xmark": $fa-var-volume-xmark, - "volume-mute": $fa-var-volume-mute, - "volume-times": $fa-var-volume-times, - "hand-sparkles": $fa-var-hand-sparkles, - "grip": $fa-var-grip, - "grip-horizontal": $fa-var-grip-horizontal, - "share-from-square": $fa-var-share-from-square, - "share-square": $fa-var-share-square, - "gun": $fa-var-gun, - "square-phone": $fa-var-square-phone, - "phone-square": $fa-var-phone-square, - "plus": $fa-var-plus, - "add": $fa-var-add, - "expand": $fa-var-expand, - "computer": $fa-var-computer, - "xmark": $fa-var-xmark, - "close": $fa-var-close, - "multiply": $fa-var-multiply, - "remove": $fa-var-remove, - "times": $fa-var-times, - "arrows-up-down-left-right": $fa-var-arrows-up-down-left-right, - "arrows": $fa-var-arrows, - "chalkboard-user": $fa-var-chalkboard-user, - "chalkboard-teacher": $fa-var-chalkboard-teacher, - "peso-sign": $fa-var-peso-sign, - "building-shield": $fa-var-building-shield, - "baby": $fa-var-baby, - "users-line": $fa-var-users-line, - "quote-left": $fa-var-quote-left, - "quote-left-alt": $fa-var-quote-left-alt, - "tractor": $fa-var-tractor, - "trash-arrow-up": $fa-var-trash-arrow-up, - "trash-restore": $fa-var-trash-restore, - "arrow-down-up-lock": $fa-var-arrow-down-up-lock, - "lines-leaning": $fa-var-lines-leaning, - "ruler-combined": $fa-var-ruler-combined, - "copyright": $fa-var-copyright, - "equals": $fa-var-equals, - "blender": $fa-var-blender, - "teeth": $fa-var-teeth, - "shekel-sign": $fa-var-shekel-sign, - "ils": $fa-var-ils, - "shekel": $fa-var-shekel, - "sheqel": $fa-var-sheqel, - "sheqel-sign": $fa-var-sheqel-sign, - "map": $fa-var-map, - "rocket": $fa-var-rocket, - "photo-film": $fa-var-photo-film, - "photo-video": $fa-var-photo-video, - "folder-minus": $fa-var-folder-minus, - "store": $fa-var-store, - "arrow-trend-up": $fa-var-arrow-trend-up, - "plug-circle-minus": $fa-var-plug-circle-minus, - "sign-hanging": $fa-var-sign-hanging, - "sign": $fa-var-sign, - "bezier-curve": $fa-var-bezier-curve, - "bell-slash": $fa-var-bell-slash, - "tablet": $fa-var-tablet, - "tablet-android": $fa-var-tablet-android, - "school-flag": $fa-var-school-flag, - "fill": $fa-var-fill, - "angle-up": $fa-var-angle-up, - "drumstick-bite": $fa-var-drumstick-bite, - "holly-berry": $fa-var-holly-berry, - "chevron-left": $fa-var-chevron-left, - "bacteria": $fa-var-bacteria, - "hand-lizard": $fa-var-hand-lizard, - "disease": $fa-var-disease, - "briefcase-medical": $fa-var-briefcase-medical, - "genderless": $fa-var-genderless, - "chevron-right": $fa-var-chevron-right, - "retweet": $fa-var-retweet, - "car-rear": $fa-var-car-rear, - "car-alt": $fa-var-car-alt, - "pump-soap": $fa-var-pump-soap, - "video-slash": $fa-var-video-slash, - "battery-quarter": $fa-var-battery-quarter, - "battery-2": $fa-var-battery-2, - "radio": $fa-var-radio, - "baby-carriage": $fa-var-baby-carriage, - "carriage-baby": $fa-var-carriage-baby, - "traffic-light": $fa-var-traffic-light, - "thermometer": $fa-var-thermometer, - "vr-cardboard": $fa-var-vr-cardboard, - "hand-middle-finger": $fa-var-hand-middle-finger, - "percent": $fa-var-percent, - "percentage": $fa-var-percentage, - "truck-moving": $fa-var-truck-moving, - "glass-water-droplet": $fa-var-glass-water-droplet, - "display": $fa-var-display, - "face-smile": $fa-var-face-smile, - "smile": $fa-var-smile, - "thumbtack": $fa-var-thumbtack, - "thumb-tack": $fa-var-thumb-tack, - "trophy": $fa-var-trophy, - "person-praying": $fa-var-person-praying, - "pray": $fa-var-pray, - "hammer": $fa-var-hammer, - "hand-peace": $fa-var-hand-peace, - "rotate": $fa-var-rotate, - "sync-alt": $fa-var-sync-alt, - "spinner": $fa-var-spinner, - "robot": $fa-var-robot, - "peace": $fa-var-peace, - "gears": $fa-var-gears, - "cogs": $fa-var-cogs, - "warehouse": $fa-var-warehouse, - "arrow-up-right-dots": $fa-var-arrow-up-right-dots, - "splotch": $fa-var-splotch, - "face-grin-hearts": $fa-var-face-grin-hearts, - "grin-hearts": $fa-var-grin-hearts, - "dice-four": $fa-var-dice-four, - "sim-card": $fa-var-sim-card, - "transgender": $fa-var-transgender, - "transgender-alt": $fa-var-transgender-alt, - "mercury": $fa-var-mercury, - "arrow-turn-down": $fa-var-arrow-turn-down, - "level-down": $fa-var-level-down, - "person-falling-burst": $fa-var-person-falling-burst, - "award": $fa-var-award, - "ticket-simple": $fa-var-ticket-simple, - "ticket-alt": $fa-var-ticket-alt, - "building": $fa-var-building, - "angles-left": $fa-var-angles-left, - "angle-double-left": $fa-var-angle-double-left, - "qrcode": $fa-var-qrcode, - "clock-rotate-left": $fa-var-clock-rotate-left, - "history": $fa-var-history, - "face-grin-beam-sweat": $fa-var-face-grin-beam-sweat, - "grin-beam-sweat": $fa-var-grin-beam-sweat, - "file-export": $fa-var-file-export, - "arrow-right-from-file": $fa-var-arrow-right-from-file, - "shield": $fa-var-shield, - "shield-blank": $fa-var-shield-blank, - "arrow-up-short-wide": $fa-var-arrow-up-short-wide, - "sort-amount-up-alt": $fa-var-sort-amount-up-alt, - "house-medical": $fa-var-house-medical, - "golf-ball-tee": $fa-var-golf-ball-tee, - "golf-ball": $fa-var-golf-ball, - "circle-chevron-left": $fa-var-circle-chevron-left, - "chevron-circle-left": $fa-var-chevron-circle-left, - "house-chimney-window": $fa-var-house-chimney-window, - "pen-nib": $fa-var-pen-nib, - "tent-arrow-turn-left": $fa-var-tent-arrow-turn-left, - "tents": $fa-var-tents, - "wand-magic": $fa-var-wand-magic, - "magic": $fa-var-magic, - "dog": $fa-var-dog, - "carrot": $fa-var-carrot, - "moon": $fa-var-moon, - "wine-glass-empty": $fa-var-wine-glass-empty, - "wine-glass-alt": $fa-var-wine-glass-alt, - "cheese": $fa-var-cheese, - "yin-yang": $fa-var-yin-yang, - "music": $fa-var-music, - "code-commit": $fa-var-code-commit, - "temperature-low": $fa-var-temperature-low, - "person-biking": $fa-var-person-biking, - "biking": $fa-var-biking, - "broom": $fa-var-broom, - "shield-heart": $fa-var-shield-heart, - "gopuram": $fa-var-gopuram, - "earth-oceania": $fa-var-earth-oceania, - "globe-oceania": $fa-var-globe-oceania, - "square-xmark": $fa-var-square-xmark, - "times-square": $fa-var-times-square, - "xmark-square": $fa-var-xmark-square, - "hashtag": $fa-var-hashtag, - "up-right-and-down-left-from-center": $fa-var-up-right-and-down-left-from-center, - "expand-alt": $fa-var-expand-alt, - "oil-can": $fa-var-oil-can, - "t": $fa-var-t, - "hippo": $fa-var-hippo, - "chart-column": $fa-var-chart-column, - "infinity": $fa-var-infinity, - "vial-circle-check": $fa-var-vial-circle-check, - "person-arrow-down-to-line": $fa-var-person-arrow-down-to-line, - "voicemail": $fa-var-voicemail, - "fan": $fa-var-fan, - "person-walking-luggage": $fa-var-person-walking-luggage, - "up-down": $fa-var-up-down, - "arrows-alt-v": $fa-var-arrows-alt-v, - "cloud-moon-rain": $fa-var-cloud-moon-rain, - "calendar": $fa-var-calendar, - "trailer": $fa-var-trailer, - "bahai": $fa-var-bahai, - "haykal": $fa-var-haykal, - "sd-card": $fa-var-sd-card, - "dragon": $fa-var-dragon, - "shoe-prints": $fa-var-shoe-prints, - "circle-plus": $fa-var-circle-plus, - "plus-circle": $fa-var-plus-circle, - "face-grin-tongue-wink": $fa-var-face-grin-tongue-wink, - "grin-tongue-wink": $fa-var-grin-tongue-wink, - "hand-holding": $fa-var-hand-holding, - "plug-circle-exclamation": $fa-var-plug-circle-exclamation, - "link-slash": $fa-var-link-slash, - "chain-broken": $fa-var-chain-broken, - "chain-slash": $fa-var-chain-slash, - "unlink": $fa-var-unlink, - "clone": $fa-var-clone, - "person-walking-arrow-loop-left": $fa-var-person-walking-arrow-loop-left, - "arrow-up-z-a": $fa-var-arrow-up-z-a, - "sort-alpha-up-alt": $fa-var-sort-alpha-up-alt, - "fire-flame-curved": $fa-var-fire-flame-curved, - "fire-alt": $fa-var-fire-alt, - "tornado": $fa-var-tornado, - "file-circle-plus": $fa-var-file-circle-plus, - "book-quran": $fa-var-book-quran, - "quran": $fa-var-quran, - "anchor": $fa-var-anchor, - "border-all": $fa-var-border-all, - "face-angry": $fa-var-face-angry, - "angry": $fa-var-angry, - "cookie-bite": $fa-var-cookie-bite, - "arrow-trend-down": $fa-var-arrow-trend-down, - "rss": $fa-var-rss, - "feed": $fa-var-feed, - "draw-polygon": $fa-var-draw-polygon, - "scale-balanced": $fa-var-scale-balanced, - "balance-scale": $fa-var-balance-scale, - "gauge-simple-high": $fa-var-gauge-simple-high, - "tachometer": $fa-var-tachometer, - "tachometer-fast": $fa-var-tachometer-fast, - "shower": $fa-var-shower, - "desktop": $fa-var-desktop, - "desktop-alt": $fa-var-desktop-alt, - "m": $fa-var-m, - "table-list": $fa-var-table-list, - "th-list": $fa-var-th-list, - "comment-sms": $fa-var-comment-sms, - "sms": $fa-var-sms, - "book": $fa-var-book, - "user-plus": $fa-var-user-plus, - "check": $fa-var-check, - "battery-three-quarters": $fa-var-battery-three-quarters, - "battery-4": $fa-var-battery-4, - "house-circle-check": $fa-var-house-circle-check, - "angle-left": $fa-var-angle-left, - "diagram-successor": $fa-var-diagram-successor, - "truck-arrow-right": $fa-var-truck-arrow-right, - "arrows-split-up-and-left": $fa-var-arrows-split-up-and-left, - "hand-fist": $fa-var-hand-fist, - "fist-raised": $fa-var-fist-raised, - "cloud-moon": $fa-var-cloud-moon, - "briefcase": $fa-var-briefcase, - "person-falling": $fa-var-person-falling, - "image-portrait": $fa-var-image-portrait, - "portrait": $fa-var-portrait, - "user-tag": $fa-var-user-tag, - "rug": $fa-var-rug, - "earth-europe": $fa-var-earth-europe, - "globe-europe": $fa-var-globe-europe, - "cart-flatbed-suitcase": $fa-var-cart-flatbed-suitcase, - "luggage-cart": $fa-var-luggage-cart, - "rectangle-xmark": $fa-var-rectangle-xmark, - "rectangle-times": $fa-var-rectangle-times, - "times-rectangle": $fa-var-times-rectangle, - "window-close": $fa-var-window-close, - "baht-sign": $fa-var-baht-sign, - "book-open": $fa-var-book-open, - "book-journal-whills": $fa-var-book-journal-whills, - "journal-whills": $fa-var-journal-whills, - "handcuffs": $fa-var-handcuffs, - "triangle-exclamation": $fa-var-triangle-exclamation, - "exclamation-triangle": $fa-var-exclamation-triangle, - "warning": $fa-var-warning, - "database": $fa-var-database, - "share": $fa-var-share, - "arrow-turn-right": $fa-var-arrow-turn-right, - "mail-forward": $fa-var-mail-forward, - "bottle-droplet": $fa-var-bottle-droplet, - "mask-face": $fa-var-mask-face, - "hill-rockslide": $fa-var-hill-rockslide, - "right-left": $fa-var-right-left, - "exchange-alt": $fa-var-exchange-alt, - "paper-plane": $fa-var-paper-plane, - "road-circle-exclamation": $fa-var-road-circle-exclamation, - "dungeon": $fa-var-dungeon, - "align-right": $fa-var-align-right, - "money-bill-1-wave": $fa-var-money-bill-1-wave, - "money-bill-wave-alt": $fa-var-money-bill-wave-alt, - "life-ring": $fa-var-life-ring, - "hands": $fa-var-hands, - "sign-language": $fa-var-sign-language, - "signing": $fa-var-signing, - "calendar-day": $fa-var-calendar-day, - "water-ladder": $fa-var-water-ladder, - "ladder-water": $fa-var-ladder-water, - "swimming-pool": $fa-var-swimming-pool, - "arrows-up-down": $fa-var-arrows-up-down, - "arrows-v": $fa-var-arrows-v, - "face-grimace": $fa-var-face-grimace, - "grimace": $fa-var-grimace, - "wheelchair-move": $fa-var-wheelchair-move, - "wheelchair-alt": $fa-var-wheelchair-alt, - "turn-down": $fa-var-turn-down, - "level-down-alt": $fa-var-level-down-alt, - "person-walking-arrow-right": $fa-var-person-walking-arrow-right, - "square-envelope": $fa-var-square-envelope, - "envelope-square": $fa-var-envelope-square, - "dice": $fa-var-dice, - "bowling-ball": $fa-var-bowling-ball, - "brain": $fa-var-brain, - "bandage": $fa-var-bandage, - "band-aid": $fa-var-band-aid, - "calendar-minus": $fa-var-calendar-minus, - "circle-xmark": $fa-var-circle-xmark, - "times-circle": $fa-var-times-circle, - "xmark-circle": $fa-var-xmark-circle, - "gifts": $fa-var-gifts, - "hotel": $fa-var-hotel, - "earth-asia": $fa-var-earth-asia, - "globe-asia": $fa-var-globe-asia, - "id-card-clip": $fa-var-id-card-clip, - "id-card-alt": $fa-var-id-card-alt, - "magnifying-glass-plus": $fa-var-magnifying-glass-plus, - "search-plus": $fa-var-search-plus, - "thumbs-up": $fa-var-thumbs-up, - "user-clock": $fa-var-user-clock, - "hand-dots": $fa-var-hand-dots, - "allergies": $fa-var-allergies, - "file-invoice": $fa-var-file-invoice, - "window-minimize": $fa-var-window-minimize, - "mug-saucer": $fa-var-mug-saucer, - "coffee": $fa-var-coffee, - "brush": $fa-var-brush, - "mask": $fa-var-mask, - "magnifying-glass-minus": $fa-var-magnifying-glass-minus, - "search-minus": $fa-var-search-minus, - "ruler-vertical": $fa-var-ruler-vertical, - "user-large": $fa-var-user-large, - "user-alt": $fa-var-user-alt, - "train-tram": $fa-var-train-tram, - "user-nurse": $fa-var-user-nurse, - "syringe": $fa-var-syringe, - "cloud-sun": $fa-var-cloud-sun, - "stopwatch-20": $fa-var-stopwatch-20, - "square-full": $fa-var-square-full, - "magnet": $fa-var-magnet, - "jar": $fa-var-jar, - "note-sticky": $fa-var-note-sticky, - "sticky-note": $fa-var-sticky-note, - "bug-slash": $fa-var-bug-slash, - "arrow-up-from-water-pump": $fa-var-arrow-up-from-water-pump, - "bone": $fa-var-bone, - "user-injured": $fa-var-user-injured, - "face-sad-tear": $fa-var-face-sad-tear, - "sad-tear": $fa-var-sad-tear, - "plane": $fa-var-plane, - "tent-arrows-down": $fa-var-tent-arrows-down, - "exclamation": $fa-var-exclamation, - "arrows-spin": $fa-var-arrows-spin, - "print": $fa-var-print, - "turkish-lira-sign": $fa-var-turkish-lira-sign, - "try": $fa-var-try, - "turkish-lira": $fa-var-turkish-lira, - "dollar-sign": $fa-var-dollar-sign, - "dollar": $fa-var-dollar, - "usd": $fa-var-usd, - "x": $fa-var-x, - "magnifying-glass-dollar": $fa-var-magnifying-glass-dollar, - "search-dollar": $fa-var-search-dollar, - "users-gear": $fa-var-users-gear, - "users-cog": $fa-var-users-cog, - "person-military-pointing": $fa-var-person-military-pointing, - "building-columns": $fa-var-building-columns, - "bank": $fa-var-bank, - "institution": $fa-var-institution, - "museum": $fa-var-museum, - "university": $fa-var-university, - "umbrella": $fa-var-umbrella, - "trowel": $fa-var-trowel, - "d": $fa-var-d, - "stapler": $fa-var-stapler, - "masks-theater": $fa-var-masks-theater, - "theater-masks": $fa-var-theater-masks, - "kip-sign": $fa-var-kip-sign, - "hand-point-left": $fa-var-hand-point-left, - "handshake-simple": $fa-var-handshake-simple, - "handshake-alt": $fa-var-handshake-alt, - "jet-fighter": $fa-var-jet-fighter, - "fighter-jet": $fa-var-fighter-jet, - "square-share-nodes": $fa-var-square-share-nodes, - "share-alt-square": $fa-var-share-alt-square, - "barcode": $fa-var-barcode, - "plus-minus": $fa-var-plus-minus, - "video": $fa-var-video, - "video-camera": $fa-var-video-camera, - "graduation-cap": $fa-var-graduation-cap, - "mortar-board": $fa-var-mortar-board, - "hand-holding-medical": $fa-var-hand-holding-medical, - "person-circle-check": $fa-var-person-circle-check, - "turn-up": $fa-var-turn-up, - "level-up-alt": $fa-var-level-up-alt, -); - -$fa-brand-icons: ( - "monero": $fa-var-monero, - "hooli": $fa-var-hooli, - "yelp": $fa-var-yelp, - "cc-visa": $fa-var-cc-visa, - "lastfm": $fa-var-lastfm, - "shopware": $fa-var-shopware, - "creative-commons-nc": $fa-var-creative-commons-nc, - "aws": $fa-var-aws, - "redhat": $fa-var-redhat, - "yoast": $fa-var-yoast, - "cloudflare": $fa-var-cloudflare, - "ups": $fa-var-ups, - "wpexplorer": $fa-var-wpexplorer, - "dyalog": $fa-var-dyalog, - "bity": $fa-var-bity, - "stackpath": $fa-var-stackpath, - "buysellads": $fa-var-buysellads, - "first-order": $fa-var-first-order, - "modx": $fa-var-modx, - "guilded": $fa-var-guilded, - "vnv": $fa-var-vnv, - "square-js": $fa-var-square-js, - "js-square": $fa-var-js-square, - "microsoft": $fa-var-microsoft, - "qq": $fa-var-qq, - "orcid": $fa-var-orcid, - "java": $fa-var-java, - "invision": $fa-var-invision, - "creative-commons-pd-alt": $fa-var-creative-commons-pd-alt, - "centercode": $fa-var-centercode, - "glide-g": $fa-var-glide-g, - "drupal": $fa-var-drupal, - "hire-a-helper": $fa-var-hire-a-helper, - "creative-commons-by": $fa-var-creative-commons-by, - "unity": $fa-var-unity, - "whmcs": $fa-var-whmcs, - "rocketchat": $fa-var-rocketchat, - "vk": $fa-var-vk, - "untappd": $fa-var-untappd, - "mailchimp": $fa-var-mailchimp, - "css3-alt": $fa-var-css3-alt, - "square-reddit": $fa-var-square-reddit, - "reddit-square": $fa-var-reddit-square, - "vimeo-v": $fa-var-vimeo-v, - "contao": $fa-var-contao, - "square-font-awesome": $fa-var-square-font-awesome, - "deskpro": $fa-var-deskpro, - "sistrix": $fa-var-sistrix, - "square-instagram": $fa-var-square-instagram, - "instagram-square": $fa-var-instagram-square, - "battle-net": $fa-var-battle-net, - "the-red-yeti": $fa-var-the-red-yeti, - "square-hacker-news": $fa-var-square-hacker-news, - "hacker-news-square": $fa-var-hacker-news-square, - "edge": $fa-var-edge, - "napster": $fa-var-napster, - "square-snapchat": $fa-var-square-snapchat, - "snapchat-square": $fa-var-snapchat-square, - "google-plus-g": $fa-var-google-plus-g, - "artstation": $fa-var-artstation, - "markdown": $fa-var-markdown, - "sourcetree": $fa-var-sourcetree, - "google-plus": $fa-var-google-plus, - "diaspora": $fa-var-diaspora, - "foursquare": $fa-var-foursquare, - "stack-overflow": $fa-var-stack-overflow, - "github-alt": $fa-var-github-alt, - "phoenix-squadron": $fa-var-phoenix-squadron, - "pagelines": $fa-var-pagelines, - "algolia": $fa-var-algolia, - "red-river": $fa-var-red-river, - "creative-commons-sa": $fa-var-creative-commons-sa, - "safari": $fa-var-safari, - "google": $fa-var-google, - "square-font-awesome-stroke": $fa-var-square-font-awesome-stroke, - "font-awesome-alt": $fa-var-font-awesome-alt, - "atlassian": $fa-var-atlassian, - "linkedin-in": $fa-var-linkedin-in, - "digital-ocean": $fa-var-digital-ocean, - "nimblr": $fa-var-nimblr, - "chromecast": $fa-var-chromecast, - "evernote": $fa-var-evernote, - "hacker-news": $fa-var-hacker-news, - "creative-commons-sampling": $fa-var-creative-commons-sampling, - "adversal": $fa-var-adversal, - "creative-commons": $fa-var-creative-commons, - "watchman-monitoring": $fa-var-watchman-monitoring, - "fonticons": $fa-var-fonticons, - "weixin": $fa-var-weixin, - "shirtsinbulk": $fa-var-shirtsinbulk, - "codepen": $fa-var-codepen, - "git-alt": $fa-var-git-alt, - "lyft": $fa-var-lyft, - "rev": $fa-var-rev, - "windows": $fa-var-windows, - "wizards-of-the-coast": $fa-var-wizards-of-the-coast, - "square-viadeo": $fa-var-square-viadeo, - "viadeo-square": $fa-var-viadeo-square, - "meetup": $fa-var-meetup, - "centos": $fa-var-centos, - "adn": $fa-var-adn, - "cloudsmith": $fa-var-cloudsmith, - "pied-piper-alt": $fa-var-pied-piper-alt, - "square-dribbble": $fa-var-square-dribbble, - "dribbble-square": $fa-var-dribbble-square, - "codiepie": $fa-var-codiepie, - "node": $fa-var-node, - "mix": $fa-var-mix, - "steam": $fa-var-steam, - "cc-apple-pay": $fa-var-cc-apple-pay, - "scribd": $fa-var-scribd, - "openid": $fa-var-openid, - "instalod": $fa-var-instalod, - "expeditedssl": $fa-var-expeditedssl, - "sellcast": $fa-var-sellcast, - "square-twitter": $fa-var-square-twitter, - "twitter-square": $fa-var-twitter-square, - "r-project": $fa-var-r-project, - "delicious": $fa-var-delicious, - "freebsd": $fa-var-freebsd, - "vuejs": $fa-var-vuejs, - "accusoft": $fa-var-accusoft, - "ioxhost": $fa-var-ioxhost, - "fonticons-fi": $fa-var-fonticons-fi, - "app-store": $fa-var-app-store, - "cc-mastercard": $fa-var-cc-mastercard, - "itunes-note": $fa-var-itunes-note, - "golang": $fa-var-golang, - "kickstarter": $fa-var-kickstarter, - "grav": $fa-var-grav, - "weibo": $fa-var-weibo, - "uncharted": $fa-var-uncharted, - "firstdraft": $fa-var-firstdraft, - "square-youtube": $fa-var-square-youtube, - "youtube-square": $fa-var-youtube-square, - "wikipedia-w": $fa-var-wikipedia-w, - "wpressr": $fa-var-wpressr, - "rendact": $fa-var-rendact, - "angellist": $fa-var-angellist, - "galactic-republic": $fa-var-galactic-republic, - "nfc-directional": $fa-var-nfc-directional, - "skype": $fa-var-skype, - "joget": $fa-var-joget, - "fedora": $fa-var-fedora, - "stripe-s": $fa-var-stripe-s, - "meta": $fa-var-meta, - "laravel": $fa-var-laravel, - "hotjar": $fa-var-hotjar, - "bluetooth-b": $fa-var-bluetooth-b, - "sticker-mule": $fa-var-sticker-mule, - "creative-commons-zero": $fa-var-creative-commons-zero, - "hips": $fa-var-hips, - "behance": $fa-var-behance, - "reddit": $fa-var-reddit, - "discord": $fa-var-discord, - "chrome": $fa-var-chrome, - "app-store-ios": $fa-var-app-store-ios, - "cc-discover": $fa-var-cc-discover, - "wpbeginner": $fa-var-wpbeginner, - "confluence": $fa-var-confluence, - "mdb": $fa-var-mdb, - "dochub": $fa-var-dochub, - "accessible-icon": $fa-var-accessible-icon, - "ebay": $fa-var-ebay, - "amazon": $fa-var-amazon, - "unsplash": $fa-var-unsplash, - "yarn": $fa-var-yarn, - "square-steam": $fa-var-square-steam, - "steam-square": $fa-var-steam-square, - "500px": $fa-var-500px, - "square-vimeo": $fa-var-square-vimeo, - "vimeo-square": $fa-var-vimeo-square, - "asymmetrik": $fa-var-asymmetrik, - "font-awesome": $fa-var-font-awesome, - "font-awesome-flag": $fa-var-font-awesome-flag, - "font-awesome-logo-full": $fa-var-font-awesome-logo-full, - "gratipay": $fa-var-gratipay, - "apple": $fa-var-apple, - "hive": $fa-var-hive, - "gitkraken": $fa-var-gitkraken, - "keybase": $fa-var-keybase, - "apple-pay": $fa-var-apple-pay, - "padlet": $fa-var-padlet, - "amazon-pay": $fa-var-amazon-pay, - "square-github": $fa-var-square-github, - "github-square": $fa-var-github-square, - "stumbleupon": $fa-var-stumbleupon, - "fedex": $fa-var-fedex, - "phoenix-framework": $fa-var-phoenix-framework, - "shopify": $fa-var-shopify, - "neos": $fa-var-neos, - "hackerrank": $fa-var-hackerrank, - "researchgate": $fa-var-researchgate, - "swift": $fa-var-swift, - "angular": $fa-var-angular, - "speakap": $fa-var-speakap, - "angrycreative": $fa-var-angrycreative, - "y-combinator": $fa-var-y-combinator, - "empire": $fa-var-empire, - "envira": $fa-var-envira, - "square-gitlab": $fa-var-square-gitlab, - "gitlab-square": $fa-var-gitlab-square, - "studiovinari": $fa-var-studiovinari, - "pied-piper": $fa-var-pied-piper, - "wordpress": $fa-var-wordpress, - "product-hunt": $fa-var-product-hunt, - "firefox": $fa-var-firefox, - "linode": $fa-var-linode, - "goodreads": $fa-var-goodreads, - "square-odnoklassniki": $fa-var-square-odnoklassniki, - "odnoklassniki-square": $fa-var-odnoklassniki-square, - "jsfiddle": $fa-var-jsfiddle, - "sith": $fa-var-sith, - "themeisle": $fa-var-themeisle, - "page4": $fa-var-page4, - "hashnode": $fa-var-hashnode, - "react": $fa-var-react, - "cc-paypal": $fa-var-cc-paypal, - "squarespace": $fa-var-squarespace, - "cc-stripe": $fa-var-cc-stripe, - "creative-commons-share": $fa-var-creative-commons-share, - "bitcoin": $fa-var-bitcoin, - "keycdn": $fa-var-keycdn, - "opera": $fa-var-opera, - "itch-io": $fa-var-itch-io, - "umbraco": $fa-var-umbraco, - "galactic-senate": $fa-var-galactic-senate, - "ubuntu": $fa-var-ubuntu, - "draft2digital": $fa-var-draft2digital, - "stripe": $fa-var-stripe, - "houzz": $fa-var-houzz, - "gg": $fa-var-gg, - "dhl": $fa-var-dhl, - "square-pinterest": $fa-var-square-pinterest, - "pinterest-square": $fa-var-pinterest-square, - "xing": $fa-var-xing, - "blackberry": $fa-var-blackberry, - "creative-commons-pd": $fa-var-creative-commons-pd, - "playstation": $fa-var-playstation, - "quinscape": $fa-var-quinscape, - "less": $fa-var-less, - "blogger-b": $fa-var-blogger-b, - "opencart": $fa-var-opencart, - "vine": $fa-var-vine, - "paypal": $fa-var-paypal, - "gitlab": $fa-var-gitlab, - "typo3": $fa-var-typo3, - "reddit-alien": $fa-var-reddit-alien, - "yahoo": $fa-var-yahoo, - "dailymotion": $fa-var-dailymotion, - "affiliatetheme": $fa-var-affiliatetheme, - "pied-piper-pp": $fa-var-pied-piper-pp, - "bootstrap": $fa-var-bootstrap, - "odnoklassniki": $fa-var-odnoklassniki, - "nfc-symbol": $fa-var-nfc-symbol, - "ethereum": $fa-var-ethereum, - "speaker-deck": $fa-var-speaker-deck, - "creative-commons-nc-eu": $fa-var-creative-commons-nc-eu, - "patreon": $fa-var-patreon, - "avianex": $fa-var-avianex, - "ello": $fa-var-ello, - "gofore": $fa-var-gofore, - "bimobject": $fa-var-bimobject, - "facebook-f": $fa-var-facebook-f, - "square-google-plus": $fa-var-square-google-plus, - "google-plus-square": $fa-var-google-plus-square, - "mandalorian": $fa-var-mandalorian, - "first-order-alt": $fa-var-first-order-alt, - "osi": $fa-var-osi, - "google-wallet": $fa-var-google-wallet, - "d-and-d-beyond": $fa-var-d-and-d-beyond, - "periscope": $fa-var-periscope, - "fulcrum": $fa-var-fulcrum, - "cloudscale": $fa-var-cloudscale, - "forumbee": $fa-var-forumbee, - "mizuni": $fa-var-mizuni, - "schlix": $fa-var-schlix, - "square-xing": $fa-var-square-xing, - "xing-square": $fa-var-xing-square, - "bandcamp": $fa-var-bandcamp, - "wpforms": $fa-var-wpforms, - "cloudversify": $fa-var-cloudversify, - "usps": $fa-var-usps, - "megaport": $fa-var-megaport, - "magento": $fa-var-magento, - "spotify": $fa-var-spotify, - "optin-monster": $fa-var-optin-monster, - "fly": $fa-var-fly, - "aviato": $fa-var-aviato, - "itunes": $fa-var-itunes, - "cuttlefish": $fa-var-cuttlefish, - "blogger": $fa-var-blogger, - "flickr": $fa-var-flickr, - "viber": $fa-var-viber, - "soundcloud": $fa-var-soundcloud, - "digg": $fa-var-digg, - "tencent-weibo": $fa-var-tencent-weibo, - "symfony": $fa-var-symfony, - "maxcdn": $fa-var-maxcdn, - "etsy": $fa-var-etsy, - "facebook-messenger": $fa-var-facebook-messenger, - "audible": $fa-var-audible, - "think-peaks": $fa-var-think-peaks, - "bilibili": $fa-var-bilibili, - "erlang": $fa-var-erlang, - "cotton-bureau": $fa-var-cotton-bureau, - "dashcube": $fa-var-dashcube, - "42-group": $fa-var-42-group, - "innosoft": $fa-var-innosoft, - "stack-exchange": $fa-var-stack-exchange, - "elementor": $fa-var-elementor, - "square-pied-piper": $fa-var-square-pied-piper, - "pied-piper-square": $fa-var-pied-piper-square, - "creative-commons-nd": $fa-var-creative-commons-nd, - "palfed": $fa-var-palfed, - "superpowers": $fa-var-superpowers, - "resolving": $fa-var-resolving, - "xbox": $fa-var-xbox, - "searchengin": $fa-var-searchengin, - "tiktok": $fa-var-tiktok, - "square-facebook": $fa-var-square-facebook, - "facebook-square": $fa-var-facebook-square, - "renren": $fa-var-renren, - "linux": $fa-var-linux, - "glide": $fa-var-glide, - "linkedin": $fa-var-linkedin, - "hubspot": $fa-var-hubspot, - "deploydog": $fa-var-deploydog, - "twitch": $fa-var-twitch, - "ravelry": $fa-var-ravelry, - "mixer": $fa-var-mixer, - "square-lastfm": $fa-var-square-lastfm, - "lastfm-square": $fa-var-lastfm-square, - "vimeo": $fa-var-vimeo, - "mendeley": $fa-var-mendeley, - "uniregistry": $fa-var-uniregistry, - "figma": $fa-var-figma, - "creative-commons-remix": $fa-var-creative-commons-remix, - "cc-amazon-pay": $fa-var-cc-amazon-pay, - "dropbox": $fa-var-dropbox, - "instagram": $fa-var-instagram, - "cmplid": $fa-var-cmplid, - "facebook": $fa-var-facebook, - "gripfire": $fa-var-gripfire, - "jedi-order": $fa-var-jedi-order, - "uikit": $fa-var-uikit, - "fort-awesome-alt": $fa-var-fort-awesome-alt, - "phabricator": $fa-var-phabricator, - "ussunnah": $fa-var-ussunnah, - "earlybirds": $fa-var-earlybirds, - "trade-federation": $fa-var-trade-federation, - "autoprefixer": $fa-var-autoprefixer, - "whatsapp": $fa-var-whatsapp, - "slideshare": $fa-var-slideshare, - "google-play": $fa-var-google-play, - "viadeo": $fa-var-viadeo, - "line": $fa-var-line, - "google-drive": $fa-var-google-drive, - "servicestack": $fa-var-servicestack, - "simplybuilt": $fa-var-simplybuilt, - "bitbucket": $fa-var-bitbucket, - "imdb": $fa-var-imdb, - "deezer": $fa-var-deezer, - "raspberry-pi": $fa-var-raspberry-pi, - "jira": $fa-var-jira, - "docker": $fa-var-docker, - "screenpal": $fa-var-screenpal, - "bluetooth": $fa-var-bluetooth, - "gitter": $fa-var-gitter, - "d-and-d": $fa-var-d-and-d, - "microblog": $fa-var-microblog, - "cc-diners-club": $fa-var-cc-diners-club, - "gg-circle": $fa-var-gg-circle, - "pied-piper-hat": $fa-var-pied-piper-hat, - "kickstarter-k": $fa-var-kickstarter-k, - "yandex": $fa-var-yandex, - "readme": $fa-var-readme, - "html5": $fa-var-html5, - "sellsy": $fa-var-sellsy, - "sass": $fa-var-sass, - "wirsindhandwerk": $fa-var-wirsindhandwerk, - "wsh": $fa-var-wsh, - "buromobelexperte": $fa-var-buromobelexperte, - "salesforce": $fa-var-salesforce, - "octopus-deploy": $fa-var-octopus-deploy, - "medapps": $fa-var-medapps, - "ns8": $fa-var-ns8, - "pinterest-p": $fa-var-pinterest-p, - "apper": $fa-var-apper, - "fort-awesome": $fa-var-fort-awesome, - "waze": $fa-var-waze, - "cc-jcb": $fa-var-cc-jcb, - "snapchat": $fa-var-snapchat, - "snapchat-ghost": $fa-var-snapchat-ghost, - "fantasy-flight-games": $fa-var-fantasy-flight-games, - "rust": $fa-var-rust, - "wix": $fa-var-wix, - "square-behance": $fa-var-square-behance, - "behance-square": $fa-var-behance-square, - "supple": $fa-var-supple, - "rebel": $fa-var-rebel, - "css3": $fa-var-css3, - "staylinked": $fa-var-staylinked, - "kaggle": $fa-var-kaggle, - "space-awesome": $fa-var-space-awesome, - "deviantart": $fa-var-deviantart, - "cpanel": $fa-var-cpanel, - "goodreads-g": $fa-var-goodreads-g, - "square-git": $fa-var-square-git, - "git-square": $fa-var-git-square, - "square-tumblr": $fa-var-square-tumblr, - "tumblr-square": $fa-var-tumblr-square, - "trello": $fa-var-trello, - "creative-commons-nc-jp": $fa-var-creative-commons-nc-jp, - "get-pocket": $fa-var-get-pocket, - "perbyte": $fa-var-perbyte, - "grunt": $fa-var-grunt, - "weebly": $fa-var-weebly, - "connectdevelop": $fa-var-connectdevelop, - "leanpub": $fa-var-leanpub, - "black-tie": $fa-var-black-tie, - "themeco": $fa-var-themeco, - "python": $fa-var-python, - "android": $fa-var-android, - "bots": $fa-var-bots, - "free-code-camp": $fa-var-free-code-camp, - "hornbill": $fa-var-hornbill, - "js": $fa-var-js, - "ideal": $fa-var-ideal, - "git": $fa-var-git, - "dev": $fa-var-dev, - "sketch": $fa-var-sketch, - "yandex-international": $fa-var-yandex-international, - "cc-amex": $fa-var-cc-amex, - "uber": $fa-var-uber, - "github": $fa-var-github, - "php": $fa-var-php, - "alipay": $fa-var-alipay, - "youtube": $fa-var-youtube, - "skyatlas": $fa-var-skyatlas, - "firefox-browser": $fa-var-firefox-browser, - "replyd": $fa-var-replyd, - "suse": $fa-var-suse, - "jenkins": $fa-var-jenkins, - "twitter": $fa-var-twitter, - "rockrms": $fa-var-rockrms, - "pinterest": $fa-var-pinterest, - "buffer": $fa-var-buffer, - "npm": $fa-var-npm, - "yammer": $fa-var-yammer, - "btc": $fa-var-btc, - "dribbble": $fa-var-dribbble, - "stumbleupon-circle": $fa-var-stumbleupon-circle, - "internet-explorer": $fa-var-internet-explorer, - "telegram": $fa-var-telegram, - "telegram-plane": $fa-var-telegram-plane, - "old-republic": $fa-var-old-republic, - "square-whatsapp": $fa-var-square-whatsapp, - "whatsapp-square": $fa-var-whatsapp-square, - "node-js": $fa-var-node-js, - "edge-legacy": $fa-var-edge-legacy, - "slack": $fa-var-slack, - "slack-hash": $fa-var-slack-hash, - "medrt": $fa-var-medrt, - "usb": $fa-var-usb, - "tumblr": $fa-var-tumblr, - "vaadin": $fa-var-vaadin, - "quora": $fa-var-quora, - "reacteurope": $fa-var-reacteurope, - "medium": $fa-var-medium, - "medium-m": $fa-var-medium-m, - "amilia": $fa-var-amilia, - "mixcloud": $fa-var-mixcloud, - "flipboard": $fa-var-flipboard, - "viacoin": $fa-var-viacoin, - "critical-role": $fa-var-critical-role, - "sitrox": $fa-var-sitrox, - "discourse": $fa-var-discourse, - "joomla": $fa-var-joomla, - "mastodon": $fa-var-mastodon, - "airbnb": $fa-var-airbnb, - "wolf-pack-battalion": $fa-var-wolf-pack-battalion, - "buy-n-large": $fa-var-buy-n-large, - "gulp": $fa-var-gulp, - "creative-commons-sampling-plus": $fa-var-creative-commons-sampling-plus, - "strava": $fa-var-strava, - "ember": $fa-var-ember, - "canadian-maple-leaf": $fa-var-canadian-maple-leaf, - "teamspeak": $fa-var-teamspeak, - "pushed": $fa-var-pushed, - "wordpress-simple": $fa-var-wordpress-simple, - "nutritionix": $fa-var-nutritionix, - "wodu": $fa-var-wodu, - "google-pay": $fa-var-google-pay, - "intercom": $fa-var-intercom, - "zhihu": $fa-var-zhihu, - "korvue": $fa-var-korvue, - "pix": $fa-var-pix, - "steam-symbol": $fa-var-steam-symbol, -); diff --git a/public/vendor/fontawesome/scss/brands.scss b/public/vendor/fontawesome/scss/brands.scss deleted file mode 100644 index 617535bba8..0000000000 --- a/public/vendor/fontawesome/scss/brands.scss +++ /dev/null @@ -1,30 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -@import 'functions'; -@import 'variables'; - -:root, :host { - --#{$fa-css-prefix}-style-family-brands: 'Font Awesome 6 Brands'; - --#{$fa-css-prefix}-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; -} - -@font-face { - font-family: 'Font Awesome 6 Brands'; - font-style: normal; - font-weight: 400; - font-display: $fa-font-display; - src: url('#{$fa-font-path}/fa-brands-400.woff2') format('woff2'), - url('#{$fa-font-path}/fa-brands-400.ttf') format('truetype'); -} - -.fab, -.#{$fa-css-prefix}-brands { - font-weight: 400; -} - -@each $name, $icon in $fa-brand-icons { - .#{$fa-css-prefix}-#{$name}:before { content: unquote("\"#{ $icon }\""); } -} diff --git a/public/vendor/fontawesome/scss/fontawesome.scss b/public/vendor/fontawesome/scss/fontawesome.scss deleted file mode 100644 index c14ee94283..0000000000 --- a/public/vendor/fontawesome/scss/fontawesome.scss +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -// Font Awesome core compile (Web Fonts-based) -// ------------------------- - -@import 'functions'; -@import 'variables'; -@import 'mixins'; -@import 'core'; -@import 'sizing'; -@import 'fixed-width'; -@import 'list'; -@import 'bordered-pulled'; -@import 'animated'; -@import 'rotated-flipped'; -@import 'stacked'; -@import 'icons'; -@import 'screen-reader'; diff --git a/public/vendor/fontawesome/scss/regular.scss b/public/vendor/fontawesome/scss/regular.scss deleted file mode 100644 index 0985c48df0..0000000000 --- a/public/vendor/fontawesome/scss/regular.scss +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -@import 'functions'; -@import 'variables'; - -:root, :host { - --#{$fa-css-prefix}-style-family-classic: '#{ $fa-style-family }'; - --#{$fa-css-prefix}-font-regular: normal 400 1em/1 '#{ $fa-style-family }'; -} - -@font-face { - font-family: 'Font Awesome 6 Free'; - font-style: normal; - font-weight: 400; - font-display: $fa-font-display; - src: url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'), - url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'); -} - -.far, -.#{$fa-css-prefix}-regular { - font-weight: 400; -} diff --git a/public/vendor/fontawesome/scss/solid.scss b/public/vendor/fontawesome/scss/solid.scss deleted file mode 100644 index 9b90120033..0000000000 --- a/public/vendor/fontawesome/scss/solid.scss +++ /dev/null @@ -1,26 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -@import 'functions'; -@import 'variables'; - -:root, :host { - --#{$fa-css-prefix}-style-family-classic: '#{ $fa-style-family }'; - --#{$fa-css-prefix}-font-solid: normal 900 1em/1 '#{ $fa-style-family }'; -} - -@font-face { - font-family: 'Font Awesome 6 Free'; - font-style: normal; - font-weight: 900; - font-display: $fa-font-display; - src: url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'), - url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'); -} - -.fas, -.#{$fa-css-prefix}-solid { - font-weight: 900; -} diff --git a/public/vendor/fontawesome/scss/v4-shims.scss b/public/vendor/fontawesome/scss/v4-shims.scss deleted file mode 100644 index 2e267770a9..0000000000 --- a/public/vendor/fontawesome/scss/v4-shims.scss +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - * Copyright 2022 Fonticons, Inc. - */ -// V4 shims compile (Web Fonts-based) -// ------------------------- - -@import 'functions'; -@import 'variables'; -@import 'shims'; diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-brands-400.ttf deleted file mode 100644 index 502f3621e7f97d1d94ce05794e47a6c6a56e94e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186112 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 diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.ttf deleted file mode 100644 index 13c9489771fd4e60ed0ea9303e882f94f640ec6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 397728 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

    i|I718`*rt|GmTIU1 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
    ob`%8gI^rtK!=OYkA-N~JwDH`iz&8WQCv=spLL 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
    #+EkODqv!&>Eb>LGm0 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 PqgJwz$gNb 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 diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.woff2 b/public/vendor/fontawesome/webfonts/6.2.0/fa-solid-900.woff2 deleted file mode 100644 index 3516fdbe330ef1cd0775dbb5bdee41a4ce2cc010..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150472 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 z 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 diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.ttf b/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.ttf deleted file mode 100644 index dc2981941df8e153515fcc8718292d5e83b3d594..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10136 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 AZvX%Q diff --git a/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.woff2 b/public/vendor/fontawesome/webfonts/6.2.0/fa-v4compatibility.woff2 deleted file mode 100644 index 28d46b15ace8f3e5056c6de1e387062b92c8dae3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4584 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 SoVIq!9~U|32P^TH0RsTY6q0@b diff --git a/src/controllers/api.js b/src/controllers/api.js index e0f23206f9..7aebe9c3e3 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -10,6 +10,7 @@ const plugins = require('../plugins'); const translator = require('../translator'); const languages = require('../languages'); const { generateToken } = require('../middleware/csrf'); +const utils = require('../utils'); const apiController = module.exports; @@ -19,6 +20,9 @@ const asset_base_url = nconf.get('asset_base_url'); const socketioTransports = nconf.get('socket.io:transports') || ['polling', 'websocket']; const socketioOrigins = nconf.get('socket.io:origins'); const websocketAddress = nconf.get('socket.io:address') || ''; +const fontawesome_pro = nconf.get('fontawesome:pro') || false; +const fontawesome_styles = utils.getFontawesomeStyles(); +const fontawesome_version = utils.getFontawesomeVersion(); apiController.loadConfig = async function (req) { const config = { @@ -86,6 +90,11 @@ apiController.loadConfig = async function (req) { iconBackgrounds: await user.getIconBackgrounds(req.uid), emailPrompt: meta.config.emailPrompt, useragent: req.useragent, + fontawesome: { + pro: fontawesome_pro, + styles: fontawesome_styles, + version: fontawesome_version, + }, }; let settings = config; diff --git a/src/meta/css.js b/src/meta/css.js index 8b19edbc92..d9edcdf360 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -10,6 +10,7 @@ const plugins = require('../plugins'); const db = require('../database'); const file = require('../file'); const minifier = require('./minifier'); +const utils = require('../utils'); const CSS = module.exports; @@ -35,7 +36,8 @@ const buildImports = { '@import "admin/overrides";', '@import "bootstrap/scss/bootstrap";', '@import "mixins";', - '@import "fontawesome";', + '@import "fontawesome/loader";', + getFontawesomeStyle(), '@import "@adactive/bootstrap-tagsinput/src/bootstrap-tagsinput";', '@import "generics";', '@import "responsive-utilities";', @@ -119,7 +121,9 @@ function boostrapImport(themeData) { '@import "bootstrap/scss/utilities/api";', // scss-docs-end import-stack - '@import "fontawesome";', + '@import "fontawesome/loader";', + getFontawesomeStyle(), + '@import "mixins";', // core mixins '@import "generics";', '@import "client";', // core page styles @@ -128,6 +132,12 @@ function boostrapImport(themeData) { ].join('\n'); } + +function getFontawesomeStyle() { + const styles = utils.getFontawesomeStyles(); + return styles.map(style => `@import "fontawesome/style-${style}";`).join('\n'); +} + async function filterMissingFiles(filepaths) { const exists = await Promise.all( filepaths.map(async (filepath) => { @@ -176,6 +186,7 @@ async function getBundleMetadata(target) { path.join(__dirname, '../../node_modules'), path.join(__dirname, '../../public/scss'), path.join(__dirname, '../../public/vendor/fontawesome/scss'), + path.join(utils.getFontawesomePath(), 'scss'), ]; // Skin support diff --git a/src/prestart.js b/src/prestart.js index bda51ad9e5..7a84a0a958 100644 --- a/src/prestart.js +++ b/src/prestart.js @@ -58,6 +58,10 @@ function loadConfig(configFile) { isCluster: false, isPrimary: true, jobsDisabled: false, + fontawesome: { + pro: false, + styles: '*', + }, }); // Explicitly cast as Bool, loader.js passes in isCluster as string 'true'/'false' diff --git a/src/routes/index.js b/src/routes/index.js index 4008f1565a..97fa857a1a 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -9,6 +9,7 @@ const meta = require('../meta'); const controllers = require('../controllers'); const controllerHelpers = require('../controllers/helpers'); const plugins = require('../plugins'); +const utils = require('../utils'); const authRoutes = require('./authentication'); const writeRoutes = require('./write'); @@ -172,6 +173,7 @@ function addCoreRoutes(app, router, middleware, mounts) { const statics = [ { route: '/assets', path: path.join(__dirname, '../../build/public') }, { route: '/assets', path: path.join(__dirname, '../../public') }, + { route: '/assets/vendor/fontawesome/webfonts', path: path.join(utils.getFontawesomePath(), 'webfonts') }, ]; const staticOptions = { maxAge: app.enabled('cache') ? 5184000000 : 0, diff --git a/src/utils.js b/src/utils.js index 2d0d2e7b9c..fb59865f69 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,6 +1,8 @@ 'use strict'; const crypto = require('crypto'); +const nconf = require('nconf'); +const path = require('node:path'); process.profile = function (operation, start) { console.log('%s took %d milliseconds', operation, process.elapsedTimeSince(start)); @@ -38,4 +40,36 @@ utils.getSass = function () { } }; +utils.getFontawesomePath = function () { + let packageName = '@fortawesome/fontawesome-free'; + if (nconf.get('fontawesome:pro') === true) { + packageName = '@fortawesome/fontawesome-pro'; + } + const pathToMainFile = require.resolve(packageName); + // main file will be in `js/fontawesome.js` - we need to go up two directories to get to the root of the package + const fontawesomePath = path.dirname(path.dirname(pathToMainFile)); + return fontawesomePath; +}; + +utils.getFontawesomeStyles = function () { + let styles = nconf.get('fontawesome:styles') || '*'; + // "*" is a special case, it means all styles, spread is used to support both string and array (["*"]) + if ([...styles][0] === '*') { + styles = ['solid', 'brands', 'regular']; + if (nconf.get('fontawesome:pro')) { + styles.push('light', 'thin', 'sharp', 'duotone'); + } + } + if (!Array.isArray(styles)) { + styles = [styles]; + } + return styles; +}; + +utils.getFontawesomeVersion = function () { + const fontawesomePath = utils.getFontawesomePath(); + const packageJson = require(path.join(fontawesomePath, 'package.json')); + return packageJson.version; +}; + module.exports = utils; From 910aeb2ca28abbb1cb23b36c6b622b94cd0f3e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 31 Jul 2023 11:27:37 -0400 Subject: [PATCH 190/300] add missing tooltip --- install/package.json | 2 +- public/language/en-GB/admin/admin.json | 3 ++- public/language/en-GB/admin/manage/categories.json | 1 - src/views/admin/manage/category.tpl | 2 +- src/views/admin/manage/group.tpl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/install/package.json b/install/package.json index ce041b6c28..c237da149f 100644 --- a/install/package.json +++ b/install/package.json @@ -102,7 +102,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.19", + "nodebb-theme-harmony": "1.1.20", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.6", "nodebb-theme-persona": "13.2.11", diff --git a/public/language/en-GB/admin/admin.json b/public/language/en-GB/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/en-GB/admin/admin.json +++ b/public/language/en-GB/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/en-GB/admin/manage/categories.json b/public/language/en-GB/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/en-GB/admin/manage/categories.json +++ b/public/language/en-GB/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/src/views/admin/manage/category.tpl b/src/views/admin/manage/category.tpl index 4c34df4730..9da7e1b079 100644 --- a/src/views/admin/manage/category.tpl +++ b/src/views/admin/manage/category.tpl @@ -99,7 +99,7 @@

    -
    +
    From f075e12a919a4f8098b2c98b0b7285af4bb9ea77 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 31 Jul 2023 15:28:17 +0000 Subject: [PATCH 191/300] chore(i18n): fallback strings for new resources: nodebb.admin-admin, nodebb.admin-manage-categories --- public/language/ar/admin/admin.json | 3 ++- public/language/ar/admin/manage/categories.json | 1 - public/language/bg/admin/admin.json | 3 ++- public/language/bg/admin/manage/categories.json | 1 - public/language/bn/admin/admin.json | 3 ++- public/language/bn/admin/manage/categories.json | 1 - public/language/cs/admin/admin.json | 3 ++- public/language/cs/admin/manage/categories.json | 1 - public/language/da/admin/admin.json | 3 ++- public/language/da/admin/manage/categories.json | 1 - public/language/de/admin/admin.json | 3 ++- public/language/de/admin/manage/categories.json | 1 - public/language/el/admin/admin.json | 3 ++- public/language/el/admin/manage/categories.json | 1 - public/language/en-US/admin/admin.json | 3 ++- public/language/en-US/admin/manage/categories.json | 1 - public/language/en-x-pirate/admin/admin.json | 3 ++- public/language/en-x-pirate/admin/manage/categories.json | 1 - public/language/es/admin/admin.json | 3 ++- public/language/es/admin/manage/categories.json | 1 - public/language/et/admin/admin.json | 3 ++- public/language/et/admin/manage/categories.json | 1 - public/language/fa-IR/admin/admin.json | 3 ++- public/language/fa-IR/admin/manage/categories.json | 1 - public/language/fi/admin/admin.json | 3 ++- public/language/fi/admin/manage/categories.json | 1 - public/language/fr/admin/admin.json | 3 ++- public/language/fr/admin/manage/categories.json | 1 - public/language/gl/admin/admin.json | 3 ++- public/language/gl/admin/manage/categories.json | 1 - public/language/he/admin/admin.json | 3 ++- public/language/he/admin/manage/categories.json | 1 - public/language/hr/admin/admin.json | 3 ++- public/language/hr/admin/manage/categories.json | 1 - public/language/hu/admin/admin.json | 3 ++- public/language/hu/admin/manage/categories.json | 1 - public/language/hy/admin/admin.json | 3 ++- public/language/hy/admin/manage/categories.json | 1 - public/language/id/admin/admin.json | 3 ++- public/language/id/admin/manage/categories.json | 1 - public/language/it/admin/admin.json | 3 ++- public/language/it/admin/manage/categories.json | 1 - public/language/ja/admin/admin.json | 3 ++- public/language/ja/admin/manage/categories.json | 1 - public/language/ko/admin/admin.json | 3 ++- public/language/ko/admin/manage/categories.json | 1 - public/language/lt/admin/admin.json | 3 ++- public/language/lt/admin/manage/categories.json | 1 - public/language/lv/admin/admin.json | 3 ++- public/language/lv/admin/manage/categories.json | 1 - public/language/ms/admin/admin.json | 3 ++- public/language/ms/admin/manage/categories.json | 1 - public/language/nb/admin/admin.json | 3 ++- public/language/nb/admin/manage/categories.json | 1 - public/language/nl/admin/admin.json | 3 ++- public/language/nl/admin/manage/categories.json | 1 - public/language/pl/admin/admin.json | 3 ++- public/language/pl/admin/manage/categories.json | 1 - public/language/pt-BR/admin/admin.json | 3 ++- public/language/pt-BR/admin/manage/categories.json | 1 - public/language/pt-PT/admin/admin.json | 3 ++- public/language/pt-PT/admin/manage/categories.json | 1 - public/language/ro/admin/admin.json | 3 ++- public/language/ro/admin/manage/categories.json | 1 - public/language/ru/admin/admin.json | 3 ++- public/language/ru/admin/manage/categories.json | 1 - public/language/rw/admin/admin.json | 3 ++- public/language/rw/admin/manage/categories.json | 1 - public/language/sc/admin/admin.json | 3 ++- public/language/sc/admin/manage/categories.json | 1 - public/language/sk/admin/admin.json | 3 ++- public/language/sk/admin/manage/categories.json | 1 - public/language/sl/admin/admin.json | 3 ++- public/language/sl/admin/manage/categories.json | 1 - public/language/sq-AL/admin/admin.json | 3 ++- public/language/sq-AL/admin/manage/categories.json | 1 - public/language/sr/admin/admin.json | 3 ++- public/language/sr/admin/manage/categories.json | 1 - public/language/sv/admin/admin.json | 3 ++- public/language/sv/admin/manage/categories.json | 1 - public/language/th/admin/admin.json | 3 ++- public/language/th/admin/manage/categories.json | 1 - public/language/tr/admin/admin.json | 3 ++- public/language/tr/admin/manage/categories.json | 1 - public/language/uk/admin/admin.json | 3 ++- public/language/uk/admin/manage/categories.json | 1 - public/language/vi/admin/admin.json | 3 ++- public/language/vi/admin/manage/categories.json | 1 - public/language/zh-CN/admin/admin.json | 3 ++- public/language/zh-CN/admin/manage/categories.json | 1 - public/language/zh-TW/admin/admin.json | 3 ++- public/language/zh-TW/admin/manage/categories.json | 1 - 92 files changed, 92 insertions(+), 92 deletions(-) diff --git a/public/language/ar/admin/admin.json b/public/language/ar/admin/admin.json index 3a578f3e95..626d8e2212 100644 --- a/public/language/ar/admin/admin.json +++ b/public/language/ar/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ar/admin/manage/categories.json b/public/language/ar/admin/manage/categories.json index 2f371d2292..ae485deeaa 100644 --- a/public/language/ar/admin/manage/categories.json +++ b/public/language/ar/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/bg/admin/admin.json b/public/language/bg/admin/admin.json index 879e8122b7..da89fda2ef 100644 --- a/public/language/bg/admin/admin.json +++ b/public/language/bg/admin/admin.json @@ -13,5 +13,6 @@ "max": "Макс.:", "view": "Преглед", "edit": "Редактиране", - "add": "Добавяне" + "add": "Добавяне", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/bg/admin/manage/categories.json b/public/language/bg/admin/manage/categories.json index 1afecd591e..034169a831 100644 --- a/public/language/bg/admin/manage/categories.json +++ b/public/language/bg/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Списък от разрешени етикети", "upload-image": "Качване на изображение", "upload": "Качване", - "select-icon": "Изберете иконка", "delete-image": "Премахване", "category-image": "Изображение на категорията", "image-and-icon": "Изображение и иконка", diff --git a/public/language/bn/admin/admin.json b/public/language/bn/admin/admin.json index 478ef4c161..ce847c502d 100644 --- a/public/language/bn/admin/admin.json +++ b/public/language/bn/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/bn/admin/manage/categories.json b/public/language/bn/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/bn/admin/manage/categories.json +++ b/public/language/bn/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/cs/admin/admin.json b/public/language/cs/admin/admin.json index 79e58e40de..5fb62a418b 100644 --- a/public/language/cs/admin/admin.json +++ b/public/language/cs/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/cs/admin/manage/categories.json b/public/language/cs/admin/manage/categories.json index 89271ab6c2..4fa89573c0 100644 --- a/public/language/cs/admin/manage/categories.json +++ b/public/language/cs/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Seznam povolených značek", "upload-image": "Nahrát obrázek", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Vyjmout", "category-image": "Obrázek kategorie", "image-and-icon": "Image & Icon", diff --git a/public/language/da/admin/admin.json b/public/language/da/admin/admin.json index 3e78aa21f9..027ab1edae 100644 --- a/public/language/da/admin/admin.json +++ b/public/language/da/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/da/admin/manage/categories.json b/public/language/da/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/da/admin/manage/categories.json +++ b/public/language/da/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/de/admin/admin.json b/public/language/de/admin/admin.json index 4e782d8d2e..d4211ebc5f 100644 --- a/public/language/de/admin/admin.json +++ b/public/language/de/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "Anzeigen", "edit": "Bearbeiten", - "add": "Hinzufügen" + "add": "Hinzufügen", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/de/admin/manage/categories.json b/public/language/de/admin/manage/categories.json index 21d36ae17a..d914363786 100644 --- a/public/language/de/admin/manage/categories.json +++ b/public/language/de/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Bild hochladen", "upload": "Hochladen", - "select-icon": "Icon auswählen", "delete-image": "Entfernen", "category-image": "Kategoriebild", "image-and-icon": "Bild & Icon", diff --git a/public/language/el/admin/admin.json b/public/language/el/admin/admin.json index b8a34c75d1..8a79e434f6 100644 --- a/public/language/el/admin/admin.json +++ b/public/language/el/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/el/admin/manage/categories.json b/public/language/el/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/el/admin/manage/categories.json +++ b/public/language/el/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/en-US/admin/admin.json b/public/language/en-US/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/en-US/admin/admin.json +++ b/public/language/en-US/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/en-US/admin/manage/categories.json b/public/language/en-US/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/en-US/admin/manage/categories.json +++ b/public/language/en-US/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/en-x-pirate/admin/admin.json b/public/language/en-x-pirate/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/en-x-pirate/admin/admin.json +++ b/public/language/en-x-pirate/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/en-x-pirate/admin/manage/categories.json b/public/language/en-x-pirate/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/en-x-pirate/admin/manage/categories.json +++ b/public/language/en-x-pirate/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/es/admin/admin.json b/public/language/es/admin/admin.json index de08b28fc1..458e023a41 100644 --- a/public/language/es/admin/admin.json +++ b/public/language/es/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/es/admin/manage/categories.json b/public/language/es/admin/manage/categories.json index 94bc8ff37d..4ca9a9d5d8 100644 --- a/public/language/es/admin/manage/categories.json +++ b/public/language/es/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Etiquetas permitidas", "upload-image": "Subir Imagen", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Eliminar", "category-image": "Imagen de Categoría", "image-and-icon": "Image & Icon", diff --git a/public/language/et/admin/admin.json b/public/language/et/admin/admin.json index 1bb9683b85..1e904fd12e 100644 --- a/public/language/et/admin/admin.json +++ b/public/language/et/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/et/admin/manage/categories.json b/public/language/et/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/et/admin/manage/categories.json +++ b/public/language/et/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/fa-IR/admin/admin.json b/public/language/fa-IR/admin/admin.json index 38b347366b..34435717b6 100644 --- a/public/language/fa-IR/admin/admin.json +++ b/public/language/fa-IR/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/fa-IR/admin/manage/categories.json b/public/language/fa-IR/admin/manage/categories.json index c940769f68..4f21de69fe 100644 --- a/public/language/fa-IR/admin/manage/categories.json +++ b/public/language/fa-IR/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/fi/admin/admin.json b/public/language/fi/admin/admin.json index 7b26ca982e..211d49e84c 100644 --- a/public/language/fi/admin/admin.json +++ b/public/language/fi/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/fi/admin/manage/categories.json b/public/language/fi/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/fi/admin/manage/categories.json +++ b/public/language/fi/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/fr/admin/admin.json b/public/language/fr/admin/admin.json index 384e64f55f..4b5c2f385e 100644 --- a/public/language/fr/admin/admin.json +++ b/public/language/fr/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "Voir", "edit": "Éditer ", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/fr/admin/manage/categories.json b/public/language/fr/admin/manage/categories.json index 3340bf8fb1..0f75ab999b 100644 --- a/public/language/fr/admin/manage/categories.json +++ b/public/language/fr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Liste blanche de mots clés", "upload-image": "Envoyer une image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Enlever", "category-image": "Image de la catégorie", "image-and-icon": "Image & Icon", diff --git a/public/language/gl/admin/admin.json b/public/language/gl/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/gl/admin/admin.json +++ b/public/language/gl/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/gl/admin/manage/categories.json b/public/language/gl/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/gl/admin/manage/categories.json +++ b/public/language/gl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/he/admin/admin.json b/public/language/he/admin/admin.json index 7e52ea0d9e..05c6ac70fb 100644 --- a/public/language/he/admin/admin.json +++ b/public/language/he/admin/admin.json @@ -13,5 +13,6 @@ "max": "מקסימום:", "view": "צפייה", "edit": "עריכה", - "add": "הוספה" + "add": "הוספה", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/he/admin/manage/categories.json b/public/language/he/admin/manage/categories.json index d96db4e2ba..8018e022b1 100644 --- a/public/language/he/admin/manage/categories.json +++ b/public/language/he/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "רשימה לבנה של תגיות", "upload-image": "העלה תמונה", "upload": "העלאה", - "select-icon": "בחר סמל", "delete-image": "הסרה", "category-image": "תמונת קטגוריה", "image-and-icon": "תמונה וסמל", diff --git a/public/language/hr/admin/admin.json b/public/language/hr/admin/admin.json index a7c0ff924a..4de39987a2 100644 --- a/public/language/hr/admin/admin.json +++ b/public/language/hr/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/hr/admin/manage/categories.json b/public/language/hr/admin/manage/categories.json index 3f425ed857..15147d3389 100644 --- a/public/language/hr/admin/manage/categories.json +++ b/public/language/hr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Učitaj sliku", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Ukloni", "category-image": "Slika kategorije", "image-and-icon": "Image & Icon", diff --git a/public/language/hu/admin/admin.json b/public/language/hu/admin/admin.json index c7b0c876a1..8248580557 100644 --- a/public/language/hu/admin/admin.json +++ b/public/language/hu/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/hu/admin/manage/categories.json b/public/language/hu/admin/manage/categories.json index 7cec893e3f..daa6007ca8 100644 --- a/public/language/hu/admin/manage/categories.json +++ b/public/language/hu/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Engedélyezett címkék", "upload-image": "Kép feltöltése", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Kép törlése", "category-image": "Kategóriakép", "image-and-icon": "Image & Icon", diff --git a/public/language/hy/admin/admin.json b/public/language/hy/admin/admin.json index 6ae4598925..3f7a51e4c6 100644 --- a/public/language/hy/admin/admin.json +++ b/public/language/hy/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/hy/admin/manage/categories.json b/public/language/hy/admin/manage/categories.json index af1fb7d6a4..bbe31b7116 100644 --- a/public/language/hy/admin/manage/categories.json +++ b/public/language/hy/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Նշեք Whitelist", "upload-image": "Վերբեռնել նկար", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Հեռացնել ", "category-image": "Կատեգորիայի նկար ", "image-and-icon": "Image & Icon", diff --git a/public/language/id/admin/admin.json b/public/language/id/admin/admin.json index 2b282dba78..2470022bd9 100644 --- a/public/language/id/admin/admin.json +++ b/public/language/id/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/id/admin/manage/categories.json b/public/language/id/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/id/admin/manage/categories.json +++ b/public/language/id/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/it/admin/admin.json b/public/language/it/admin/admin.json index b5c0225c03..2d888feb85 100644 --- a/public/language/it/admin/admin.json +++ b/public/language/it/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "Visualizza", "edit": "Modifica", - "add": "Aggiungi" + "add": "Aggiungi", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/it/admin/manage/categories.json b/public/language/it/admin/manage/categories.json index 8c0f4d0347..a9a830ae2e 100644 --- a/public/language/it/admin/manage/categories.json +++ b/public/language/it/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Whitelist tag", "upload-image": "Caricamento Immagine", "upload": "Carica", - "select-icon": "Seleziona icona", "delete-image": "Rimuove", "category-image": "Immagine di Categoria", "image-and-icon": "Immagine e icona", diff --git a/public/language/ja/admin/admin.json b/public/language/ja/admin/admin.json index 2471f5c3d7..e3a5942b3e 100644 --- a/public/language/ja/admin/admin.json +++ b/public/language/ja/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ja/admin/manage/categories.json b/public/language/ja/admin/manage/categories.json index 9a51f63699..df4e0299d0 100644 --- a/public/language/ja/admin/manage/categories.json +++ b/public/language/ja/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "画像をアップロード", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "削除", "category-image": "カテゴリ画像", "image-and-icon": "Image & Icon", diff --git a/public/language/ko/admin/admin.json b/public/language/ko/admin/admin.json index 5257763f6a..86e5585c62 100644 --- a/public/language/ko/admin/admin.json +++ b/public/language/ko/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ko/admin/manage/categories.json b/public/language/ko/admin/manage/categories.json index abb4733ec9..e450251e09 100644 --- a/public/language/ko/admin/manage/categories.json +++ b/public/language/ko/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "태그 화이트리스트", "upload-image": "이미지 업로드", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "제거", "category-image": "카테고리 이미지", "image-and-icon": "Image & Icon", diff --git a/public/language/lt/admin/admin.json b/public/language/lt/admin/admin.json index fadce9096b..5aeca68b5e 100644 --- a/public/language/lt/admin/admin.json +++ b/public/language/lt/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/lt/admin/manage/categories.json b/public/language/lt/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/lt/admin/manage/categories.json +++ b/public/language/lt/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/lv/admin/admin.json b/public/language/lv/admin/admin.json index f53a0043f6..2d243e3944 100644 --- a/public/language/lv/admin/admin.json +++ b/public/language/lv/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/lv/admin/manage/categories.json b/public/language/lv/admin/manage/categories.json index 2318d20066..f9f49b5aad 100644 --- a/public/language/lv/admin/manage/categories.json +++ b/public/language/lv/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Augšupielādēt bildi", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Noņemt", "category-image": "Kategorijas bilde", "image-and-icon": "Image & Icon", diff --git a/public/language/ms/admin/admin.json b/public/language/ms/admin/admin.json index 4e723fdf3f..aee71766f0 100644 --- a/public/language/ms/admin/admin.json +++ b/public/language/ms/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ms/admin/manage/categories.json b/public/language/ms/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/ms/admin/manage/categories.json +++ b/public/language/ms/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/nb/admin/admin.json b/public/language/nb/admin/admin.json index dbdee3d930..df7e3493a5 100644 --- a/public/language/nb/admin/admin.json +++ b/public/language/nb/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/nb/admin/manage/categories.json b/public/language/nb/admin/manage/categories.json index 0b33bd8602..98339a3cc5 100644 --- a/public/language/nb/admin/manage/categories.json +++ b/public/language/nb/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/nl/admin/admin.json b/public/language/nl/admin/admin.json index 3d2e0b799d..2f206bce67 100644 --- a/public/language/nl/admin/admin.json +++ b/public/language/nl/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/nl/admin/manage/categories.json b/public/language/nl/admin/manage/categories.json index 1a786831b4..0ef47bcb70 100644 --- a/public/language/nl/admin/manage/categories.json +++ b/public/language/nl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/pl/admin/admin.json b/public/language/pl/admin/admin.json index 36e9d0f559..3611b28fba 100644 --- a/public/language/pl/admin/admin.json +++ b/public/language/pl/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/pl/admin/manage/categories.json b/public/language/pl/admin/manage/categories.json index 81f50eed3e..e45b15347d 100644 --- a/public/language/pl/admin/manage/categories.json +++ b/public/language/pl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Otaguj białą listę", "upload-image": "Prześlij obrazek", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Usuń", "category-image": "Obrazek kategorii", "image-and-icon": "Image & Icon", diff --git a/public/language/pt-BR/admin/admin.json b/public/language/pt-BR/admin/admin.json index df71a99aac..313e12bbe3 100644 --- a/public/language/pt-BR/admin/admin.json +++ b/public/language/pt-BR/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/pt-BR/admin/manage/categories.json b/public/language/pt-BR/admin/manage/categories.json index 9ff41af7ed..a222c6f033 100644 --- a/public/language/pt-BR/admin/manage/categories.json +++ b/public/language/pt-BR/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Lista Branca de Tags", "upload-image": "Enviar Imagem", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remover", "category-image": "Imagem da Categoria", "image-and-icon": "Image & Icon", diff --git a/public/language/pt-PT/admin/admin.json b/public/language/pt-PT/admin/admin.json index 0e8ac0ff26..8307aaa28f 100644 --- a/public/language/pt-PT/admin/admin.json +++ b/public/language/pt-PT/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/pt-PT/admin/manage/categories.json b/public/language/pt-PT/admin/manage/categories.json index b12490364c..c076c33851 100644 --- a/public/language/pt-PT/admin/manage/categories.json +++ b/public/language/pt-PT/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Enviar Imagem", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remover", "category-image": "Imagem da Categoria", "image-and-icon": "Image & Icon", diff --git a/public/language/ro/admin/admin.json b/public/language/ro/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/ro/admin/admin.json +++ b/public/language/ro/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ro/admin/manage/categories.json b/public/language/ro/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/ro/admin/manage/categories.json +++ b/public/language/ro/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/ru/admin/admin.json b/public/language/ru/admin/admin.json index b7e7e6d8a1..f6fae1cf93 100644 --- a/public/language/ru/admin/admin.json +++ b/public/language/ru/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/ru/admin/manage/categories.json b/public/language/ru/admin/manage/categories.json index 02bada0fc5..49ae61f61e 100644 --- a/public/language/ru/admin/manage/categories.json +++ b/public/language/ru/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Разрешенный список меток", "upload-image": "Загрузить изображение", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Удалить", "category-image": "Изображение категории", "image-and-icon": "Image & Icon", diff --git a/public/language/rw/admin/admin.json b/public/language/rw/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/rw/admin/admin.json +++ b/public/language/rw/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/rw/admin/manage/categories.json b/public/language/rw/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/rw/admin/manage/categories.json +++ b/public/language/rw/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sc/admin/admin.json b/public/language/sc/admin/admin.json index 48994c38a7..96c58b1733 100644 --- a/public/language/sc/admin/admin.json +++ b/public/language/sc/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sc/admin/manage/categories.json b/public/language/sc/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sc/admin/manage/categories.json +++ b/public/language/sc/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sk/admin/admin.json b/public/language/sk/admin/admin.json index aae9f76473..46a378cdb6 100644 --- a/public/language/sk/admin/admin.json +++ b/public/language/sk/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sk/admin/manage/categories.json b/public/language/sk/admin/manage/categories.json index b78a199d98..9dc3cc8829 100644 --- a/public/language/sk/admin/manage/categories.json +++ b/public/language/sk/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Nahrať obrázok", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Odobrať", "category-image": "Obrázok kategórie", "image-and-icon": "Image & Icon", diff --git a/public/language/sl/admin/admin.json b/public/language/sl/admin/admin.json index 4c0114649f..9c98de272f 100644 --- a/public/language/sl/admin/admin.json +++ b/public/language/sl/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sl/admin/manage/categories.json b/public/language/sl/admin/manage/categories.json index d2c96483be..c6da77d39b 100644 --- a/public/language/sl/admin/manage/categories.json +++ b/public/language/sl/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Bela lista oznak", "upload-image": "Naloži sliko", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Odstrani", "category-image": "Slika kategorije", "image-and-icon": "Image & Icon", diff --git a/public/language/sq-AL/admin/admin.json b/public/language/sq-AL/admin/admin.json index 1e850fb816..299d08b5b9 100644 --- a/public/language/sq-AL/admin/admin.json +++ b/public/language/sq-AL/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sq-AL/admin/manage/categories.json b/public/language/sq-AL/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sq-AL/admin/manage/categories.json +++ b/public/language/sq-AL/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sr/admin/admin.json b/public/language/sr/admin/admin.json index 74825d8eed..677c70c226 100644 --- a/public/language/sr/admin/admin.json +++ b/public/language/sr/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sr/admin/manage/categories.json b/public/language/sr/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sr/admin/manage/categories.json +++ b/public/language/sr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/sv/admin/admin.json b/public/language/sv/admin/admin.json index 43aa5d4980..5163abb1c8 100644 --- a/public/language/sv/admin/admin.json +++ b/public/language/sv/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/sv/admin/manage/categories.json b/public/language/sv/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/sv/admin/manage/categories.json +++ b/public/language/sv/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/th/admin/admin.json b/public/language/th/admin/admin.json index c87a6b322f..ee88fab2c3 100644 --- a/public/language/th/admin/admin.json +++ b/public/language/th/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/th/admin/manage/categories.json b/public/language/th/admin/manage/categories.json index 0cfb251c56..8a9ff471b0 100644 --- a/public/language/th/admin/manage/categories.json +++ b/public/language/th/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", "image-and-icon": "Image & Icon", diff --git a/public/language/tr/admin/admin.json b/public/language/tr/admin/admin.json index a3f790684f..d0fd44bb6f 100644 --- a/public/language/tr/admin/admin.json +++ b/public/language/tr/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/tr/admin/manage/categories.json b/public/language/tr/admin/manage/categories.json index 82137392ff..f79f1fc55a 100644 --- a/public/language/tr/admin/manage/categories.json +++ b/public/language/tr/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "İzin Verilen Etiketler", "upload-image": "Görsel Yükle", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Sil", "category-image": "Kategori Görseli", "image-and-icon": "Image & Icon", diff --git a/public/language/uk/admin/admin.json b/public/language/uk/admin/admin.json index 89890b5032..54ce5f0e3c 100644 --- a/public/language/uk/admin/admin.json +++ b/public/language/uk/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/uk/admin/manage/categories.json b/public/language/uk/admin/manage/categories.json index ccff2556f3..ffec24d057 100644 --- a/public/language/uk/admin/manage/categories.json +++ b/public/language/uk/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "Завантажити зображення", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Видалити", "category-image": "Зображення категорії", "image-and-icon": "Image & Icon", diff --git a/public/language/vi/admin/admin.json b/public/language/vi/admin/admin.json index c9fe017767..16dd9e8839 100644 --- a/public/language/vi/admin/admin.json +++ b/public/language/vi/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/vi/admin/manage/categories.json b/public/language/vi/admin/manage/categories.json index c47a4feebd..b4d06d17fa 100644 --- a/public/language/vi/admin/manage/categories.json +++ b/public/language/vi/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Danh Sách Trắng Gắn Thẻ ", "upload-image": "Tải Lên Ảnh", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "Xóa", "category-image": "Ảnh Chuyên Mục", "image-and-icon": "Image & Icon", diff --git a/public/language/zh-CN/admin/admin.json b/public/language/zh-CN/admin/admin.json index 4f722f7144..218a77c3b5 100644 --- a/public/language/zh-CN/admin/admin.json +++ b/public/language/zh-CN/admin/admin.json @@ -13,5 +13,6 @@ "max": "最大:", "view": "浏览", "edit": "编辑", - "add": "添加" + "add": "添加", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/zh-CN/admin/manage/categories.json b/public/language/zh-CN/admin/manage/categories.json index 2d51d702c9..301bc332ca 100644 --- a/public/language/zh-CN/admin/manage/categories.json +++ b/public/language/zh-CN/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "标签白名单", "upload-image": "上传图片", "upload": "上传", - "select-icon": "选择图标", "delete-image": "移除", "category-image": "版块图片", "image-and-icon": "图片和图标", diff --git a/public/language/zh-TW/admin/admin.json b/public/language/zh-TW/admin/admin.json index e8a033114f..2885f18659 100644 --- a/public/language/zh-TW/admin/admin.json +++ b/public/language/zh-TW/admin/admin.json @@ -13,5 +13,6 @@ "max": "Max:", "view": "View", "edit": "Edit", - "add": "Add" + "add": "Add", + "select-icon": "Select Icon" } \ No newline at end of file diff --git a/public/language/zh-TW/admin/manage/categories.json b/public/language/zh-TW/admin/manage/categories.json index 5172bf8f69..b1b4d88422 100644 --- a/public/language/zh-TW/admin/manage/categories.json +++ b/public/language/zh-TW/admin/manage/categories.json @@ -20,7 +20,6 @@ "tag-whitelist": "Tag Whitelist", "upload-image": "上傳圖片", "upload": "Upload", - "select-icon": "Select Icon", "delete-image": "移除", "category-image": "版面圖片", "image-and-icon": "Image & Icon", From 4ca71f63548c5efe470bf5dcdd371a29d4bfcf3e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 31 Jul 2023 17:45:38 -0400 Subject: [PATCH 192/300] fix: #11855, remove superfluous password challenge on admin email update (unless they're updating their own) --- src/user/interstitials.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/user/interstitials.js b/src/user/interstitials.js index cbb82ba9f7..fbdb63f9ab 100644 --- a/src/user/interstitials.js +++ b/src/user/interstitials.js @@ -28,8 +28,8 @@ Interstitials.email = async (data) => { return data; } - const [isAdminOrGlobalMod, hasPassword, hasPending] = await Promise.all([ - user.isAdminOrGlobalMod(data.req.uid), + const [canManageUsers, hasPassword, hasPending] = await Promise.all([ + privileges.admin.can('admin:users', data.req.uid), user.hasPassword(data.userData.uid), user.email.isValidationPending(data.userData.uid), ]); @@ -44,7 +44,12 @@ Interstitials.email = async (data) => { data: { email, requireEmailAddress: meta.config.requireEmailAddress, - issuePasswordChallenge: !!data.userData.uid && hasPassword, + issuePasswordChallenge: + hasPassword && + ( + (canManageUsers && data.userData.uid === data.req.uid) || // admin changing own email + (!canManageUsers && !!data.userData.uid) // non-admins changing own email + ), hasPending, }, callback: async (userData, formData) => { @@ -68,7 +73,7 @@ Interstitials.email = async (data) => { }), ]); - if (!isAdminOrGlobalMod && !isPasswordCorrect) { + if (!canManageUsers && !isPasswordCorrect) { await sleep(2000); } @@ -87,7 +92,7 @@ Interstitials.email = async (data) => { } // Admins editing will auto-confirm, unless editing their own email - if (isAdminOrGlobalMod && userData.uid !== data.req.uid) { + if (canManageUsers && userData.uid !== data.req.uid) { if (!await user.email.available(formData.email)) { throw new Error('[[error:email-taken]]'); } @@ -115,7 +120,7 @@ Interstitials.email = async (data) => { throw new Error('[[error:invalid-email]]'); } - if (current.length && (!hasPassword || (hasPassword && isPasswordCorrect) || isAdminOrGlobalMod)) { + if (current.length && (!hasPassword || (hasPassword && isPasswordCorrect) || canManageUsers)) { // User or admin explicitly clearing their email await user.email.remove(userData.uid, isSelf ? data.req.session.id : null); } From 00e680b942e5f70cb2073920a04ec6a5d1e05671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 31 Jul 2023 18:17:51 -0400 Subject: [PATCH 193/300] expose getEventsByEventIds and fix stop = -1 --- src/events.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/events.js b/src/events.js index 53f1e160ac..7329aa486e 100644 --- a/src/events.js +++ b/src/events.js @@ -107,7 +107,11 @@ events.getEvents = async function (filter, start, stop, from, to) { to = '+inf'; } - const eids = await db.getSortedSetRevRangeByScore(`events:time${filter ? `:${filter}` : ''}`, start, stop - start + 1, to, from); + const eids = await db.getSortedSetRevRangeByScore(`events:time${filter ? `:${filter}` : ''}`, start, stop === -1 ? -1 : stop - start + 1, to, from); + return await events.getEventsByEventIds(eids); +}; + +events.getEventsByEventIds = async (eids) => { let eventsData = await db.getObjects(eids.map(eid => `event:${eid}`)); eventsData = eventsData.filter(Boolean); await addUserData(eventsData, 'uid', 'user'); From f7ee3d9c1ea42deebb48510f77d91037797dd0fc Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 1 Aug 2023 09:18:43 +0000 Subject: [PATCH 194/300] Latest translations and fallbacks --- public/language/bg/admin/admin.json | 2 +- public/language/it/admin/admin.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/language/bg/admin/admin.json b/public/language/bg/admin/admin.json index da89fda2ef..01ae9b511d 100644 --- a/public/language/bg/admin/admin.json +++ b/public/language/bg/admin/admin.json @@ -14,5 +14,5 @@ "view": "Преглед", "edit": "Редактиране", "add": "Добавяне", - "select-icon": "Select Icon" + "select-icon": "Изберете иконка" } \ No newline at end of file diff --git a/public/language/it/admin/admin.json b/public/language/it/admin/admin.json index 2d888feb85..fdff713a70 100644 --- a/public/language/it/admin/admin.json +++ b/public/language/it/admin/admin.json @@ -14,5 +14,5 @@ "view": "Visualizza", "edit": "Modifica", "add": "Aggiungi", - "select-icon": "Select Icon" + "select-icon": "Seleziona icona" } \ No newline at end of file From 82562bec444940608052f3e4149e0c61ec80bf3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Aug 2023 11:25:37 -0400 Subject: [PATCH 195/300] fix: fix escaped characters in tooltips, fix priv checks in tooltips closes #11862, closes #11857 --- public/src/client/topic/votes.js | 3 ++- src/socket.io/posts/votes.js | 46 +++++++++++++++++++++++++------- test/posts.js | 8 ++++++ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/public/src/client/topic/votes.js b/public/src/client/topic/votes.js index 6f4c624492..7a5920742b 100644 --- a/public/src/client/topic/votes.js +++ b/public/src/client/topic/votes.js @@ -50,6 +50,7 @@ define('forum/topic/votes', [ el.attr('title', title); (new bootstrap.Tooltip(el, { container: '#content', + html: true, })).show(); } let usernames = data.usernames @@ -57,7 +58,7 @@ define('forum/topic/votes', [ if (!usernames.length) { return; } - if (usernames.length + data.otherCount > 6) { + if (usernames.length + data.otherCount > data.cutoff) { usernames = usernames.join(', ').replace(/,/g, '|'); translator.translate('[[topic:users_and_others, ' + usernames + ', ' + data.otherCount + ']]', function (translated) { translated = translated.replace(/\|/g, ','); diff --git a/src/socket.io/posts/votes.js b/src/socket.io/posts/votes.js index 0ecd8196ef..4c971efd82 100644 --- a/src/socket.io/posts/votes.js +++ b/src/socket.io/posts/votes.js @@ -1,5 +1,7 @@ 'use strict'; +const _ = require('lodash'); + const db = require('../../database'); const user = require('../../user'); const posts = require('../../posts'); @@ -39,23 +41,47 @@ module.exports = function (SocketPosts) { if (!Array.isArray(pids)) { throw new Error('[[error:invalid-data]]'); } - const data = await posts.getUpvotedUidsByPids(pids); + + const [cids, data, isAdmin] = await Promise.all([ + posts.getCidsByPids(pids), + posts.getUpvotedUidsByPids(pids), + privileges.users.isAdministrator(socket.uid), + ]); + + if (!isAdmin) { + const isAllowed = await privileges.categories.isUserAllowedTo( + 'topics:read', _.uniq(cids), socket.uid + ); + if (isAllowed.includes(false)) { + throw new Error('[[error:no-privileges]]'); + } + } + if (!data.length) { return []; } - - const result = await Promise.all(data.map(async (uids) => { + const cutoff = 6; + const sliced = data.map((uids) => { let otherCount = 0; - if (uids.length > 6) { - otherCount = uids.length - 5; - uids = uids.slice(0, 5); + if (uids.length > cutoff) { + otherCount = uids.length - (cutoff - 1); + uids = uids.slice(0, cutoff - 1); } - const usernames = await user.getUsernamesByUids(uids); return { - otherCount: otherCount, - usernames: usernames, + otherCount, + uids, }; - })); + }); + + const uniqUids = _.uniq(_.flatten(sliced.map(d => d.uids))); + const usernameMap = _.zipObject(uniqUids, await user.getUsernamesByUids(uniqUids)); + const result = sliced.map( + data => ({ + otherCount: data.otherCount, + cutoff: cutoff, + usernames: data.uids.map(uid => usernameMap[uid]), + }) + ); return result; }; }; diff --git a/test/posts.js b/test/posts.js index ef4069ec81..8b3cc947e2 100644 --- a/test/posts.js +++ b/test/posts.js @@ -216,6 +216,14 @@ describe('Post\'s', () => { }); }); + it('should fail to get upvoters if user does not have read privilege', async () => { + await privileges.categories.rescind(['groups:topics:read'], cid, 'guests'); + await assert.rejects(socketPosts.getUpvoters({ uid: 0 }, [postData.pid]), { + message: '[[error:no-privileges]]', + }); + await privileges.categories.give(['groups:topics:read'], cid, 'guests'); + }); + it('should unvote a post', async () => { const result = await apiPosts.unvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }); assert.equal(result.post.upvotes, 0); From da8521393b83a24f40ee1ac53b468a399f2cf995 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:35:51 -0400 Subject: [PATCH 196/300] fix(deps): update dependency sass to v1.64.2 (#11861) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index c237da149f..3bcdc40367 100644 --- a/install/package.json +++ b/install/package.json @@ -125,7 +125,7 @@ "rss": "1.2.2", "rtlcss": "4.1.0", "sanitize-html": "2.11.0", - "sass": "1.64.1", + "sass": "1.64.2", "semver": "7.5.4", "serve-favicon": "2.5.0", "sharp": "0.32.4", From c79c1e5fa91160b66b8c9641b0a0d624839fd222 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:35:59 -0400 Subject: [PATCH 197/300] fix(deps): update dependency pg-cursor to v2.10.2 (#11860) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 3bcdc40367..dac9f3313b 100644 --- a/install/package.json +++ b/install/package.json @@ -113,7 +113,7 @@ "passport-http-bearer": "1.0.1", "passport-local": "1.0.0", "pg": "8.11.1", - "pg-cursor": "2.10.1", + "pg-cursor": "2.10.2", "postcss": "8.4.27", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", From c9c23513132d2b60f7d1077922d16296bc9b5a78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:36:13 -0400 Subject: [PATCH 198/300] chore(deps): update dependency sass-embedded to v1.64.2 (#11858) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index dac9f3313b..bba509a540 100644 --- a/install/package.json +++ b/install/package.json @@ -172,7 +172,7 @@ "smtp-server": "3.12.0" }, "optionalDependencies": { - "sass-embedded": "1.64.1" + "sass-embedded": "1.64.2" }, "resolutions": { "*/jquery": "3.7.0" From 5582fe923cb1d2ffea26c9101389b41a74ea2602 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:59:28 -0400 Subject: [PATCH 199/300] fix(deps): update dependency pg to v8.11.2 (#11859) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index bba509a540..56b18fc01a 100644 --- a/install/package.json +++ b/install/package.json @@ -112,7 +112,7 @@ "passport": "0.6.0", "passport-http-bearer": "1.0.1", "passport-local": "1.0.0", - "pg": "8.11.1", + "pg": "8.11.2", "pg-cursor": "2.10.2", "postcss": "8.4.27", "postcss-clean": "1.2.0", From b5a8941a51fc356fba84a5df9d7542510fab4169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Aug 2023 14:31:15 -0400 Subject: [PATCH 200/300] get rid of less, slideout --- install/package.json | 2 -- src/meta/aliases.js | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/install/package.json b/install/package.json index 56b18fc01a..5ceafdbef2 100644 --- a/install/package.json +++ b/install/package.json @@ -81,7 +81,6 @@ "jsesc": "3.0.2", "json2csv": "5.0.7", "jsonwebtoken": "9.0.1", - "less": "4.1.3", "lodash": "4.17.21", "logrotate-stream": "0.2.9", "lru-cache": "10.0.0", @@ -130,7 +129,6 @@ "serve-favicon": "2.5.0", "sharp": "0.32.4", "sitemap": "7.1.1", - "slideout": "1.0.1", "socket.io": "4.7.1", "socket.io-client": "4.7.1", "@socket.io/redis-adapter": "8.2.1", diff --git a/src/meta/aliases.js b/src/meta/aliases.js index d5eb42aa89..068080ed72 100644 --- a/src/meta/aliases.js +++ b/src/meta/aliases.js @@ -13,9 +13,9 @@ const aliases = { 'clientcss', 'clientscss', 'clientstyles', 'clientstyle', ], 'admin control panel styles': [ - 'admincss', 'adminless', 'adminstyles', 'adminstyle', 'acpcss', 'acpless', 'acpstyles', 'acpstyle', + 'admincss', 'adminscss', 'adminstyles', 'adminstyle', 'acpcss', 'acpscss', 'acpstyles', 'acpstyle', ], - styles: ['css', 'less', 'style'], + styles: ['css', 'scss', 'style'], templates: ['tpl'], languages: ['lang', 'i18n'], }; From f4e2e6176e4dddbd57efe6fa8248b65c0357f273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Aug 2023 21:19:19 -0400 Subject: [PATCH 201/300] fix: chat mark read regression --- public/src/modules/chat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index d1b5a8ecd6..33b3e9a16a 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -154,11 +154,11 @@ define('chat', [ alerts.error(err); // Revert on failure - module.markChatElUnread($(chatEl), !(state === 1)); + module.markChatElUnread($(chatEl), !state); }); // Immediate feedback - module.markChatElUnread($(chatEl), state === 1); + module.markChatElUnread($(chatEl), state); }; module.isFromBlockedUser = function (fromUid) { From b688b6d4f20dff90b097c0926f7ae8cf3cbc163b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Aug 2023 22:04:45 -0400 Subject: [PATCH 202/300] bs5.3 updates (#11667) * bs5.3 updates * bootstrap 5.3.1 * chore: up bootswatch * chore: up deps --- install/package.json | 8 ++++---- src/meta/css.js | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/install/package.json b/install/package.json index 5ceafdbef2..8295a0ef95 100644 --- a/install/package.json +++ b/install/package.json @@ -42,8 +42,8 @@ "benchpressjs": "2.5.1", "body-parser": "1.20.2", "bootbox": "6.0.0", - "bootstrap": "5.2.3", - "bootswatch": "5.2.3", + "bootstrap": "5.3.1", + "bootswatch": "5.3.1", "chalk": "4.1.2", "chart.js": "2.9.4", "cli-graph": "3.2.2", @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.1.3", - "nodebb-plugin-composer-default": "10.2.6", + "nodebb-plugin-composer-default": "10.2.7", "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.20", + "nodebb-theme-harmony": "1.1.21", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.6", "nodebb-theme-persona": "13.2.11", diff --git a/src/meta/css.js b/src/meta/css.js index d9edcdf360..490ac8c215 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -75,6 +75,7 @@ function boostrapImport(themeData) { // bs files '@import "bootstrap/scss/variables";', + '@import "bootstrap/scss/variables-dark";', '@import "bootstrap/scss/maps";', '@import "bootstrap/scss/mixins";', '@import "bootstrap/scss/utilities";', From 58968353ef910482a42af653e7ecb45c29d33c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Aug 2023 22:05:24 -0400 Subject: [PATCH 203/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 8295a0ef95..97e5341436 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.21", + "nodebb-theme-harmony": "1.1.22", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.6", "nodebb-theme-persona": "13.2.11", From 99c22942898cfa5ddafc5b47671cf8904a20facd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 11:40:12 -0400 Subject: [PATCH 204/300] feat: add flags link to acp manage menu, closes #11867 --- public/language/en-GB/admin/menu.json | 1 + src/views/admin/partials/navigation.tpl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/public/language/en-GB/admin/menu.json b/public/language/en-GB/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/en-GB/admin/menu.json +++ b/public/language/en-GB/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/src/views/admin/partials/navigation.tpl b/src/views/admin/partials/navigation.tpl index c73e8007af..8c89f6a702 100644 --- a/src/views/admin/partials/navigation.tpl +++ b/src/views/admin/partials/navigation.tpl @@ -53,6 +53,8 @@ [[admin/menu:manage/uploads]] [[admin/menu:manage/digest]]
    +
    [[pages:moderator-tools]]
    + [[admin/menu:manage/flagged-content]] [[admin/menu:manage/post-queue]] [[admin/menu:manage/ip-blacklist]] {{{ end }}} From ad9d8f7783afc883351a16b900ffe66cdaf2bdb7 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 2 Aug 2023 15:40:39 +0000 Subject: [PATCH 205/300] chore(i18n): fallback strings for new resources: nodebb.admin-menu --- public/language/ar/admin/menu.json | 1 + public/language/bg/admin/menu.json | 1 + public/language/bn/admin/menu.json | 1 + public/language/cs/admin/menu.json | 1 + public/language/da/admin/menu.json | 1 + public/language/de/admin/menu.json | 1 + public/language/el/admin/menu.json | 1 + public/language/en-US/admin/menu.json | 1 + public/language/en-x-pirate/admin/menu.json | 1 + public/language/es/admin/menu.json | 1 + public/language/et/admin/menu.json | 1 + public/language/fa-IR/admin/menu.json | 1 + public/language/fi/admin/menu.json | 1 + public/language/fr/admin/menu.json | 1 + public/language/gl/admin/menu.json | 1 + public/language/he/admin/menu.json | 1 + public/language/hr/admin/menu.json | 1 + public/language/hu/admin/menu.json | 1 + public/language/hy/admin/menu.json | 1 + public/language/id/admin/menu.json | 1 + public/language/it/admin/menu.json | 1 + public/language/ja/admin/menu.json | 1 + public/language/ko/admin/menu.json | 1 + public/language/lt/admin/menu.json | 1 + public/language/lv/admin/menu.json | 1 + public/language/ms/admin/menu.json | 1 + public/language/nb/admin/menu.json | 1 + public/language/nl/admin/menu.json | 1 + public/language/pl/admin/menu.json | 1 + public/language/pt-BR/admin/menu.json | 1 + public/language/pt-PT/admin/menu.json | 1 + public/language/ro/admin/menu.json | 1 + public/language/ru/admin/menu.json | 1 + public/language/rw/admin/menu.json | 1 + public/language/sc/admin/menu.json | 1 + public/language/sk/admin/menu.json | 1 + public/language/sl/admin/menu.json | 1 + public/language/sq-AL/admin/menu.json | 1 + public/language/sr/admin/menu.json | 1 + public/language/sv/admin/menu.json | 1 + public/language/th/admin/menu.json | 1 + public/language/tr/admin/menu.json | 1 + public/language/uk/admin/menu.json | 1 + public/language/vi/admin/menu.json | 1 + public/language/zh-CN/admin/menu.json | 1 + public/language/zh-TW/admin/menu.json | 1 + 46 files changed, 46 insertions(+) diff --git a/public/language/ar/admin/menu.json b/public/language/ar/admin/menu.json index 1b091099bf..845ad3fcbf 100644 --- a/public/language/ar/admin/menu.json +++ b/public/language/ar/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "الأعضاء", "manage/admins-mods": "Admins & Mods", "manage/registration": "قائمة انتظار التسجيل", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "قائمة انتظار المشاركة", "manage/groups": "المجموعات", "manage/ip-blacklist": "قائمة حظر عناوين IP", diff --git a/public/language/bg/admin/menu.json b/public/language/bg/admin/menu.json index f777ef8105..3c70840631 100644 --- a/public/language/bg/admin/menu.json +++ b/public/language/bg/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Потребители", "manage/admins-mods": "Администратори и модератори", "manage/registration": "Регистрационна опашка", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Опашка за публикации", "manage/groups": "Групи", "manage/ip-blacklist": "Черен списък за IP адреси", diff --git a/public/language/bn/admin/menu.json b/public/language/bn/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/bn/admin/menu.json +++ b/public/language/bn/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/cs/admin/menu.json b/public/language/cs/admin/menu.json index fe6b907b4f..d34e12f605 100644 --- a/public/language/cs/admin/menu.json +++ b/public/language/cs/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Uživatelé", "manage/admins-mods": "Správci a moderátoři", "manage/registration": "Registrační fronta", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Fronta příspěvků", "manage/groups": "Skupiny", "manage/ip-blacklist": "Černá listina IP", diff --git a/public/language/da/admin/menu.json b/public/language/da/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/da/admin/menu.json +++ b/public/language/da/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/de/admin/menu.json b/public/language/de/admin/menu.json index b8d3f76e5b..a36d520ff1 100644 --- a/public/language/de/admin/menu.json +++ b/public/language/de/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Benutzer", "manage/admins-mods": "Admins & Mods", "manage/registration": "Warteliste", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Beitragswarteschlange", "manage/groups": "Gruppen", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/el/admin/menu.json b/public/language/el/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/el/admin/menu.json +++ b/public/language/el/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/en-US/admin/menu.json b/public/language/en-US/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/en-US/admin/menu.json +++ b/public/language/en-US/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/en-x-pirate/admin/menu.json b/public/language/en-x-pirate/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/en-x-pirate/admin/menu.json +++ b/public/language/en-x-pirate/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/es/admin/menu.json b/public/language/es/admin/menu.json index d34611740a..597b17270d 100644 --- a/public/language/es/admin/menu.json +++ b/public/language/es/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Usuarios", "manage/admins-mods": "Administradores & Mods", "manage/registration": "Cola de Registro", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Cola de mensajes", "manage/groups": "Grupos", "manage/ip-blacklist": "Lista negra de IP", diff --git a/public/language/et/admin/menu.json b/public/language/et/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/et/admin/menu.json +++ b/public/language/et/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/fa-IR/admin/menu.json b/public/language/fa-IR/admin/menu.json index 575786e68e..722f482140 100644 --- a/public/language/fa-IR/admin/menu.json +++ b/public/language/fa-IR/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "کاربران", "manage/admins-mods": "Admins & Mods", "manage/registration": "صف ثبت نام", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/fi/admin/menu.json b/public/language/fi/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/fi/admin/menu.json +++ b/public/language/fi/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/fr/admin/menu.json b/public/language/fr/admin/menu.json index 9ba612ce00..2180c33ed5 100644 --- a/public/language/fr/admin/menu.json +++ b/public/language/fr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Utilisateurs", "manage/admins-mods": "Modération", "manage/registration": "File d'inscription", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "File d’attente des messages", "manage/groups": "Groupes", "manage/ip-blacklist": "Liste noire d'IPs", diff --git a/public/language/gl/admin/menu.json b/public/language/gl/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/gl/admin/menu.json +++ b/public/language/gl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json index 29be78b9ed..affb02c2e8 100644 --- a/public/language/he/admin/menu.json +++ b/public/language/he/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "משתמשים", "manage/admins-mods": "מנחים ומנהלים", "manage/registration": "תור הרשמה", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "תור פוסטים", "manage/groups": "קבוצות", "manage/ip-blacklist": "רשימה שחורה של כתובות IP", diff --git a/public/language/hr/admin/menu.json b/public/language/hr/admin/menu.json index d8f0bb0b8c..bb2dd87d03 100644 --- a/public/language/hr/admin/menu.json +++ b/public/language/hr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Korisnici", "manage/admins-mods": "Admins & Mods", "manage/registration": "Lista zahtjeva za registraciju", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Grupe", "manage/ip-blacklist": "IP blokade", diff --git a/public/language/hu/admin/menu.json b/public/language/hu/admin/menu.json index 2c6f0fd6b0..4c73bf711d 100644 --- a/public/language/hu/admin/menu.json +++ b/public/language/hu/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Felhasználók", "manage/admins-mods": "Adminok & Moderátorok", "manage/registration": "Regisztrációs várólista", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Hozzászólási várólista", "manage/groups": "Csoportok", "manage/ip-blacklist": "IP tiltólista", diff --git a/public/language/hy/admin/menu.json b/public/language/hy/admin/menu.json index e9eb8657d1..1b483105ee 100644 --- a/public/language/hy/admin/menu.json +++ b/public/language/hy/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Օգտատերեր", "manage/admins-mods": "Admins & Mods", "manage/registration": "Գրանցման հերթ", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Գրառման Queue", "manage/groups": "Խմբեր", "manage/ip-blacklist": "IP սև ցուցակ", diff --git a/public/language/id/admin/menu.json b/public/language/id/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/id/admin/menu.json +++ b/public/language/id/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/it/admin/menu.json b/public/language/it/admin/menu.json index 6cfa55b521..63f1def90a 100644 --- a/public/language/it/admin/menu.json +++ b/public/language/it/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Utenti", "manage/admins-mods": "Amministratori e Moderatori", "manage/registration": "Coda di registrazione", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Coda post", "manage/groups": "Gruppi", "manage/ip-blacklist": "Lista degli IP bloccati", diff --git a/public/language/ja/admin/menu.json b/public/language/ja/admin/menu.json index 09589fd6ae..ba2914892c 100644 --- a/public/language/ja/admin/menu.json +++ b/public/language/ja/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "ユーザー", "manage/admins-mods": "Admins & Mods", "manage/registration": "登録キュー", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "投稿キュー", "manage/groups": "グループ", "manage/ip-blacklist": "IPブラックリスト", diff --git a/public/language/ko/admin/menu.json b/public/language/ko/admin/menu.json index e2acae1c82..0814902509 100644 --- a/public/language/ko/admin/menu.json +++ b/public/language/ko/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "사용자", "manage/admins-mods": "관리자 & 조정자", "manage/registration": "가입 승인 대기열", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "게시 대기열", "manage/groups": "그룹", "manage/ip-blacklist": "IP 블랙리스트", diff --git a/public/language/lt/admin/menu.json b/public/language/lt/admin/menu.json index ad6fff59be..d3ae8a4504 100644 --- a/public/language/lt/admin/menu.json +++ b/public/language/lt/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/lv/admin/menu.json b/public/language/lv/admin/menu.json index 82b7f18a89..97544abc7d 100644 --- a/public/language/lv/admin/menu.json +++ b/public/language/lv/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Lietotāji", "manage/admins-mods": "Administratori & moderatori", "manage/registration": "Reģistrācijas rinda", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Rakstu apstiprināšanas rinda", "manage/groups": "Grupas", "manage/ip-blacklist": "IP adrešu melnais saraksts", diff --git a/public/language/ms/admin/menu.json b/public/language/ms/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/ms/admin/menu.json +++ b/public/language/ms/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/nb/admin/menu.json b/public/language/nb/admin/menu.json index 3719330a90..8d057028a4 100644 --- a/public/language/nb/admin/menu.json +++ b/public/language/nb/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Brukere", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Grupper", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/nl/admin/menu.json b/public/language/nl/admin/menu.json index 0b26226e19..ce63a54b14 100644 --- a/public/language/nl/admin/menu.json +++ b/public/language/nl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Gebruikers", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groepen", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/pl/admin/menu.json b/public/language/pl/admin/menu.json index 2e9bbc9cc6..bd5c68d512 100644 --- a/public/language/pl/admin/menu.json +++ b/public/language/pl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Użytkownicy", "manage/admins-mods": "Administratorzy i Moderatorzy", "manage/registration": "Kolejka rejestracji", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Kolejka postów", "manage/groups": "Grupy", "manage/ip-blacklist": "Czarna lista IP", diff --git a/public/language/pt-BR/admin/menu.json b/public/language/pt-BR/admin/menu.json index 809b30d447..d4e8408367 100644 --- a/public/language/pt-BR/admin/menu.json +++ b/public/language/pt-BR/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Usuários", "manage/admins-mods": "Admins & Mods", "manage/registration": "Fila de Registro", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Fila de Posts", "manage/groups": "Grupos", "manage/ip-blacklist": "Lista Negra de IPs", diff --git a/public/language/pt-PT/admin/menu.json b/public/language/pt-PT/admin/menu.json index 02aa33f416..06371dae8d 100644 --- a/public/language/pt-PT/admin/menu.json +++ b/public/language/pt-PT/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Utilizadores", "manage/admins-mods": "Administradores e Moderadores", "manage/registration": "Registos por Aprovar", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Publicações por Aprovar", "manage/groups": "Grupos", "manage/ip-blacklist": "Lista Negra de IPs", diff --git a/public/language/ro/admin/menu.json b/public/language/ro/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/ro/admin/menu.json +++ b/public/language/ro/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/ru/admin/menu.json b/public/language/ru/admin/menu.json index 86b57b11d9..0c10ad9f1a 100644 --- a/public/language/ru/admin/menu.json +++ b/public/language/ru/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Пользователи", "manage/admins-mods": "Администраторы и модераторы", "manage/registration": "Очередь на регистрацию", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Очередь на публикацию", "manage/groups": "Группы", "manage/ip-blacklist": "Чёрный список IP", diff --git a/public/language/rw/admin/menu.json b/public/language/rw/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/rw/admin/menu.json +++ b/public/language/rw/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/sc/admin/menu.json b/public/language/sc/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/sc/admin/menu.json +++ b/public/language/sc/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/sk/admin/menu.json b/public/language/sk/admin/menu.json index d8f14024b0..c4b095b963 100644 --- a/public/language/sk/admin/menu.json +++ b/public/language/sk/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Používatelia", "manage/admins-mods": "Správcovia a moderátori", "manage/registration": "Registračná fronta", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Fronta príspevkov", "manage/groups": "Skupiny", "manage/ip-blacklist": "Čierny zoznam IP adries", diff --git a/public/language/sl/admin/menu.json b/public/language/sl/admin/menu.json index 37609ee221..0cf578c4ad 100644 --- a/public/language/sl/admin/menu.json +++ b/public/language/sl/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Uporabniki", "manage/admins-mods": "Skrbniki in moderatorji", "manage/registration": "Čakalna vrsta registracij", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Čakalna vrsta objav", "manage/groups": "Skupine", "manage/ip-blacklist": "IP črna lista", diff --git a/public/language/sq-AL/admin/menu.json b/public/language/sq-AL/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/sq-AL/admin/menu.json +++ b/public/language/sq-AL/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/sr/admin/menu.json b/public/language/sr/admin/menu.json index 9c5fbbfa23..e7aa210710 100644 --- a/public/language/sr/admin/menu.json +++ b/public/language/sr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Korisnici", "manage/admins-mods": "Admins & Mods", "manage/registration": "Lista Registracija", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Grupe", "manage/ip-blacklist": "Crna Lista IP adresa", diff --git a/public/language/sv/admin/menu.json b/public/language/sv/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/sv/admin/menu.json +++ b/public/language/sv/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/th/admin/menu.json b/public/language/th/admin/menu.json index bdc794d943..6e30be22b3 100644 --- a/public/language/th/admin/menu.json +++ b/public/language/th/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Users", "manage/admins-mods": "Admins & Mods", "manage/registration": "Registration Queue", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Post Queue", "manage/groups": "Groups", "manage/ip-blacklist": "IP Blacklist", diff --git a/public/language/tr/admin/menu.json b/public/language/tr/admin/menu.json index 953527aace..a63ce9022e 100644 --- a/public/language/tr/admin/menu.json +++ b/public/language/tr/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Kullanıcılar", "manage/admins-mods": "Yöneticiler ve Modlar", "manage/registration": "Kayıt Kuyruğu", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "İleti Kuyruğu", "manage/groups": "Gruplar", "manage/ip-blacklist": "IP Kara Listesi", diff --git a/public/language/uk/admin/menu.json b/public/language/uk/admin/menu.json index ea4e7e89e6..4b731cad0c 100644 --- a/public/language/uk/admin/menu.json +++ b/public/language/uk/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Користувачі", "manage/admins-mods": "Адміністратори та моди", "manage/registration": "Черга реєстрації", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Черга Постів", "manage/groups": "Групи", "manage/ip-blacklist": "Чорний список IP-адрес", diff --git a/public/language/vi/admin/menu.json b/public/language/vi/admin/menu.json index 23bcfce03d..6f67b8c537 100644 --- a/public/language/vi/admin/menu.json +++ b/public/language/vi/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "Người dùng", "manage/admins-mods": "Quản trị viên & Người điều hành", "manage/registration": "Hàng Đợi Đăng Ký", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "Hàng Đợi Bài Viết", "manage/groups": "Nhóm", "manage/ip-blacklist": "Danh sách đen IP", diff --git a/public/language/zh-CN/admin/menu.json b/public/language/zh-CN/admin/menu.json index 0e33098536..b3a78239cf 100644 --- a/public/language/zh-CN/admin/menu.json +++ b/public/language/zh-CN/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "用户", "manage/admins-mods": "权限分配", "manage/registration": "注册申请", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "发帖队列", "manage/groups": "群组", "manage/ip-blacklist": "IP 黑名单", diff --git a/public/language/zh-TW/admin/menu.json b/public/language/zh-TW/admin/menu.json index a22836e04f..83151597be 100644 --- a/public/language/zh-TW/admin/menu.json +++ b/public/language/zh-TW/admin/menu.json @@ -14,6 +14,7 @@ "manage/users": "使用者", "manage/admins-mods": "權限分配", "manage/registration": "註冊申請", + "manage/flagged-content": "Flagged Content", "manage/post-queue": "貼文隊列", "manage/groups": "群組", "manage/ip-blacklist": "IP 黑名單", From 78c5dfdc581eaec0023d65ce2a375fadd470dc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 12:23:16 -0400 Subject: [PATCH 206/300] feat: add icon to invite/accept notifs https://github.com/NodeBB/NodeBB/issues/11864 --- src/groups/invite.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/groups/invite.js b/src/groups/invite.js index ddb244cd0a..0683994801 100644 --- a/src/groups/invite.js +++ b/src/groups/invite.js @@ -45,6 +45,7 @@ module.exports = function (Groups) { bodyShort: `[[groups:membership.accept.notification_title, ${groupName}]]`, nid: `group:${groupName}:uid:${uid}:invite-accepted`, path: `/groups/${slugify(groupName)}`, + icon: 'fa-users', }); await notifications.push(notification, [uid]); }; @@ -68,6 +69,7 @@ module.exports = function (Groups) { bodyLong: '', nid: `group:${groupName}:uid:${uid}:invite`, path: `/groups/${slugify(groupName)}`, + icon: 'fa-users', }))); await Promise.all(uids.map((uid, index) => notifications.push(notificationData[index], uid))); From 3b125ba27e162f6a0439b12a1f9a10a4ece18add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 12:33:24 -0400 Subject: [PATCH 207/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 97e5341436..fcadbb1bd5 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.22", + "nodebb-theme-harmony": "1.1.23", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.6", "nodebb-theme-persona": "13.2.11", From 38c0c8dec0930d5e7554dade74929f6d4ad3e514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 12:52:46 -0400 Subject: [PATCH 208/300] refactor: ip blacklist.test also dont call ipaddr.parse if cidr rules is empty add a test for cidr --- src/meta/blacklist.js | 53 ++++++++++++++++++++++--------------------- test/blacklist.js | 14 ++++++++++++ 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js index 8e3bc7b1f7..fc4be5868e 100644 --- a/src/meta/blacklist.js +++ b/src/meta/blacklist.js @@ -44,48 +44,49 @@ Blacklist.get = async function () { }; Blacklist.test = async function (clientIp) { - // Some handy test addresses - // clientIp = '2001:db8:85a3:0:0:8a2e:370:7334'; // IPv6 - // clientIp = '127.0.15.1'; // IPv4 - // clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail if (!clientIp) { return; } clientIp = clientIp.split(':').length === 2 ? clientIp.split(':')[0] : clientIp; - let addr; - try { - addr = ipaddr.parse(clientIp); - } catch (err) { - winston.error(`[meta/blacklist] Error parsing client IP : ${clientIp}`); - throw err; - } - - if ( - !Blacklist._rules.ipv4.includes(clientIp) && // not explicitly specified in ipv4 list - !Blacklist._rules.ipv6.includes(clientIp) && // not explicitly specified in ipv6 list - !Blacklist._rules.cidr.some((subnet) => { + const rules = Blacklist._rules; + function checkCidrRange(clientIP) { + if (!rules.cidr.length) { + return false; + } + let addr; + try { + addr = ipaddr.parse(clientIP); + } catch (err) { + winston.error(`[meta/blacklist] Error parsing client IP : ${clientIp}`); + throw err; + } + return rules.cidr.some((subnet) => { const cidr = ipaddr.parseCIDR(subnet); if (addr.kind() !== cidr[0].kind()) { return false; } return addr.match(cidr); - }) // not in a blacklisted IPv4 or IPv6 cidr range - ) { - try { - // To return test failure, pass back an error in callback - await plugins.hooks.fire('filter:blacklist.test', { ip: clientIp }); - } catch (err) { - analytics.increment('blacklist'); - throw err; - } - } else { + }); + } + + if (rules.ipv4.includes(clientIp) || + rules.ipv6.includes(clientIp) || + checkCidrRange(clientIp)) { const err = new Error('[[error:blacklisted-ip]]'); err.code = 'blacklisted-ip'; analytics.increment('blacklist'); throw err; } + + try { + // To return test failure, throw an error in hook + await plugins.hooks.fire('filter:blacklist.test', { ip: clientIp }); + } catch (err) { + analytics.increment('blacklist'); + throw err; + } }; Blacklist.validate = function (rules) { diff --git a/test/blacklist.js b/test/blacklist.js index f682ccd16c..068882b8c8 100644 --- a/test/blacklist.js +++ b/test/blacklist.js @@ -59,10 +59,24 @@ describe('blacklist', () => { }); }); + it('should fail ip test against blacklist with port', (done) => { + blacklist.test('1.1.1.1:4567', (err) => { + assert.equal(err.message, '[[error:blacklisted-ip]]'); + done(); + }); + }); + it('should pass ip test and not crash with ipv6 address', (done) => { blacklist.test('2001:db8:85a3:0:0:8a2e:370:7334', (err) => { assert.ifError(err); done(); }); }); + + it('should fail ip test due to cidr', (done) => { + blacklist.test('192.168.100.1', (err) => { + assert.equal(err.message, '[[error:blacklisted-ip]]'); + done(); + }); + }); }); From e8fb02f3f770c02dd72941b7a8d18bae18d90cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 15:03:00 -0400 Subject: [PATCH 209/300] chore: harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index fcadbb1bd5..428b256545 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.1.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.23", + "nodebb-theme-harmony": "1.1.24", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.6", "nodebb-theme-persona": "13.2.11", From 3837798292b60e1eeb829c4b6888d9a3be90bd65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 15:13:08 -0400 Subject: [PATCH 210/300] test: fix test if ip is invalid --- src/meta/blacklist.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js index fc4be5868e..e655224f2d 100644 --- a/src/meta/blacklist.js +++ b/src/meta/blacklist.js @@ -49,6 +49,10 @@ Blacklist.test = async function (clientIp) { } clientIp = clientIp.split(':').length === 2 ? clientIp.split(':')[0] : clientIp; + if (!validator.isIP(clientIp)) { + throw new Error('[[error:invalid-ip]]'); + } + const rules = Blacklist._rules; function checkCidrRange(clientIP) { if (!rules.cidr.length) { From 856754a5aabb9ad1f5a43f3d118b6f83c75f52d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 2 Aug 2023 17:08:14 -0400 Subject: [PATCH 211/300] dark theme acp --- public/language/en-GB/admin/dashboard.json | 1 + public/scss/admin/admin.scss | 15 +++++++------ public/scss/admin/common.scss | 22 +++++++++++++++---- public/scss/admin/general/dashboard.scss | 4 +--- public/scss/admin/general/navigation.scss | 3 +-- public/scss/admin/overrides.scss | 8 +++++++ public/src/admin/dashboard.js | 25 ++++++++++++---------- src/views/admin/dashboard.tpl | 16 ++++++++++---- src/views/admin/header.tpl | 6 +++++- src/views/admin/manage/tags.tpl | 2 +- src/views/admin/partials/offcanvas.tpl | 2 +- src/views/admin/partials/sidebar-left.tpl | 2 +- src/views/admin/settings/api.tpl | 6 +++--- src/views/admin/settings/navigation.tpl | 2 +- 14 files changed, 75 insertions(+), 39 deletions(-) diff --git a/public/language/en-GB/admin/dashboard.json b/public/language/en-GB/admin/dashboard.json index c77f7ff0c2..cb517252e0 100644 --- a/public/language/en-GB/admin/dashboard.json +++ b/public/language/en-GB/admin/dashboard.json @@ -48,6 +48,7 @@ "restart-disabled": "Rebuilding and Restarting your NodeBB has been disabled as you do not seem to be running it via the appropriate daemon.", "maintenance-mode": "Maintenance Mode", "maintenance-mode-title": "Click here to set up maintenance mode for NodeBB", + "dark-mode": "Dark Mode", "realtime-chart-updates": "Realtime Chart Updates", "active-users": "Active Users", diff --git a/public/scss/admin/admin.scss b/public/scss/admin/admin.scss index c7ee741967..5003d75f94 100644 --- a/public/scss/admin/admin.scss +++ b/public/scss/admin/admin.scss @@ -37,7 +37,7 @@ body { padding-top: 0; } .acp-page-main-header { - background-color: white; + background-color: var(--bs-body-bg); } .settings, .categories, .category, .admins-mods { @@ -83,17 +83,17 @@ body { } .card:not([data-container-html]) { - background-color: #FFF; + background-color: var(--bs-body-bg); box-sizing: border-box; border-radius: 3px; border-width: 0px; - box-shadow: 0px 1px 3px 0px rgba(165, 165, 165, 0.75); + box-shadow: 0px 1px 3px 0px rgba(var(--bs-secondary-rgb), 0.5); margin-bottom: 20px; >.card-header { @include acp-panel-heading; - background: #fefefe; - color: #333; + background-color: var(--bs-body-bg); + color: var(--bs-body-color); } &.card-danger >.card-header { @@ -113,7 +113,7 @@ body { cursor: pointer; line-height: 36px; text-align: center; - color: $gray-800; + color: $gray-700; margin: 4px; &:hover, &.selected { @@ -136,7 +136,8 @@ body { .bootstrap-tagsinput { box-shadow: $input-box-shadow; width: 100%; - + background-color: var(--bs-body-bg); + border: var(--bs-border-width) solid var(--bs-border-color); input { font-size: 0.875rem; width: 64px; diff --git a/public/scss/admin/common.scss b/public/scss/admin/common.scss index 85cea66ed2..b94eddd2da 100644 --- a/public/scss/admin/common.scss +++ b/public/scss/admin/common.scss @@ -13,8 +13,6 @@ .tracking-tight { letter-spacing: -0.02em; } -$btn-ghost-hover-color: mix($light, $dark, 90%); - @mixin btn-ghost-base { display: flex; align-items: center; @@ -27,12 +25,11 @@ $btn-ghost-hover-color: mix($light, $dark, 90%); padding: ($spacer * 0.25) ($spacer * 0.5); text-align: left; --bs-text-opacity: 1; - color: rgb(73 80 87 / var(--bs-text-opacity)); + color: $btn-ghost-color; font-family: $font-family-secondary; cursor: pointer; &:hover, &.active { background-color: $btn-ghost-hover-color; - color: rgb(73 80 87 / var(--bs-text-opacity)); text-decoration: none; } } @@ -66,6 +63,23 @@ $btn-ghost-hover-color: mix($light, $dark, 90%); line-height: 1.25rem; } +@include color-mode(dark) { + #content { + .btn-light { + @extend .btn-dark; + } + .text-bg-light { + @extend .text-bg-dark; + } + .btn-ghost, .btn-ghost-sm, .btn-outline, .btn-outline-sm { + color: $btn-ghost-color-dark; + &:hover, &.active { + background-color: $btn-ghost-hover-color-dark; + } + } + } +} + .flex-basis-md-200 { @include media-breakpoint-up(md) { flex-basis: 200px!important; diff --git a/public/scss/admin/general/dashboard.scss b/public/scss/admin/general/dashboard.scss index 5ad836cdd9..cecbbb1dbe 100644 --- a/public/scss/admin/general/dashboard.scss +++ b/public/scss/admin/general/dashboard.scss @@ -7,7 +7,7 @@ .graph-container { position: relative; - background: $body-bg; + background: var(--bg-body-bg); &.fullscreen { width: 100%; @@ -70,8 +70,6 @@ list-style-type: none; padding: 0.5rem 1rem; margin: 0; - background: rgba(255, 255, 255, 0.66); - border: 1px solid #ddd; li { div { diff --git a/public/scss/admin/general/navigation.scss b/public/scss/admin/general/navigation.scss index ada36aeeea..561471576a 100644 --- a/public/scss/admin/general/navigation.scss +++ b/public/scss/admin/general/navigation.scss @@ -11,11 +11,10 @@ #active-navigation { float: none; min-height: 50px; - border: 1px solid #eee; overflow: auto; .active { - background-color: #eee; + background-color: $gray-700; } li a { diff --git a/public/scss/admin/overrides.scss b/public/scss/admin/overrides.scss index 58922bd310..90f71d908f 100644 --- a/public/scss/admin/overrides.scss +++ b/public/scss/admin/overrides.scss @@ -16,9 +16,17 @@ $yellow: #ffc107 !default; $green: #198754 !default; $cyan: #0dcaf0 !default; +$light: $gray-100 !default; +$dark: $gray-900 !default; + $body-color: $gray-800; $text-muted: $gray-600 !default; +$btn-ghost-color: rgb(73, 80, 87); +$btn-ghost-hover-color: mix($light, $dark, 90%); +$btn-ghost-color-dark: rgb(175, 191, 206); +$btn-ghost-hover-color-dark: mix($dark, $light, 90%); + // Custom fonts $font-family-sans-serif: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; diff --git a/public/src/admin/dashboard.js b/public/src/admin/dashboard.js index ef80204127..3cd0b93619 100644 --- a/public/src/admin/dashboard.js +++ b/public/src/admin/dashboard.js @@ -43,6 +43,7 @@ define('admin/dashboard', [ isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); + setupDarkModeButton(); setupRealtimeButton(); setupGraphs(function () { socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); @@ -529,18 +530,20 @@ define('admin/dashboard', [ graphs.topics.update(); } + function setupDarkModeButton() { + let bsTheme = localStorage.getItem('data-bs-theme') || 'light'; + $('#toggle-dark-mode').prop('checked', bsTheme === 'dark') + .on('click', function () { + const isChecked = $(this).is(':checked'); + bsTheme = isChecked ? 'dark' : 'light'; + $('html').attr('data-bs-theme', bsTheme); + localStorage.setItem('data-bs-theme', bsTheme); + }); + } + function setupRealtimeButton() { - $('#toggle-realtime .fa').on('click', function () { - const $this = $(this); - if ($this.hasClass('fa-toggle-on')) { - $this.removeClass('fa-toggle-on').addClass('fa-toggle-off'); - $this.parent().find('strong').html('OFF'); - initiateDashboard(false); - } else { - $this.removeClass('fa-toggle-off').addClass('fa-toggle-on'); - $this.parent().find('strong').html('ON'); - initiateDashboard(true); - } + $('#toggle-realtime').on('click', function () { + initiateDashboard($(this).is(':checked')); }); } diff --git a/src/views/admin/dashboard.tpl b/src/views/admin/dashboard.tpl index 6858038257..5f5de432cd 100644 --- a/src/views/admin/dashboard.tpl +++ b/src/views/admin/dashboard.tpl @@ -10,7 +10,7 @@
    -
      +
      • () [[admin/dashboard:registered]]
      • () [[admin/dashboard:guest]]
      @@ -25,7 +25,7 @@
      -
        +
        • () [[admin/dashboard:reading-posts]]
        • () [[admin/dashboard:on-categories]]
        • () [[admin/dashboard:browsing-topics]]
        • @@ -42,7 +42,7 @@
          -
            +
          @@ -83,7 +83,15 @@ [[admin/dashboard:maintenance-mode]] - [[admin/dashboard:realtime-chart-updates]] OFF +
          + + +
          + +
          + + +
          {{{ end }}}
          [[admin/dashboard:notices]]
          diff --git a/src/views/admin/header.tpl b/src/views/admin/header.tpl index fdc655b44b..e2f7725123 100644 --- a/src/views/admin/header.tpl +++ b/src/views/admin/header.tpl @@ -1,5 +1,5 @@ - + {title} @@ -15,6 +15,10 @@ flags: {}, inAdmin: true }; + const theme = localStorage.getItem('data-bs-theme'); + if (theme && theme === 'dark') { + document.documentElement.setAttribute('data-bs-theme', 'dark'); + } diff --git a/src/views/admin/manage/tags.tpl b/src/views/admin/manage/tags.tpl index edeff453c6..00c4260f41 100644 --- a/src/views/admin/manage/tags.tpl +++ b/src/views/admin/manage/tags.tpl @@ -21,7 +21,7 @@
          -
          +
          [[admin/manage/tags:description]]
          diff --git a/src/views/admin/partials/offcanvas.tpl b/src/views/admin/partials/offcanvas.tpl index f4651a74e6..20688bd1ab 100644 --- a/src/views/admin/partials/offcanvas.tpl +++ b/src/views/admin/partials/offcanvas.tpl @@ -1,4 +1,4 @@ -
          +
          diff --git a/src/views/admin/partials/sidebar-left.tpl b/src/views/admin/partials/sidebar-left.tpl index d56029d806..3a336101a6 100644 --- a/src/views/admin/partials/sidebar-left.tpl +++ b/src/views/admin/partials/sidebar-left.tpl @@ -1,4 +1,4 @@ -

        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⩔OXm;SG?%mnT`Kc(VO?Zg)i&5 z;lwj;yWtg)S6}z1icFr`m4*g-7q~O$YHy)|%}!Ipv*`oup0avDToF$d~hII-SH z)HQ;&xAv&;9bvs2>w}H&ppUK9+#)2X>F?gSeVf+Xw%xRUZZ2~YIYIbjx;MAKBbli? z9b}c!4kO@pRrRyf9pv?Vo9nk-f8a9lm{Mt(O2_!DZrCKI*UWc@3FX=*^C&`X!A&;K zhk^l&>6sJ+nQ$5;A?u(k7{pl+=1|T`uXyzkm5@HjtRI^@cxZ}G9%H2Ma>l$G(>Aw| ziiK)S-7GRgZ_xn!x-fMDi5blDIe&X(8vJwwtB4_@uA&+bm1Zxa7j}-gtYViOA*2Yv zT12SqSOa3&@&U4JlNh6#Oy=_23PVG&Nz1aD^=OpcIztLWGOWjmR{6p8-&~=YNpMMaI`vg+tE0GX3CIclKNI0JA3AeOU@n6I3SlW>Uo1#P&1UCyy-E z11>TUZr~#@21Aq2A}9bXO6)Cvq)g6}u^br|$0FaL7&Hf7!GbV|c&gHggvUmLk?pXm zC%r7|R=blOW}cOYSj)rS$tRCab(?u)So~wij6l`D%hQ}^@<}H6RCKmHQtov4n0=u< z4zFV#>tRiV?E`R58K{QXNCGkrNy74UHj^Ah2kFkhUp0D6ibYJ6uc-UfF9Wrj_#N*9 zS{v!4;g}nO`4}$3&dU)m##DYY5e%!>_?~dQOCpSjT)!u!or_tcf^ncYqHh7~n}n%w zpT;my$UfXkq^?ugd#f5yHkS?5j;q<38)REtkCEPv%P!lycUqks9lPn~vC%7Ux#hY~ zRny1_;T!U~a210mA(a@8tHcJ0ILS~KW&9g4xURJP;XQ{JtonK-C zDV(|ie{Jz(0q}87UQpO($kI>fx`Zp(eASZb!^-0FT>~W#)4c2E6oMpoAHgKN)0;r8pmS89R;wnpOphR%K%>o>763#Hl84*L8 z1trH0=fGa)c3#dvIxCk`@@yGG(GYUU6lrl@kOa6%FpjBLXb-C9(?sdvnB^;oY0Imv z9xTLDqk(Wfk3%ZxB521*- z9}7UNy(sF&)WHPP<8cTKqQe-Na9fqh$2`@WfR$nsK4oig)vd=zFwnH5Tw`9S^V#1RI*7=b8R!iB8700(1*@_svVI2zM!q75f_E;2{^*-pW09b@T zYlFoikltZ9&E(3Sa%RyiuPt-uc;w6C8DIxtK#gI%tPoy~#E9vp0P9k!bF|7|Y1ux! zM?u8R2dhIv#aYXn&DO`Dp92%q&31+~j5wqwVmZw8fIs|}9a65J)%HGZd0k6vC(TRng_LNHP zNVVE(Ri|NZF;|F2bGU9?x_>60&xKy{0KzF`HmOu~d5$PfO6 zLBy!<2RMeld0FAQZ565 z!xLB5JQH4bG}?WAl(bpM%)+0G#e%^hx2O0zpRWp*h{wy5?MP53+Koo8nk(x>T5xeR zLQvCW%C?8PmrV!ptR<2Tam*HW5I0Tj7#q*(;z*}NJalLZ!|Uo75O|5$N$mZQ-zrsW z4H!3_`4V)QC!9(p=4uHNj2GH*D_Sh3aw;%1pZ4lZW(13BNIs7uqd0j#iPRrXD7%zS z5MMn#BOdaK)jXQ(VBTOy^M&Hm7lsQ}EM+_kIPN51gtG63TTGIP?){|jX82&Qb!!sd zy;ClS;}g4k%3X4T*XFJ|to+*u(4N%ZJn^A1Q(%Zw&@r?<2)#5sv8|*~lD8260%gR@ zNYphbXhJ&p=53^H3V~5Nf>S*%`|+>nZR~d&`-8)1`;e)k4Cx}mmKAB%SB*s|A}3xB zsUjgdoG_0R;04VB$+Jl`nnH$pG!?O|)Rk(iJ3gyEfZ;I6ESlT+K%Pm17!SAGn7ZPV z6wRy4x19U@v14pyyu~<|$+QErbNKnqf4`;*ESj$*5@)U=6c_u{?TQ2E-b=p|&}Osr+P1J5!0Ur?b3Sc?wmFfJ`E<^< z37*SE3UVr|-u&F!+p%n z+jIU_t#5U^oloWnTPO7`bw80VE7%7R2i<5ZgeI)TnJYn`akgqh%@E#{@0p&NCm{pc zFm!yPK$9)29^SYg$1OFk?tj&*p{45 zp<^L<@!~OTCvn)I5=70J+@c7UrA7OsCrBM>ZQaNx8?nq>6&@9rTK#f$G-o0Q|f+|ZK5D;{+kjv_5Iu*PICV{+w zYlpAW6YMpd88N#P^{R4wKR(k0l-t z#-*Sc%b>G|vPpvRg2DQ(`T2TXEub*M&Dodzb5b$@va}a_Nun{DJ*|Go9PC81^-9U_ z;&6dx3CQTl_TBsz4BV5ovE|z^A!ZhYXalaJ;*&w;-x+9`0W+#HJEB753d|#3-e3ao zgP9qrl$V*oR!{CXB>>l2wqasX%glC-GRzC4l5h>v1Il-B5)(|E;3k;)>3 zjfAlQFeelIVm=ZxV`JU^!b1FoiE1SoBwL{ne4gm|;lqayjY${<3?w+4gf@T&O4k#k z@OzPo38GVl>ajREB>0^r$UgCmN8|BImh*(cipT1=k%!cWHV(=&X|9l>{$DcyMSFL_g%&Wsv}mSQ@ersFSlP77Jyf zr12H8Bz|!$44|tqSE4qU2vjN#cfjosh!QYMHgNw5i}{|oM@n>n18mk0Gr zg;8++#odkL|6s+TfyR1U{hOYd-WP2QPi4j@#>SJoSZwau7z9^kYGP|3uA8%@FpIlX*q!}P0KZ)+>NN@&rm7=!DNHOlnIaOmG7Lm z=#A6_Tdbo* zTI2{oMLY4@QgM<)@mt0n{f-QYMJzmrfv#g;tQgO$l$xceXf$kq5d5>WOKuTqB==ah z-BWS%Jh9-F(KpY7ZENjeUh9l zKQMCM*Fy&y6zV{62f)yL(@mu8#_EwD4Fjn}jx*rzgd23A7oUs?fJgc#$ek{m+~HI+ z?GTOzIx|*MP$1QS#M-2)D9E|ZX9MWWFWG&rtrCi@#}6b#Nymih66BPslAjmXP8p9j zQ%OjOED;6T679$r_aHi9aj{&G{16e!XNNOce=r=*x#6d(SkJqCQNrNM)<)myN#T_N z0We%HBU(>pvhjpFC1kD_XPghJClUR;T*Yt>6s4!TQXNMD=$C}hp!Y)@;@C z;&53;{)~AC4@Gr|WU@4Mn5`A{VK+=@&_WI-5^gq#eQFY>20s-~I)-~_4p{}7J-Cp$ z3~oSdRG(y|k~NAI9Q5)Jz}p?N*W8A+*7M;-jLKgInjwc2HsqB-Yi0`i0}_~_mw|^P zH&PTSdvR95xH1tWHN)URrpPhz5>gGve~4x|vV{T{icO~7%%jY+d8qncV5o8lohd@^ zXkV!m!u~x|h(zpd4FEP%@L5nclg#H!tp~!QfaMGBX$U ziAlYM;xqkg*f5@E&iQaaT1lH$ZUhzWGw0@08B`Fsn}yBW7p5zy@U< zE-pUst1z0ADXhvS-TJ8^1ZxKlgjA3T{MB7o>!JM_z47(A@oRN<-%vg~7pY%f(E;!E z*Ryo7x!$y)gClJMXUHuftIjqb7SIBw(*#?9e`Bmu`Jm4wBLL;~!fIApwM_QgJ*Dfbbd?=z41e4}&Z)J)IXL^VuABBjY^ z5=s}S8^LDoJ{#-R?gQwY{S^F&eA8B$XUE=8bjaIWmowMs&Jm0OJP}>62h#m`EuI8M z_C-0l1LBRnCmVu&WPqN~tys}R$w}jdwv$jfSmV++f`{8;LjPUJ0ZhF--j8kUd5wFf z3>Ps3#3-1!cELaeQ(Hptl-!kgJTvWnP9$8MtC8}Ds1`Go>6cWdhyF@1`53|<`>~BZ z>fy&-l?e8@;N2K@0)BrgLO02JE&wmB@a}6ZV95L66gw$%+k^bkSKAc=NBjpk;u6;p z^d!e!=i$X4V2%v7fX)IU)KokH6CQ_nVA%!eIM3ZRF$q0%nu`d-M4f^XuckUW}Xo{_wpG*u7H-_Vr zd45bCR!jZ9+P3}98~goaK6S~i#S44)Dz$g-g~eT$B!3R)xkKY9*%0EnuO)a*XxMy2 z#}i}8d*(1!<5QD3*f&_}!5Y6N zX@@#I7b>6mAlXLmZ+z0$h$kShA~IT*TQEV*>rviQhYuPpf*4PTJ} zY;w}ZY?4c_P>1&0l~y}k44dcjY_tA+@MjCa`GRX2Kc6FbLNEQV_}gtKWf~ZNHr8Mk zfEr!9(Z)c&TfxHA0ox38o73GU%g=x$cA_jrXP#hM8mfBb?mf+>z{owjuiSck!_Qpt zz?4K1gtV@q{RSo$3%9*^QaDrfjg^}z9S=-c#ZJL98SadZ{p0jB0bCJ9fUzGMk%pJUuifXk>GM0fESXUq{l4aY6OrtFOM|iihvI>tSf)RBCz>i%rif zPO^V%+v;1Ls1l7{+EkqpY%E;(@c zfXVxW3j@tGuSOlCeIq0kpmXt+CPf(HLMFkyy0cj1ZVCYfjA6&vV~fC48}8hKeHPt@ z>wYsqL z&33y!yloq{MC^95_OOf?a~pghc^(Vkf`KgXr}7Ml33;{65He&SLf8R=5N5!S)5b{G znF`0z!eEgpH8(SdLn6WoERz{!Q2ygv7t#~Q{R0m{felsqo_=KrY7Bzg@UfmM3@rf^ z1DR4efKxR?50~eu8edOS!qD#h16!+djyJwHn#-X@f?&zzMzNvGB&ioOK(sNKFJc5a znoL14c~i+z4014K6hlI4*GL#MG2~|aWmH6{8S__w0(XuTc4oggIA#p-g>ufjv4KB4 zIQDEQ<3*3~p}~2JvHsTJIDkb?c5oczh)rys6hp3mW^f!g^&>s^2(>b&{US-{Sh=?A zU4vuoim0C%9J^fy)awSvo-Jj(t`qw1!Fh{%zA!irxNcV6!Ew+vsl0>Zm}^XZd2k$; z`cJQ~pIh5LHFa|J?E2!}OKYoVmL`v{p1Jbcc(7giR}SC@~k zo~^DetydS%o~W*`uCCmTrL6k_yM0++127I9Eo;_NCDw}e>XxH-C>@=LC&xpoZG zz%`D~aAl10% zIezm$F?OB*Hg@br;nVqh{0r!`e#)QVYR~}i3hjTGJtTp$MEFSXDHy2`f#cC&0J!5= ztu}}hnp7!hcZ_{i4lzEiIjW?}Y6y*O6)UZ}YN%l(pDiT!BWe_0V4NJ^9W|+@$mKVq zW>r_ssUDKYJ~FdyYP;Hj1>-JtiQ299sJ&{R+OIBEm#G7&N-tN3)M0f*9aUGLg1w4p zMAxWm)phE6b%VMQhrpXLZoEa^s-CKDQ%_U3t2@-9I;M`R6U22ssZOCeSSHZ=yeGI6{?{i1p!8j4?rg8UWrX7v{J zR`sjuZR+jn9qQNAJF&QZH`$bb9c}IV)NiQYB$NGb4Nd2+;h>p$Ta^KJDn*jIi>{hRuC zc&qQK?}1T&fR^n))sNJFk@;)`&l#6+>xh<#4lEIj5s>={y+o8H;zUJsRFfc*lrc%N z%%lnYlGQn#Ct?Urgt|-&gNm-|ny%}H9@b6W(rrDWNA(!-kS26TPwFXDKQqM4?CLop zB+cu-UeMe0cD+OI)VuU0#7x?w_v(FmzrIvoMs|~f`f`0pAI9(QD7o0K)K`&@?HYZp zzD{4SZy@sKP5Ng26n%@nl~_x+>8I)2^&NUqAJfP63B9CG>Qnl(Ue-_7cj^^=MxWKI zexv>+{mc4I`d9Ru^;`5? z$rtxF{dWBh{cHN2`d#|n`aSyB^?UXE^l#|j)W4;FTmO!Jzy5&!p#G5lFj*XaPyfFD z1O12kVf{z?kM&3NBl=POC;FrMG4i|onf{pmxc+nf3H^WcC-tZFr^!V38U2^~v-)%T zuk`2jU+XXEztLaRU(#RJU(sLHU(;XL-_U=n|4x5X|GoYP{g3)v`k(Ya>u>9S(f_Ky zqyJ6+yZ#UTUHv`%ef*kh-o3VT z-n)EaX>rAWX8HK})nhBGr{Zfo=loLV-15>1KF(3%!rA5ZdxIwymsjpRvns8R4azK^ zU84`@7teUlEZ?(q-d;PsdT#mTz1E4PrDrak4=$ZJwbWTzI<Cl7tXGoTVW^y$5&P_oH)r)EZL_nEU%ncI^j9JeAkk1Znksk{OW~s zKJ%=V)f17`Yn>BI=T=tlwQ1n7d)Jrz7tS6(y?B0o=|uAG#r5N-&n%wpoLQye ztLK-`p7Pwidg4O#?q#t5*%J)riMyB1-|0EFy1r%|KXYzn`GoJ-^2)OOTc=i67SEn? zpIg4iT3cQ}zj}{Prt0kKi6zgOrS(PY+~SFqrS<69lgB$J7|G)@9*Zjh`Mq}UnPaOf z{VI#V3oyn#xN ztuk0E%V+OgIbYa9_e5AF$M5W{LRy_%S-snTaoJcWSC)_e-#W~F$5G^p!>cg{eCzGm znIua7$QvN7a*^^n1sqJ-KrvN?ZTji+9c=e>)ElW~C>n~o{BDP{UzvK?ls1-Abrzs8 z^=0Rulf1XqW*j@ou52Hu&DcTjY`tcf(=D&PEz7c#bvVzXY#TTE`zX@rrR!V{M56_I zUoPkMRcz@}F9Uy@(Hw<7Bs_))LqW$;_K#UyY%gvdI)=ZwI$w`0XGq;B123OV>l}Dd zVAEk;+xQ&xz4cpI1~1d-hN7~*>SXuf(x&F!m331{YI{5$elo5Y$CnQ+UHRHiASyjM z*LNl>g<)3m1k9tk4pB`19Q)G9!U$uVd0WfH8q&It+u)|5Uig+=n0r=%ZDy38LSt*d zz4lT{mr6f^@9h&RHm(4|u4O4upFytS5QQ-S=4DC0{P>Y_!oF_@0BKnc>D-vtaJvG#dE-2=6UjO;!#I_xJ`m=8 zXswT^MmcroU9gD7T%u1g2Wtk>hTS`>iZQ>oCI+CIvDlTfL)ydFso&29TS+=`!lfKXt*EE>Mc$-$Or;^Ja2C-&j-h5p|WZ*f* z*EugfWeKBk>wo|L`*=(7vp0t#xasYUSwolNvMH4?MYOU}vD5l5?C+F7MXU^oIztZb ztN`<*clB-02E5DSY6|6k^k{Y!i*_1fj=wC3O%YdH*1Ta7O3B#n-p`6sg%26sUdK|7 zmVNfwb)?@uq%vHrH|wJ!Gh2R(W6CDg;-2WaxAHKU5fO+_^?kOtKMA>Gg+eUQ1I%%D zU~m&#>BR;J{y|5X(@&{S(HV%g{xLakUK%WdU99;r{g_9=Ch^g{MA`I8LhF)940B@p zy3A-v=jU8eS@FVMnAn}s;bVdMzVA&h5~uNRkIn!1ex-~%%de)Y&@hW!7P>Jx?J2k> z=BC!t*K{wYX)r=U#xkkQbXcM_?6h7zz$!mKfw%$dbPOyG?`MT|LFHQf*5HVkrnl$J zOtro@_SdFU}J{(D_s(f^L9Z`Dc;YS29l$AwtG1iCQHMS$U9kJD zDiEr{Qrgrf}5qPCz(_uZ|`!oE;Y1mHO1ITV?&$O1#4f_sIumY+F@T3 z&YR12kw#=d@JjZP?2V3ncXFygZ}XBjXkZjueS ztdWm8C_?XN#c}^YE5o~dfUcRbOgpL&tdAc4C48(IpQ+)a1)z=uoT5eFQHIvVlkpjg zp|+FSIAN{3`=Jo96ylEc@(3s$&l#J~($@JD!ZZw~O)th^N$ZQ%`xn7qU53jO=T8G%U)#P4ukV?O z0tf3PA`%DF8KTMU`~5(|WJ7SqB}c2E+{=VL-uK>EHQk)(o~>N4eH!;&EvK#`_kBGY5(^9|pyX7N%71;of&kOU_C!>=JN}N+vPQ%`Mz(hy zq<%c}`cwneH0qNfp@3{(!5LbEmXM|tYrBmijVVY`Su!Zz;QZb+xyIl;E~^o#u=BIX#;rMG6b$ z&(u#tG6)|1*4lPTc|S1U(+Lx)i&>&Qkg-?{9M8K>ULM9+lrp=aUJ;$YH(E-Bxd7#S zgD;M#U-*8tZ{R%?uHoZ^rW?&Eu|rXbcq*y-hhgH4~S_X5?8I3M!q7jh$Lac*{2fyn^w~pk}2>r8$YDR`f@0@x_Jze zXuP31XExr9X*o3wc70FM8q{(M4Zm2Q7D8mBEfGrsmRzC3x-N)vEvn>mPhOjot9cV7 zlHlYs6iacsS+pK2Y7do*k!q3{Bxc%C*c3y7F&gTV?aR z>#4(9PoQEuTvHI8uKox|gd=t{(3Vub3uVRAIK!kUr4RO>mzSG_c2v0j=fq%ce=0N(vVPASW_cagux!~OOxAP~VbEI7|S?@K^ zyT0I9zQ+Wej23N0r7A@QH3~G!kO8<%f+1mX@E4_>t1=a>nQd4rd-q%#`Y{Qj+Nkd?W4;nqY|q91VPXwMV9G>ZL<9VN2hjzCIEyw-M#9oyK$>Ii>hV8ZU0ds=sx zOG-5nC^hZte?7^h20|0nNMXjR6>Wj{{Y~rVfq|01*TC{)YJ!+L(_^qK__u$v^Lb9Ze?Pf@YejcVMNT*gcf8); zvCb@5OE>~>TivfcKeK@Qf%24)T6Gz}eAgep`X~Z#zrUA@3IY~wl7An10mg+1Zyx9Z z@Z~(cvOyU-D5;@9H2RpHwOUXJANwdSpbsqSjtyvln(m(Zh)yXnci5bu9rL+!Y>=6` zYqJmYR?MYBBM)mVmimHsiuN_e9#(n6Grt+jQgNEk9z+Ne3nmka)~eoCc@=IXnD8$5zXiC*sz%I8TXnQ-fy}ptw&tz)>V-mDv1k z3nUV(UgyeBmB$ay^Zlgb#f5cgu|BFe>#4M5k?%>-ORY^71ctA)5(I0?&lZco(?|Qz z_?cat_g}ZHN6ffj#rvr&Zzc*$s7u$WGmib{tE*Eu?MkD2*^E@t12WZc_v)wwss?89 zNWaxYO)t~nRJ2y+JNeU>ouqT(VDWG1S0Uh)+7%r9aJ>h!gfk6ac@5@2A=z9PG}(%$ zM?5>R_iqp7d%p54@FlExTJ`93v9bGET=ib(9cJhB1$K9Emq8q@m;S}w3--o=l`6;m zw1umu6PG=`YfwWZa1BkJHofFBOuT+xtBHcAZ-5k(<7BCVS@XR5rcS)@lb5y3Q}5}y zxbEpb+$U+OQ*lpSVk*v&mHAg0-%mevKYpOkyHm9JM@wqHj_bib!wtK0|9qUJ!b$_z zxM^=*D4+TLrSxaaYvIq@jrn?nu~9d!9c)E>Mxp}8T7BMWK2x7w#eEId)VPTF&LS2_ zcTK1Rv==_HeeNcF-y>=qY`vq#AvOpwr{eDvKL(`E$UZb<2(Rfm6D_C*U<-^*%)z$l z`fmxs8Y43%6L(WZ0>MY<7iQjiU4h5JquDT!Zxl#kY$4|8M#1tqq2sob%cx3CvtD?i=K8T$IHFEzNW2I4~_lJ zJ9oP68t?pX-@a#WK0W?Tel)%&J~%!){&;?tl!QhlL|T!Oa+a3gjDK>y6p79hz$}qt z3vSsX%@;|v#p$dNE`JxfgxSxlyvYiV7i{AXqg3<29Pfkbrc607*biNHP(APZ@r6;{ z!0Y!%d$2Gar*?|%X{*;!Epn>EKIPq4}zO)6`V*q9~bCoDS2GfrT1 z&@LaOZ6s^lsc%hiy^;uu9i)G7k%(s&Q}#?)vSxpjwptlxWgQ(gc>WT|FpwvuN>ARV z*-LT9@&8z(r?4>M-D+Ff69a|*DPT<$8BWzDSd*kq5rQ9z=Hn);+5JM7HOT>%GnH z`1o52zv;TwH1!3!unEmf>P6Gi>GZ=!?Y~o)Jmkj*g}RAVPIC6+{GPNK5cpwvbv|J8cj}id@%Tw_+E(n zs^~kddu#eC-aboz%j>O~J4t>6|NVSI;8nE+dZOi(l~*Wna@CoARoQhi+Zk$Kn+?)Q z`1>5RGpQDEa@U!|SOa$=%Ns0T*IJ%x-JxBYRxV~8m{oUF!DHQ;RbpOwYF(KHT0UW& zgj+XS!D8KvTOtl>U5*P{E>PKaR?t~xA8=M^U0GRKSc&Y*@y3npOYemT00{A!vNiGH z&Av66tIyG%`k&^XUZ0+y%ACTT7M%{AVw{?tel%yPCv7LaC#fXyCtW7nB{3w=B*!Mb zPIQ}kB~fikQAs6n`*HhGZ?SFB=wr`CN$mT9b06L7%=v$Co;&H)*|?_70$(>a65JNt zEb2qkQj=wb(u3p+`FzJ5)tB^~a}R{>zlxUdx8}xRx@$gu%023lSEUDck5_>0{%Ra^ z#FuaYw98_3?CXEX<}1;R2TX(Cp=uT=$X25{D2 zv&_R?aLq$q5IqEs91#KF0Z@Cx#16n=WQUt!W{2@%Xor(wYKN6!Y=;+7M0^$&M0_3= z5N>N@Qiq3O@|}#xiT(z!DE~+_mB4+fQV=RxSt$9O43Hdl7Bp^8V@!w1VcVTQkv#oY zM66h)vrGk`Ds4;!c%@eXHce!HSI^NO6+g)2ox#!+Lkrah`KUXkGmu6MVc>paGZ>Me zXQ$OeM_q=QvY`JEX<(}dk4i4!-af`d#}amAsb}$dAWf^MxfrU`pl(1l_@!iQ*85dI zObb8C)Ib|tB3(UdSb|!`)?Po13(v^dKp9LIR*yLZfz24vf^!A(Q!{;+0shyJm&^Lk z$oUgD{K0Y;i3NgCgj4xIRJ_I97O8BYo}@bqXNh<8m7cBeGeycuSVsGB>o7hACCSm- z#`WoI1NKt`K?8e(tnGUPV;XkmO8Icyu$%AN>+sWX9Lp8to|n0WaodXh2%+foTf_3| znEvqAu)qo?6l(a$8Kfh)BRL{v98Z`7wIit`Eh5=$AgTl!7W^*u9_gMjzKkwp{Bayr zEwTL|%rO7(CwI0-hzI;J8WT$04(T4kp0BR7kBm>eO=Nzgfdkk)3Yi1iE!Hg-C4~g3 z#3;c5_CZE_G=4fh(sKe@Lh`PF6NnRttvI73V~E7Wh%ixnvP|NX*#m-;nG*(|jD48S ziKi2slT5dez1&qy`ncZ2<_%{Dlx?8<#Lw}e8$wTTPjmtDcoGF|gAYEqaAs6bPEW*M z%DGUI7?C^){Rk3I7Td;HS$!G(@aqY@iR@c4PdNBfi#zo@&JU3-;jN~H*H?gj0m=c} zf%8kOPx=S6e^P!@{;vNW9JN*KTCoCN`+w-Mln(uuL=TAP}`C%)th_Ch!Jz zkPfH~T?gU|{|z~)0Q9QIuV)1k)*oq#z-VTpN)Pa+DZ>Bl31P1nqu>Q^trZO);7mV( zUWr2`fLK>4G%`Xf$CFhrRfk|rldBRG5Ow5DS2|6K0J^`4LgE7FgZ^R( zw7aQLEbQ80lW{@vxxzdVcmcf${SCDy(zAU>gZv7(;0 zxxu6G0`v2R?t$(hm$zSwn-A&fY^`7WnCp{_7Zk|B8ns>Mdpt#eFXsA}b`RRfj z@w!#kmRFb4&yG)zSKC|u0hYI~*Biw?A>#2GodDgu!x7(~wO=93DrxD)(*^KD4wvZW zP#t{U-9CSfwf$oH1=iQo?c24h6;#6dT>I~!l+qen?%E(?00DPUNFs7YK9kh05P9vv zIzDE`;+o=^iLof9y*!sJEMPI+h)tI&9yif(`l49iAE@sRT6qi~?=f}&P3F=NL_rVS zKM95I2%HARyKAI|!x`@n^PvaZE;5BWdFMfuULcp7B@T1GD4TFm#-vglG>>XL0iBt8 zfntyz;O4>@LdPu0AgI#l+3hQ?tiwKLlKF7{#>Z?(#=|Ue5L3yRB(12lI0_SUon~M7 zXUB-&jbX?%3oVeH##rHanPZ!?i{ys;eO`GBve_P8%uYIT{=QUwrLdz-NIujdyF}2!W+jh z3Ut>e1IJLkUDqcCA7PJH18b`z-bb}eGMAF3E(nA-Rl=lD{9!PaK@y_GG-ZH4{e_k_ z!)(h5qAtGT*+vpFpxHA#WHhRoXViqF|9jurpYjVGi>}--Q2tY4TTaC|xJ-kfAEBsE z3DZImajFn*3*XC%#cc{bM_FvQ&ZDG)TJ(6Z`>^$lt@}yC1408`nhOkWwEDPKNo==t z=j{DP&)s6R;b+ zhrS>&MlR=O2uqzX9q!XJ7*4H$&{kQTc>vEprDPP9kd2|hm=O2?L-9`=F50MBC}&+S z+>7LL$|28BwFcYkLxD=+5k-1_=3=W%~gS~O6+xa#Zs)71I_jWZ7 zJ&;qxeml%+J41f9ADo|DXRSS*;2qs8iSiWcy(Tu}VtKQ}#nTyX=xH89{)*t)R8I07qgT%c>&=1PbYE$( zgd5aj>nMwZEVmgzSvmRS6z{O}(jMnnS57Xup|Ni+K3*=fn9nrKG8KY_Y>>_*oi3?J zMojK;%0lhkQE{jp201G$nRC<4WsC<=-Yp_;KZ19QILNcB9X<+j*uImbVGu@LV0;b7 zcSda09$rRi-xT^4Nvuujm-f#4kF3`{Shg);uDw^7zt0QgHzI_2J9LE(O?Ev#`5}16 z_Vip4SvkFXAFUSfr}S0ZfEDCjzZTi1%+&KIu}jJDqAkr}J!`=CGecMq5z2S1_pkqG zYWme7_S&wH5yS>*=rcBp0@%Uv$kuRwZub68`@|h|un}m#iH1s^cXFcmaVpMfz1qNz?7 zR@tEH(G*=Fjy_MoPP|V8Ib_UhSsR+Nju&b(GtjJEq@L4L=Bwup-1?ewv=yZ;aO!!8 zW}VTTiw9lxso{1$nmsmHU443%QNr=ba5TaNyul}sxid8PY*zIOgjJ@kZyN!aM?*d9 z;{9<#c4}_^dLjd36hW$tSWcOxqMbCyg$A?#sqFC^uv=NFH0#;p0>ICpNL;*SKhEjh zCrELgRa4W!uC<~6r#|Q+$gF|qep`ZyN2}I!S8uELwY@wAuA+`(kuw3yp5Fw3rem`y zE}UhGCEfIK`UK;{i1eXC*##r}H5nB(#OAMSqaKWD0hUKr{$K6~C!=g!;fGcq1gA>I zzo<}?8@YoE>C+~t-QKNQo!u~#?|g(l|IIgjb$Cc*@S!G_UhvY>JPtXu9P^jP#HMQn zU#WnJEgo$2Y^7y;u9n?m$T>V2-jNcODoTO4BjoESoVFHzz}{#{b>{VX-TEI@Ifq%PXDqT;g9_barlO4Qj`{KB{G-uoXYBCvm3MN$eQO$%%^asj9! z0i~vV5TZ6<48)wBDyf;e=tCgfvtDJVi)tMCL-Pkdan_y2#bwR9+A#x$n!~wqi$wnh z9X-m-sY~6S*tuH0&<|)~R0~e4Yt1;i&lH-nXM3KFT)oZ|0({eSMzb*FY3ADPZcpFk zR(kK}x0&o^gkTsWAvcGF8S~YFKrx4DI*q5ef5ELzpQD`_dk9z_1YzAE9F79BaK9f> zK}I0v*BHT4#fx{Gix3biFCb7wKWgqgVsQiuE8%&hAETux_K2$2^}5rT>*%<1ChlgK z^-Fz^(A#l<&|QQ0i8Fes5{?}_FD+>k|m3pN_7EcYtOhF8+T zQVA2%k2wtlkl^k@7VH7jjZtKodvS5Yh1IUe)HD`<|DggFfTN4uWx?EM)lV#ta~sZL zjzAE8+wCwB!VC{+g<<9C2?Z+RQYo-hRX>&HB{wd*(><_{fnZrGU;rb^L7eHzqIAlh z8=8?siym`U$gED=Hyl|q)k-5!5zMkOti|=WjjPoyDrfb~{8@g67}7WOyVJAGQ!F78 zU-8Zs(>q1bk46L?&=f1;6d%Hw$TrxCkq~!p+Ffln+-t11hv$A7Ku~b!DZo&$!869p zUA0;Dr@Ei&W>Bg>Jon)BntO4@j10uPiPn78Ek8;=p)IGC2D#?K-7jw$#LJMiUAAc* z{F3aXkEa#CJtp86bCd5kybEAY!@_W z(4kBLZj=ZMFsg7VEQClO=AfPNG$hm6R{)Wf#X9A$hK*edo2Z+E0EK3j+;J$3WYC~= zF}?DI`m^R#Q^r~!V~v`a*I6@)1PX<#e_XWcveK49B+s;)Xac}~SJHWO>LU>2{;3+~ z1;bv(P>mq#t)|1+o7j=+xe;0*HwBYbExikBvOg98=mwn#FQ+gLyL z$l1~wF?!D|FZ`Zb8zjDQx_*Z&PRXSq1Y_G$U!=SlVY0$3s}c37WZ*i596fjjB+HMd z>sF69zzTZc>H@S^U&h<32dnhP#ie)CAg{C6eGxtA6mYb^Zia_+m;8w+zRh8uM~G8K zWR73x*WC(&YgL2J$Gw?R%F4*`L>Ap}Ul$U&0sEI|-L?(z%Rbld^D`?W;9055Y~LUB%Y=&wS<;pv$FnHVp}UN6~BKw zzD&4%Lfjsk;lmp%f1S){kE6^&66FH{US(lLp>sq5LG45uMTD#FmV=I6dO0>YNu{}y zFiya^=U)Bte0^oqED4}_h}lvrNHpUZ*7f6o(ljaFf4e+Dw#nb>lxB5XwBGWJcVW^cM8 zUCq?CMwX4#S@QU0gJv)$T3QnLEh)uNAh}vnBQ;fy^WBqs!qZ}_VQ(E1yBgY!r`(e0 zr;GzRyV@f6vFjmdyQ1T4qAWu4o_n>7q#%dI%gS_#!OS@5hZ%`j7Ac#rXT#S;q$ALK*UU zxy|xvWAObr`dKjQ?&Ixi$?{Tn#si0CAq5m|`SYWHPd&d(!r6Na7!- zbLXQ?pukkWI{$@XHni4cHXWUZ>F)b>U6?Io|o_A zVrw4zqA%e!j>7#l2O<+p5$xOO{BZx!d?8pbFp;Yh=;rcK7h(wk@;{W0rDd!z6bs4v zga`X*Rxf6tnZ+=v{YfFg)28tk*Tn2H3&r?{gXlhI&AHLk3*@<`zruOY(r#3**f(0y z0S(v5t-}C7BpjM$4MBCysrZonm9j5C-=+>6hUE$mhb*()lrbQzlD0GN1)aGZ7FvZJ zzZ5jATqAASz~{13&b4&VcFsA=c-Z(OxW-0 zI``Dl=mBpnLF3W4I~ zW=e$vb>jl3wig!{xjNZ^?7y#Q-d)=+s^WNfpWe*~H7$fS8jpP-{zJBqKwHd1wC~q^ zg`7Ol9Qx-yU(xouSC8EO=+_qmTmxHMJxobq z=z;s)Cu08Ub8+!`TbTzF$jk9VRHLgJex3p#t*v3mgU|-mJ7tD}f9GLD{@ZvtWD^GK zF*8!JjOQCD(+0Qu15%2UtuiSOxdnqoApNjF&qi(reETiZ=jNF5jeOi*edy-@%xaG8 zfWElnzxM;=g*dSAQuO>6_R959B~#M>StH}QCF z?Pz%WWAzGm&sD+N;{rkU;JkRQ&JUqe|1eAzUdRO@zp)pE!F~MU_pi^~$`exp2VNgK z9Oo|An!P$Ohd>Y_y18qY&dOeiWydY*+Hmb$buWj{QncG_TnBG#{@}%lSJ)xw6_g#d zIma_PsasX$%92BR`)o*xt(|U63_=DCVN9zJF~hf1#aR(TB<2aGd7QGE5B&{x04S$d zkzTj~!c{&TvOj)blBn@7|LLd{csNHgywnA|1A_H^og?vy3jJ8V0qa9FXsxRZ$0n*g z`-(PrkAG((c|o>mW9MG+zqENq66z}1{VA*8_#I#8%OWCqT6YW-1zD4@Y{wU(pME_B zp7KcZ#pW_EogR4NO(*G_p?*?X#XbY3jZ}5L=5fj{yBsov<_a20N zqF_Q~siSg8ur5fYM>eR~|4?v8%Y#kI7>#BocMq`(E0osyvSy?cy1WePF8Y%C!4|Mz z+a(Jaixqiyjrn}kbH@R+Vu?SAjp|#3Ct84I+@yq`Xa-*Qo>?s;(L>F@H~!grd8pDA ztj8C-KGdZ7Jf-J2+a?&kQ8m5pmB=pj_l4x&cL!7orqN0A2SVP@j%8u+`k-#Cdsk~>2$EuSd_%N~CNrM2lGg=h z2jY?fI)+G7e0MIZy$(iW|-vpGF4+7lLBsh6*h=)+-lo#Sptm079-mr#15;D>YdNb_jAmm>YRbTDzSmgWxqUhz{)PZfERI8Ik|z~( z?%&a)3a`dY@~{HJbLpD-m3%Z|=+&`khZyt&_Kr|K5q(*GIZ1+a5o5PLug-F;Ly;xV zu+-Tk*dI*D27~ldfY0|7N39t+8rI$7TpA17B-Qd7T8qc(!gzI9K^75Ze}mREtwb8F zzwy7=wqs4^l0_uvqEole8K1M|sHAetoBGzSKt#@3l?7Wx)|qqKPut_rxO62qfDiC; zY%W}^HQqig+tj#(fObHh1-FV9dNId2aE?=iCqcyB3D7OXQcm&&uVLdR9Wj{zKP`^bZwd1pQ{nMrb#+g*S7$ zmfoytA*s7JRV6y3s1q%7S6SrbaBZwRiIUjAO02VYotl3Pp<{U~tV^p?hvhMnNnH@m z2pFtWFQ7~~lM0a{rxzGSmB&fZD;rrWXuo-eT}n}DSYNKeMQSM0zxJV=@q%`}Mq6ag_ zZ6aRD$RK&~0MW-6$F>!`0nJIIby++nrbFBosH`Uz>1Crq_@4mfs4RASpbJe2BZUd# z2ZdyX6|R}#z8zR}w7MBH96>G%C41~Xm0>J|vXODEBgZTwgKUXhtpDX#3NY{FolZLO4IXHK2K|X3S1ur& zx5!qrmT+O+Ahggpg+RAVfo`OvIPCL@WfGl~@7L}*aQ1_^N$3ock=ir{LiZj)Zh3%t zjn^XP99N(tERM+ zqa_TNNo(+)ud*v>=)24BYmB2ps={hvyRgp)t2q`1r%X(Cngn`@+r2F$)j&LEZ%iDP zF~6E*?!2Z(3>kdDSiA1YD=QVtYM+x`C}_XvA0v;l~|f)25bALybLa zNS9pGg}B?|cv414%)XJ@=pmu0BTPCH($?b$lizLp_r74B-&=aVfFKf2f3yP;&BSF$ zOmy@3`H1$m);n|EQL4YBj29wp2nP0$Txs&DEfJ=e{vRt!U1Zu*sPFm@E*BEzDf<+; zFHu;cPofAw{}&0&&lyJzjVkLNJETQbQa$T7K)@gp^Y206&=}26V5ku|8@Q1As8KoF z8wM=Cc+nZDn5g)?;~qMQVb?a4rnOn*KK&|Z>$;3GtNCag!W_uOSR4X63J%0_q$}*7 zXRK9dXcBN}DsVqo#-to%Y;js8nEcQI$6;nAGs9g_raH>S-NJx;-tN)X&)qwxy6`qz zF=0deuXN7d&B%T8qNNzJ(H%+%-SIbwNatMN7`8R6in(WoVL^ z1iCrWKpApk{zj=dWL8Eep3F&Vbt(Q#`O?S2@?^aXJCR;kky}y&2oyS;3a3`2duekk z`cPVn_xkYwJ<;wL-r;3XbO04KAJGms1oy3W0NTsi@*YgUa_={{0L%k-f3i^D?Qw)Z z;>~{%5cKUH@KWZF7~ub80ey1};D6x(f8lu}LVpm_PZE$Ck3hcpBsbQ-%Ej^=Rnr^K z`(t)+8?tK%yrh_Hq?e)Sx!Sq8E0IZO9BAtD3*OJh13VMxr`_wMGwOA^oYFx;)i-!< zjOH@b@xgr~rvKgF4i`=3Ai~O|Eru0*idP``0;%qM@c%dx>^Z2Afb8q=edhW;Rq#7* z`%MfU;d{vX0jEp(jK(@!b-K~^v*QUB%Gc{6c15EGOOQaoqe+aT?ykp@f6h>$TMN*~ z`{28H@wi+o;8txy)`G)^SD8;rX+<>OY!_yEl4azPx9?P3di{fPWV}h11Rw;faAuD@ znrPOAnrWwni5*6>>fHJHui|4@t_4al&_Oo&B?enn#U)Ro!tnR`tBxk|Njw}3%QWeTrmAX-+>5l(w z{Ak&VujckfVYFALrj~cy+a{SU6eJ=v<%>2 z*qG(tz6CORB=Yi_YO6bi`V%GmeEA$OUVK~#oPQ(-11Fe$;N)tftfC9fR|w~I|BCM? z^L8K9xHIm3{@iu;IzL~kC(3{pfgLz_#4Snrfq2Hti&&OoO|NU$I%vr*@G7EZZegvR>Zrc6NZD^)K%dm-P+P@{X{M}NLc4!awQtX5Ft^@Q4VOD_ zKKBgb)3^NSyL}BQB8?)N117oazh&=+zwWk%@Ppuij|PPO^i4#1_xk~$yTl4FDcnM` zbpH{V-hBX-=XF-XqzCt*KZgX`w|pNg!7%kG3)j!ezuagFjx1iIjxFTy07VG7c&9tn zNWa`9>%kpCAfe~p2~}j$76(I;lA@6px*aAHf-2=BqN*jOuO3Q-)j0W~{d)L%?{Kuy zq0zT@wEcED0LK|mupWZ<{V<&=$p0~3r4JF0BEl{*?&^U;NG6w*NYjzXC!{agE94iP zz?-V3Zz?hxNsHy0YHGlj?5V_H{qH64xuJCp;pZAi!^sv}(bx;e>{vJt<9NX;`*O~bD2Hko-f^yMvSB(xN& zk#3j8>Gzr+@{8RV7kuAOtK($I;~czBp&L%}b}yzCkcU(^ott(RTr(|n%f?OZPC$*h zQgaqyMqPQQ?_2~q3`QhHGzm|Yy|MTBCw7)i!}&hSbNoJXDQ3o0KvIxat_H7 ze5<@p&8Ml_33TAiu#OFG{!l4zX|qKj;+!kk9?QT!Bpf?JZ`A%ur7w z7DR7rfZu#U89jG%*e5TvJj7hd5=u9~i~bk#Je_IE87-noMqxNic^}$)(z!5nOs1r? zkEs3P9{6Y9Ca2O;vp0%pxj{j86z!RkA&ayuh5&WviuFIPo2`#*ZF*I~Hc^XNn@mbGUI4jW**rM73QgG(K@D25!pzSh;e2{*|N%=BGGWXp`)fs=3NaLW0^Og zYmuPI(`Z9bsPa@*z0wvl#vCuHW~UzAOkDZ!*6sA<;PD=dfSQP0w?L-hz?(>e#GRzD z$P4q4Zwm8k5z5&0w3S-r)F7sgJ`Vg9&vV*Rz_RgNEZ)084FdN8f$qn$Czb4XCmTW1 zhx0%MJfUEJ;30vwn6t{=>&&oxaRHRUMbVRZgmWZX<+OrXz=0e?$nZs$YFyegk405r z2n7VLawdAomw(TEtY(Q&J=v{@! zW3Hdtcn|xqk5-GXx3*87@sP0jUG;2nmnnSr1I7Ec+qW;NEClhrm$hn5a$S>e?UOFz z(4MOgJC9uT`Bs#yEpA}+1o4JGrS62BHaW7~I6Dj~-jkb_J1h_Y`_)~G|62TUrM1{S z8=CvCwH1>8fa-=#Ib>RrQ~HVwTHzpJJr=4jic-*KABpLwxF{)LJu)+v^?fUZW1YTv zZB{QYpQN8Za=e+9FE5|&j`#;nVPO@a=#S1@1{Tfl-LS@qM@NIdBJmz^T_NA9ZiENb zYovAdi*crgjW4bIm}+c`qe{Nj$?qEm+Ll-~t=g7aRm}%@1nW#Rw)NJ{uSnK^O?-!9 z?GBkr*R}$MTJFGYJX#Y(iICT@!*GTtZ#p~_2SXIx{Kby{I5b%2F zT(*4y5vt?LR9yy8-YQwParwj5^l1Os=P4tQhak(3r~cXzYnRO;Cz~>rc7qPI zDjc-B2ud(UE2h4as~!~NFY#RouV630UM{JQ)}~Ol6`8@9c|HDBXgGrUtGMb9bF~VU z-O%rdXkEB zWt!@17QhiD{+I1-r3R)PH+T1j*X-T5_uW@&QxJ>l*!GtXwClhr!!wFV1o6S7SvzR@ zgw`GH9h>1GZ4QMfg|eg(C7(FIO4F$6vm6(2D+TTpZGfy5Sti!zz%TWcInFZ3hJKCB% zW97rg!aQXa*d8@uj(pUj4*mqB8K=KcpySo_+aVq#sadK;jjsAaMPmGPWe#`=jE9h7 zbjg4FSW{7}s}OCd9PucheMptZPp`=UCKp?m3`5;-S?}`-1kiFq#Sw~=kh);S=m~?k zcK2}BTV4*T$z~=gHO!sxE6>6G*KB~_F^fw0Vz>%+Nl9*!_b$QoK#v z@cZzIc{BZEKQ6aATMEvD2j)L*Zia|0Nx=+b7C0usdr|@c@Y!vI_)B6ueGn+NWheBk zDCtIn*hOVHy3VtoAVLEGYO@@^M*-P=d>9bwjfhcST+jIch(?xd&~8?N4(FrkNHm#|^=3~YA9=Vyl4F8F)E{Rtzr9!W;sfLEICF)&RkRU6RSxa2%_B+i^JHK94+U%=q;)>01Ao=-T?j5hL4?E2oThpYbSY4$f#5d^rV7|-p zr|lD?@F_GByC$l}-?8WJQ7KII%O#mycpJjB|Ck+ReIS2P zGRs;=^X}bJREomzq#DbNr9|xqz_XKu<{&y_0C`W!hbW}c7yU!H#bZp`2k!9@w!NQ5 z3lgK!7pY|zQ&VSVQkRTy#UBnyXE-?_Yu)H#vb4X(gLG-e4Z=Up{ew-XQSFW%Z8UXpXs1uP4zxF-+0rdplk z0e2RKfjp+xaR8`XV(t%bQDGWpaU48mn#Aof6@7@L`S>3Zvu0TR7%5UTiOPW<6Y*|8 z$eh9wnEU6h#CpnK8CpZ&v=ZUKqIFA^+o@FxOU;OGQjI#0R74*Szyl1dm{)FV4Sq@| zDvO3}Rdw=*jsB)bYI6mar1eK;IZYZm(#{tnI-D{C93i$nqFP$I61QBj_<=)_{17#6 zQ%vb7$Z0ZtOZKm@j`{E4K;7(^y;D=zc;3YBjMOGxhC9-Vd(!P-Q8lX~+WX-4@=)DB zB7@$6_P;b`_f0(y$DguF?Mfq$;l@;IZQk_&HJK%Jr0`IiLZRCD5b_@J@%0L9t-XzF zrvMk;Rt%EEz-@4ZLV5>pVWB2b5YY`)PV2;A@4i>Fc2Ul6WSQd0ecWWLoD${oc5p~E zmK9f~vWM1BUrSC6lkMQ%1y^pftL{tCMXV2kx09tu@uo;<@3d2U{m*%y00QCEs%(x4 zS{}7JN$cg_-~)3lwNZ$Byc3ftwgWPFZ(;S+W!RHp5*A%!|65O&7s0rENt@~W?qfX4 z0IL@uFJcf^c2)=)6fs{N&m&)mOs5f%elvm|muKhb3CeIHYy>;e-MLlmAl8}=SUC*aH{ROHCnF*T-or(AHv5Dhxq$79Spb8aJ#*RJ1 zn4e6`N_=!DCmgBNCPiejYqHRTt5P{B|6EGqj_6bjaeJu(<}fs-iJ13Jm=cZ1TH5qy znY5yb8qutga7qV{A{2L_k*zw?1)s}_1wbCn9kD~|#&A54BKUD**w z;ff$Ts<^))i3)D>_ZpfG00jj_h?JNZ zR8mw3yd3tqZzvjfX{a>GaurW5Tq`ZU6OkDFjQ1^VB4M4{Yo?>k@1Njx@*0Aoyv`Pw| zG&-mtUBE9nnR&CN!+`}N3ui0AJ(a(entCg`SU7OQ2DPOJAWUW*wM1>SD&Xx69>iY2m;Jy}H4=y_Z95L!XwObn2O;J_YU(;|BmHOOT;>{gujBZ8+fdG(1_`% z%vi}srgshwQ=_68Nmej;do>#rn!)o1Yhx}~8tqhipq>TR{jwFR;;>ZPP! zVf~mq!~}}g&;1bS445^F1v~DK7koaD3W<$v0{KlOnpkRu340oBmo1#5IjxO{sN?{L z^7wmxc*_CU#xU39B5ExKlecZ{${(=P8S5Hg)Y;ZsNRHojasYy6XG)VeB>pzBA%*~02=ogHiaURE0|w8h~SlPE&M3Toe#9 z0s-uM)Aych3T`bGDGgPvJ}>7-)cZ5PHq|m6vrStZ+lcfBOHA9o2c}ALjGdH+lR-$} z!?}XMJX4HApWP+_JR)K7zWlcBbF9*-&m+I*P-gJEwDrgv@*S z*tiW85u2A@OX__unWG8968M^?YF_A&%+DG~ZpyTc^v4 zzTudB3SsNGE!%Yb6E52wJgxz*3%MToRaa^i1BRYGfb`Bz~ zX|bac#*CMGDtt6?bd&lWWr`z?jOUeLq(xCRW80c}8^#O34|ul5X}=u|w5|EHa&G_! zVRCy}1fEtCme#B`qI~=&)vC2AQ8ut?+t~mKJ3%GqBzZAzmlQXZ9&hKDiG*-yFAvkZ zB2!cwy+Mxr*3r@NKLh7VcZMdu z7v|2y5kKYxYls}GNZVMZ41su%1*w1i462wXjVz;&tL6~C@d7Yot<=JV1VO}JtU%E*<+ zMYrGh^yC-F&#x&!YRwF@_zu%Krz2^)Z%f{jx>riOD%;nMPASA zjbK%-mop`C9u-G2al_@UPEdB?ApVYM|)HO{HBTa`K!zdfAEawy% z%U4&&<0yt@NtsNW&F0$ra?xxyhmtXE2@W6#M@b??qEsSyqOvelDosa|QJN(R&WF0L z>tU$tx*opF4+6v>@cl3V2tvP{t&csAG5|(BZ@fM`m^PZ8X*!w~8G0l&$27gBnjMsB zqX9qxC^rwMEn#ox? z%i^+{m6K^KU9C|sihL7h^>o3bQAMv-#ntYq6ltTQ&~Z%)H-YPfFO_8Dv14n@O= zIX4ahAE!|;-OI<4hGF(;#)C#92m!*d(eydxBJOnK1VAO7Zp_(lMMqbHfZcEwuD=0b z4wU+TWKo2jlP6A`#3bI@P!0J60HR?wn}&f1_xP=WaSz#`J6Z1GnJf4K2kg zMBB{ECnFFda;b|I0U!-n71jAJ%C1+d1QW2RjH)A!!V?PHd>8~x$k z(l~Cj|3z23QwyzEUT2|w_VfS!B@31 zE&8{9>}5LWFXxZzh!(gSdB}K z?_FAY`K3#Q5KhPy`RPIONk%5*cJh7_QDu1?SrDX3E2J)wznrP05A!0=@+{3#nM$EV z9L14#kddfaxu}zRQDNUqQ4?&IGA*fB;19h|&_f#Pc0GwVtrpPded0K>ubxgEsj zRB!MY>j!9~iJG)bO~Q5KViAo;qj9)c8UrGXi#i;SM&oEvi~%NgFG|ynE~VZ{hjGtV zU3W>l7Z2CGRT|v^0w72z&waD$U4gfGN z>S#0?jibLj=K&xuaOG51)45K4g&q_sRxVSQP(}J&>G%Oa;CI^358D28;!k z{PqF54#;{!J!f4?dL$<#R9UU`9cq^4g|z+>CQ25vtV>mX_t@)?Db`&|_Ji}_2S3;>m=8Mfdu*(8MD%&tAi(xNoa>_Vbq z)Q-(!jTw=^Ur;41%w}t}I~Z8jrVi#t7$CS;>2O{L&~NsGp%few#s-$512h_gVf($t zNt65OaOi>lV$jd&@TQh&S`c#dS1|M_+HeAW7ieyx{li+qZovN-NvH#wYs;&fpabZq=7ITo+wtr zURNmqsRL*lV4So&VYA;8pKnH?4u;|MRv;sckSou=C-)&EI&nxyNLa^N<*O=-`%q=E zAD5LR&ph+YGr#$r?|kPw@IdRUA3gl()>l5yWsc9mGTquh3BNa^-GOrf_lPBjT;Y0Oh)QN&3uPtyA|EWG*6kHH>VrLKl9Xm;I zKRSyu%u546LtW(Z z(~!(C49=Ntn3MwWwr7~=GX}t$y?z&v#&M7&iNysX2cXOV2n^E{0G2KhqzhLFP-X%G2MhoWO$R9r z2BvB1hJ#cJiH0EngdGOBN09><6by<$xort#I#SN4)HHthBTb5y35JXe6T#AS1VF(# zV>+TUGHuJWjFzc`VYrU2+rA$Ju4l5Q-B4=KlX~20HIO1hbZkV5+-S5rzUKQ0b{Y*` z>Yf`00oOI#u_U6aMV_)e2p9`2OVdJy82h0VuB|**BoYOeD5Y%~zJv~CI)Kgv2LuG* zR721i1wa5nh$PyTUxn|&Go(cdQjrtn9J!A?j}WlevU;+0VZ$X6n`m+>7xKZbg-TSR z*+S@P$$6F3C1|`Hp?q0y`udPXwHv%yL<=122G|AtQ3l#j%&z4dQY#U8vdAj1bMLdQpIH zF`7oToOM-NViC~MjG^)ub(u&warnPGrU^oDZW!8rrz0d#3g?@;hA{DVJd4`T4FSSC zFZczOF+lf>!G%EI+d**u#0B^na6RYndRGcW(9R5oQUeBH+ZO!m0bFy$LL< zq-?X5MImb0T!viI3fE<;5|QbZmUDPRbnFxH`-z|L#hj?s)oX)mS65ZyYt8i%lejTa zQKU_T?>9S9q*XGGJL2r}3c~C5R*#V$JLvWJ>#m`3-0e0SuG4Jv+d;riz;t>WFYQDC zuE3{>Pv+z_xr;oHyqdfzj-e-A`?Exm*EIF)dJBJNRL<(zbQ6*4ygGD|@)QLH74jo7 ztn_jQMJ_cezMZn(7CDVU_Vnxg<>Pq)AK{i2_>_8uY8cXS=;g(9+V2BiQ?9QoWh3Vl zj%HcFtP`B?9ew1zVq@d@v883oH#d$QTV6slWGozad$waz&(qv6SXrLm;Pm^$zG>P{ zx7!~$wtc}c4Qa)OX-YF5>Vj#yU>Z1~ZBuX@A=<6nW!yXbSKsURR!?3#^L^KyXxOx^ z(n3|1t84TFD~+a*!{O>mv+;erpi9q3;d%Z3C=@&>S65ZTIQ+GqZ5u|b*=gIhrZ*eC z9%Ix~!xMMkbK->e$-^IkZl_q9OqPmH7j7LM zKX&scy%Q(yx%&hmK**KffQ#^BX1wZZBDkMoFx@lBVe>({|ILV*>!H#5DUy zOv}&_Jh#`|;AuJ>QfWh@Q55TMnRy;#h7LzZ8GvaZbi1Vv5QU3G@GuNUs{m278%I&6 zO`R}6NRsh*L*;p|k7$`1Mv>z>$C3nac}#;)%9Id77zwUih982<#3d1FlAMrw7)Mg9 zf~>N%$oFtq4dZH94dd}pNYRC1khp;Xd@>9=;jLfk1R;F#@WKCsI}iUZ>D4U^I!`6t zFuLQ8DC{QcmRp{8%PqeGVc1QQZWsct>?5?(rCL=|X&)*t>f}wzm%NI+$9Lvt;Pcy6mvK3-$GMu?gL=FUuB&D-Q`Q-cCfEfP ziB!ayX_-}-PmaADK5H4h+>1ipPL)+^pLI*?-*> z+gw$C>5JZ<+2Kmu`>)0~9ec@-3K4D0#?KH*&X9BD9`XwEK|CE&2m^ol715W2>AUY%X1wM~F&!rn&IL9~(fE2=G7N zc_#p98bIP}z~5fQXx`|3UAGXv_6o!5um5ysGC8uf@$jknX|bQU3MG%s{4-pJ_cF7p zW0{X$EM~;~+OLbcL)d1u0`KJQTib|Lb#tAj0Qq?L+5%XDv`FD-2^mI`y# zXt&2jr=!8m!^4a3>coLu)qCOngizvMc^3W^E)f}1E+C-{VzxR|5f%`$;u}Ji^|RYs z_dQb}7Ot@&B^7?&`F~*`Six^`}JAr*SJ;1djbS45bqrSH-8x4BBr4W@uupNGZ zHVjnCmD+Nv4bW~aYnr1JKIMQ-DQCXVIHlL3N+?Yf`o-4wNSowjmpnnpI6(=KPOlZH z2yk^<)f^8%8&|5a;J}A_GLO9kg;&dj9ENbgoW6K58nhXU^E_sZaW5VEoZX4d24cgK z+MOE7EjADvUvSK<_n>R!b+`*sGj*QtZ$0fe$9OR|-L4Q##HFPpdrM0Iv?)aQVa9`i zGsYZ;u|*TH*+5O2ZETuS!$uRo4uSn@eV5U~n{88*nlvq`f#ZU>o3>1BHeF3$?REjW z-Bn%l8cmb~|0q90TI2}1nb=Tt%n6WgZ%!E}YEk!oyHqTTs{KW`=&O38XR?gqsIrt) zJ@na~#142qK%DgZNern%?|auiJ5>t42Rmkvwy%Qs+(G1TOl)j;0N#`RLHp*%ePtN2 z2d{DpX7)EtW77lhCPO)=7|c;2PT>E+MH0tZPTi#3MB8Ey%0i8NSr)8_a#k=D_hvvB z;Qzs3usInFAf1d;2xsYmrnk59>7dZ~}!TrkR|7))XAirtGR)A>~PRL<}urx%C zg5yMRpAd&1bm8(>+;K3p7KbWM;65UViKUNHQjj&hJeI{}m30yHW*pL6SA$1XVwte* z;<}8pswm^Eipw~w&YgQx+3&;hxpQxN)46{CpU$0o)0@hE|5fw(d=AkM|L1jYzWeSs z|8QsdJ8!=G?&Z$%cYgTIci;Vzvb^qxf0%GWt~~3L%W_DEOvwpy8zG^OYBDW^joqP7Wix^A0NnzpW2rVysBQ~9sj{#kFF z`S)`Cm>UfOe|>Iw-xJ4u&V`-y=C(VCWAHuG0Ctj@rgws!WMCSeZp* z63~C!D0y?J5(r&|pEODiiAo94h`e$cx8X98Bq68B8S;nZPsy|7p9!gBiukf0r@Nw( z7C=)oX>~Fku#vKpC;bzXSw;8PGTLb%;|ii^v&uhX>i(@mrZSOA#Pk60QgH@dDRXdl zc-iw%NTDJs_0IZ41($}FNAJ>fy(kwW)3Fllm{qe~Qf*it8P}Vj>Y@(^4dzwOzy13N z-{G8d&fxQ2v+2mH0u;I~3TXl5$OW2?5D%}Lh>W?8J(zAwpHm@t&sclwFy=}} z52XOsjRofxFlKpijJD-Ef>~78fl>-4#pWS0`luVx8BYfSFlu#t$FXf!1Ismp?%0A0 zl(N~>m0_4fhLOjk&9v8brF24szz-T5ZQA(oo>P9>0;H64aV>==`}mCXu3U!C!euff z2jl{I`RJmwQqs%pMszg-xBSVppw3Qo+b1K}eZtTW&u>upkJ#uK^AWgCy7ue4vPC;Q0YU-fs)Ixz%oUJMC6`X*xY|ert;@ z7Uvj0F`X{`g=r%&Mj1v?gl*;6`WmCN_hWxB;@q}vKW!lO<4zbp&Hz|Tg?oMoz&QA( zAA~;OXmz|1g@h2obDEu#o5(B4mqy-TZ~~*G&So6-LA64yir0COSAB3*Ix*>YMN%ya zQo5H$p~TYg@k`|4N@}`Ii!cXD(%LmI@=e?e;P2g4UKe7_SUanMOV08_0eruyJfF=r z);!lW4CBGI+_pKD!i|KGk!`g&mC zLPmC@sWkb~X0sV0BIjYWzV_hFBoZmL*tQ`XHt;=KtrxZ>sFb#O$j0WJyO%%6wqqe= zs0+@8=Z)f44`bp1yo9)=l}5mtXih=f3oZ= zJ4*#Zp6~9B#&D~z>3ASyze21CAw&{#EE@!oZ zWGz8Mh?i9s%XwjGKIh(U}rJ&n|kN5e7JQjw} zD=eekF^tQ$({%<(3=qYGVHm-t&N!ri6Td1m+*dRuSCcz5s9vFfDrKlr)fy4r*B455rb3if$g-cB59iSZcRm zw-LR`ICb(N&2bZlKiJoUI0|)L)1xRHxPo)(I_?j(i3(nuu;AF9T8{155ua-?PG>h1 z4bO|?{*iWTd8rjLY5o#i0K0zR;6QmV=AsoyUDM(yigZo0h3mMk5aRWL-);p#5VYEU z;2vL{=NfDq+D%X8XIs4}ruk-60)jnsVIb8Zi}i?DEtJ~SCZxz@Vud`|Cb-pBmZ(AG zC(OO-G4$7k;7%_H15MMkFbD&!>)4L?wov$L@RA_ef<|*ZZZ-j0&HM%k!%ou=`0e6i zp9dSh2jKaQ=JOvTG(*d_tuU}H%MR{zZAVyA>OmNWQq!bw3BesW1-27?W@6(_Fm5&g z8qIOuY;N_!5WsQO_=RHW-S`Xey=K$%06eeR^n7r^vck}^;IW*P&$%r!C1=UQUWvuy zJXXR~rnDjpq$3?S3Sv21TP_Am;U9>hhh!ovtJg76!qN8=g%1h7Syc-F!CbJ8?j2be zXtyN;nCu_yBQh4C7d2G>!Lug%eJQqYyx|xC7YU$S9jh1Bss%JsU+>$)53n|8763Rd zI*j+3?Z9yg9bNYUAn>?gbY0p3T*n4d3lQU&dY07?ega&z_+>bN%cO;K4$3%-Gn1HR zRb6CNIVN>s(=vvG2jrcfvDYYvyYH44KIyDd4iCU{zGht1Z$<%k|ET_2Uts$e0asC&!DP{dGlAxV?>F(v!z2J${lRJ$;g~lc(wPCF~bz20t-78i>M)Pvc5Awo#E3Rk%9Q}^F5-B+_{Lo9uCAK4BS)jN*T3Nm2O*BS8?z(rwna2Tu3V1Y5f6wW9Ws!SZf%p4gg_Bhc$9ru?7@5! zlq{+&mPIX#x85`XudMg~2B^?UTa#q$xkCX`htlCoOURi_85-9@#Hn{K@h7n!kH-x&O$!=JWad zT|bCNy>m_o?!ZMdA$OC{eQ+y&F)+IF9L^JgVKSB!C3i*_4MdTKbTz3l^}u>TPBx3i z65V|YJ*5urP&b{9ubLP8rDO$pr+K`8kRaiT1Qg-Y@^m&?ZXi(HC#S%TyaSXldFqx(~B4>=pOSAcWJfdK(8fN!49tO>3 z=*6DrTK#TAlg&n(B4d&Z?!>W5Y#T7m26;mzVHjGrX{v@oq)exb4$6jQvfrap@F*y| zUCvr+82}*cbSIpt;c%2C2?9Vv731MB`cwu007nLcK_tB;r6NG8EhQ~oFN%GWCo3!Y zjSbfY@ZH3BT|H^3R?DXFoh41-n{M@hfiaxKooR+0!AAu`H2=j*;6CoMvN zSXX`({uQ1fj}yZ4VwxAaYi&NA4On0lgvCy#S&slG9PTJHo=oROUeroRVay2@^(1N+ z`LukybfwW@&vM>JKA{Q;a8Tk>_WTIpe3#pEa_~AHJqt1)^(l9KL74nS9I8riEb)x(^UoQm=e1CT` z>3O;tEFIvLQ@#9rB=)>#13QrTt0R5b&9Dz~1m|N8jvrXh<8d?XKI6-P&C1@L#-* zq-UYKsXO*tuA7dyMSk)Y8qYNx|D+>%uD-duGyN(L)}od&Ez3$;(OSSyPoMK!N7A>&!Okij5cK_4=8 zrD^DTo(CX0O=vb0>}#L?UxSpfEg+dD-44Y_f#uK>Cjp{xMM_N%eAfZc)GaojQ${UB zi?XX9k{vD}A7KLrg4q<;RPdq*eGf-rFiNSeiKj3MDGeih`+2t!*iLjxsU+DDn#?;! zXc@wE`vB_=DF7S_pc@Tehue@p79r)=3W$tE*9`%CO%S59gbA?YE5PwPVL`~1e?bE8 zCd*`poFVs;N6EVh35O#L5|uV<%wP=khUPGp#T6;=MxxkiX%rB!Z%YcPD$BB&@0?x6 zqEvB_7mISHsxPN~5lt6aE?r@3mQft3s4n9yp75&w1I!=Z5chix1vrF2Hvq!~8jbo% zgns{oY1wY4qZFb&-p6LE*+eh`XKdS0wscL`TTNZlwbq*?vyf71aLI25E!rOej79*X zXS?H(=K|-dZP_#jy1j?gwtJ9r#2{GOaDCG-1Kn>nY#XjF3$Df9>kgFX0(RQHS)(Ceez3Y~TW!s>cw(B_sN5-Xgk~czmR+RI z*2YG=1Gu?))x-sG9=P$wy3=SNcy1$g+@Lyh_3iM_I391+wJn6Rxv}2s0Tji~#xQkV z18tj|QM9}?ziM+6Ic(8Sz-4k~3?d*S-6~2?%CNvj2lw45@+z{Hn(8*4ypWFPaUzjX z249tiq3gEQa{Yjb{$Ml;!_jEa7cB7ImSyX@VMq?1keb0bE%FPu6b0qX(4_EycWleH zq0#OnT-PlDh=2%)AS_+yNvGWa+qP`gm`736FswWFjw0^u-Dw$(D2nC{Mdq3}+rIKF zmT(ETADtz4lE-Gdpd740qGXNqXLZCOzewsDfaGO4r;^)9l#o0(#D$A`Q4ZXGU|npv zyxi|UNW$w3-KiI6&et{Kb>T@aI$d2CxUq57qY6M-nhv0A*4s>7*LAZ2(16e3WOCx_ zjSa+&jjP)oz=hij1Nak-3&Ax7pq{I7A-JXh6g1#So&#=dTy;~qn*s=cFh0Jz1{Ej; zLYk%&6Cq7g3Q!6@d8AlETq=$nSz1ESpgU2W?yw<*CWSyhKp`|K1o{CILKtCJF2jGq zW#W^J+(%wRNSMy%0;9C7F4I&%8my9T5IxkY%emODM0XCjiRJQ#)+pq@*Jyg44e1&ho}ZF=2m9sNaR3}A z{$*?06?eR))7XwzxbyJG@4WL1K>pX6g98ZSA=fX%Yhrop8F$4e^$ev{wMKMrjLfQY zm2;;`R1JJ?&o?2LLIuOY1~BtP#aQ%V+)F(Vr1Av5`k;g0J=fGU=cHsvy_>Z`=+I?M9}YaEsOP-t{cB&ML*^+ z7JSo?f;R~v1PQtFXYgA192t=t38{qyL#+|5LSBW7dRBAJAxU$z;d1R&@{2T-V`nW? zxv1yUNh9d0k%ymXioAF}GR7IwYpq@8t@idB&3H}IeSb76Ei-X!_J0wm2-9qwcO^H# z=K{bya41rP3aKM5^4#W(#UC}>oleU^u;3{V06`D(d}A|-0T~P4OPTM_lY}$SAIVa* z032}aeV0;zR%@@_YED>N)S<~X_AD>koZeW<UMxF4bN>xaip*s~z6HzgjSdI|tAR zMyvNUmzqoOOcPL%!MN4v1)*tK34oM(>~rCD2Vns38uVRpWQ9?f1LF9PFz_|a_mFdL zf8_8|x}E#G>nppkSl+I2k`0mam6VzAUBi8$!p2`$S258kzXT!Oa23NNMHrF;A*%4_rg2j zPNwte zq+DiAXYph@iRGl6u6Y?(lW985;M3Y-ItwT>LOHMU zawem=%&WXy$S5wWI*ap60P+%XS*bjmreZYaUXn=4nG#uA%vwaNIFQY%tg^UIv7}7) zq1@K0L;(tlIzJaWAzg#AMKL2_S@^nrQ%98i167>ZS>!jyKD;HBAFeXHFY<7nqjLAN^5qSChKVIZ{(d z$qds3uuPpvDUNH>GyzOgYAJF~HH|ZdOPVwdMAHrn*jdR&mTg(% zY-Oidf;^L^z%cV`7l5Wi!a-ZG0M&V)x7W<^zH?`(05v&ra#H~o#qJYp2M6ox2M23s z9RN*oHs&mj8Rsm9gmL9C4ncr|k6RXt61VNqFd1h;AQ-wt;Y-t$z75oF00b_hn&1F3 zVHz998USj6Mv+TFnd34l1*fP7Ok>P(8P)h0I2*?r0BUZiG3Kn9nP1B}Am~zAbq}9r zj5EddH!AL9w($h}8xUmZU@0$u>D4=g33kb>v;`M)V~@#&gH?zN>-r zYjRcwZAwN`WknWe#e5m~|6YZvOPOr~X~E0li1)~9;tE@?kwZ=C`nAoaS`Ewmt~x1Y zHvaT%A2%jmB}p*S zvLdu?+YX(Q!PIlfgEd!00i%8#c)x)(NB}+0({xP(yM-7b~nTdPOQgEeay72%+({D#5F zJ(2vlpmBvvlzRj-Z zMJ8N0jXT}yu{h6u5@HuHa^W#fx$ZOIT!Rj$Op6e>kiXw6JYO6bhO@-Mqag>zOoVl~ zCFHsjS{7i>wSf8z4Z3tdLy9dESwI08X99sq4QNR5(}($(F?}1&jXV>8eR*u%q#=Sw zeFokg5rP*YxIY`A8=*VFHhKo7fNhL4M0kDUJkGbcLIQi30c%TybsdEXVB292!K9P{ zKcMiyT>unlky8K)w(a-~xM@aQaG!gOgVXNk8c=+k+K>X^qd6y$j9g-rr~I6_ zWJFGoTgXG?G4dpNE%`7Z<6M^03fIGU;T188;h#Jlq4yGtb1Mdj zKh|L0KMo(Kn?W3fHlS~rCg4Wk`+)_%WtniQ4W_|m;28#F?Q58($x$DrZm_k{Xf(Pe zkXavP6zR*4iP2|Ha}~L6v*mdJj?-$|_FqGz0SKZJfc-xGIRo+o?cWOkJvBks8Phbs z0FmmT>6B?&xHWUJ%M8PNk=7p~Xtz9VngICp(}C=0KLpyc{GzU-=l6%6S1Q!Hy5|i# zK^O)dDF_fkrbys=ay=n+5lJD_0^i{T9)nMjZ;PAHs(>IvZctUi??oH{-sXQrv8X1~ zzY60h>xUu4NoOSt9LlXUyQUrv0sDi3ixGvT6}D^Kxzg(+p4Mg8_W_QqC5geP-|Jp~ zY?$I}rp?ApCAuy)8!L-MLAP64&T6*{5Qb}0-xmm4s}Cc2mO>azb^}16Y0&^6iiW0n zkmpe3r{98TJIK5Ih};Jlb^4yjXR(W_&vgvg!1(thd4u^TXbF&EAa)eKC9pHk_+6WE ztWnfWs}Q!ZTzxDU6tZrR@0XaVV|e)ui%c&GN^-)F#zIQ-@}6U5|6 z3kD~bSKL##v#BsiFzuyr-z{6)2%XL*CJCzM*W3+E62v4yLIhdAav9zam&s9b-Lpr7|Sto=?p*hwCxzz_QAyu*f%Ie>d4T5^+%%dR6B%=|i67avrtAE9TGP z#wS2nKvxlhy}BUMTsxT;=b0&H<*XcC=79N>IRLUmPf?MTv3jv#$n()j>ZvCxNaDP4bue2wI~`!=(vEQLReqF=Js+1V3=7(O~bYTblo&Lq{Hv$ z+%UZqX=H#f4P66tUC%Hy}pYe?l~fbG|lyg zfO7D=-EPPGMO3QQ)C`0uRLT-k!cR_>S{VjDfb03b)IdsCcf2TaT>#s5<1nDW(6%f) z2}4U~+zb&AbS)B;0i{xydbc+o4_-qNbVD~Nt&4280!kV_o*Px!KG0+yToW={)~bAV z^}_12p2!FH*u59;z4HZ)J7M|KrK?OX9fv;!D~I2@^G^H88FsFG6KC)ha++L2&XEVn z^T>&RQk`^bmMr^y$|50bBtA16OcewF+V`91PS8{G6E@V-cS)vwoDT`9pi&Dudu9YmR zcy5ENQu!uSrOe8_5Y6`iwG^@_d@%KHR%cKJ^HvwuBz&L#I+S(edmjJj0b4JSzTw7a%(~uoJ@Y7~u z!ucD|-zaW4DPHZr5OD_|IR6s;h1*|buVO;5Yd=^%`V;_^iz7#FSRRd5&iT)kl)`iF zgx4`4*!_3qcRluUhH%G=1KUorEMh(!uMy*H1AgaL%51z3sRKd?0S?9cnE`MYwM=#| zQj6YBsRNvI1`gsK)IxeMwJiF(*Ijor!lc|^0NjU&cn8k!dU%sD@UFhmz4k}}UpnzH z{JdqE7jC}ooH%z?$A=lfgTUBBx4jx)v3G<4u*E_kETXG!NcL}8J%4weUw7O3g<$uy z6yT0~834QYUP}Vpbw1hKI~50jPuvfXeEtRiKtO^dymA@743~*dMub2nq>yo<5^kHm zFDvnK1q09?s|>FCqarA5XYn^hvjq=-+3^kA(0P}w>rg%mw?VsI{B0guf4v-j;L*ch z0o}0Qvu^cOmEXp({tPa|r-(z^WQkOS=+68_&3?uk7yb~hk|II4s1s#tl6v$k69T%u zS$VYCxck(p4Bi&EUv$$=Y1m57oqMs{5Jx7P!;PX^I8l#Tk6w3O*6wA;4lcaC)jB#W zdtDHtQ>X9wnRb|+yXi%p_{HbXr~j3&52w>3vKcvBi}&@~+4W~1GuegX$1_5RRwW>~ zjc?wuOb!SEmB|s4LWYZarWUnm2CqW6s26IX5)~FS&+^8Np{-~7oxHJvH@N23 z=H}M0*X#AyH}_VSc7J?4oNpajT|KfjABGoAeS60*Me0ObacRo$Cem~#Z z+}z6h{S0pUcj$IBX#)nZx&ntk>@{F{85$nkodWjz21gQe^YMjHCMqr$j0rmoHz!x^ zuC2R`{zx@|4ucRd&F1i$d6puynk$Dth<4vWbow^l4o=^JiJm(id9Pd1?mo_SZT!6; zylS$EkY(EuK%BqgcIF4-q1$W`PlxtDx^e1v?0 ze42cod_VbN@-^}kYUjP6E^3@*<;;h9Ecd8}?#L`I z>wC5AQZSj+ciE!h1Yi5wqMkNJ0Q=!)!8+VB2EeXD6!p|15^A=)T;x@e#U(GRY@Ed< z^;PXtS@^>y469+x*=e=vEG`uT9=DjkG**xEnHKwCpY^jo>wPcl^Uw8o@6~6cB@RHVPj!D(10A1#lf6V`grN|i2@pLPA>!uMD7@K1=8nsQ}HiUuF@`@H1Y5%T}%-|ISpE7kT!ZHy+ue z7{`%hOb9Lji(+p+902HA6s4iU&tt&%oCw zn>SaTE;zR2nr=Jc(QyvY=~SI;)M|reMV(HkJJh7_Ew>s;Yk6fgi({z)r7P|Bx)TJt z4&Cnh`sQ_OYlISVKIbeBn6J&i#1ig_6Y$-!-Wv#%u zc||VMX`1D9tPta#I4wol1dRaw)0crsK4Q zU=HV?Ylg-x3KD>sW*GS%1JK*;(4>ecrIB!oKybA5MW3*!O$cO!oPsPa@87#Ft8A-j zQA)UYaML|E9ZV*t>~oLYe)}WmoRgEu<@TZtmo8s^!DKM`<~JvU$qNp@d2oO?9T|8L zUfRyQss&+Hxr|3{(Y4fQWfjb&&ySrgOT@A~d);)O>tIkcTdii1vvQc7zr)sbU1w#x z4!ji0`PsAc62Je(CQc@2&P*ow8waqqdhFQh8gyZaZ5bmzA>a@FA+0khwDi!=zi@;i6{KSI8Td>{Eb`4#eenO zXN!8FD)$Gu!mBd+XqTm#pr9GRz?Y?jBWzqNif1ZOsZ3=K$g@$Rk}}R^p5?KSxw@y% zvY*ri#msyY7L^Bt604w54iPiNEbt|rnU#|%XN`pm&{Ktz7HHTpl@@s&gI@0tvc@Wt zGEA2ik-*H0&&ru9l6cP))-INN|MMDM!sTH3ABwS`pwj(V>uE>0;6n&e+J>BJkxl$K` zyO!y?oKhK3%cLGx)s9{FUDwrhiilj8QfdG~wA}XM`0-uATL8a6K)-5fl$e%=$Y>Zi zmd`kV)I>t5tGk}-Yuetw7s{lAmPLmecU@BtxDdK@nc%JtfQ?3@<9`45yPZa(0dNhX zrBe#L$z3S{sqRxs4NWvmMw#H$65{Xv52Bp;3CqfF#0x3QA%pi#Y z;$$#LVt_aqJSDhg0C2%wX92(r&(kRYbh>8@-#0j55SS(adprmc08sNdXCuo5)$aBtWuPH583SA2=fmU#|2bL%LDX$i@9FoFF;7m6i88Oh5_&+rVxyqrePU6pzk}0M2g&&Qh;e_ zZI@}nlbo5H>V~1~fni0$A6ZI?v z%>vGBq#C6x7!D(yF#xcT0vKR$(;Wu79%;zIVqEiu##}C%VTeiyg<;s_;*jfxZg`%q zY{?zRV@zYd?_0p79s~gl`-$#(hGFX5Rvl&f|3tt!SibL5-GOccI8f*fKbypZVVnRY z@o*3)KjZ{~l*;J<3eTsMG0znX%2^odphqz)0c_9Hbgp@x+XnzcbEJq&00fsKfDR~y zXBsU4KuYPT({a6aClm6^wx)q;xDDT@-1P#^j>i!)DmfxWSReSkPUAobfT1r1fH0z= z)eHLT2mnk-}t3_S>4k1^kGz^g`%D`jW2d-$X1*pAK_rJAN0rtuZ9ov35m zy6^(V+?MabzjDe@m|RLgO_L`K)6g`HQpR=1c5nrx5T-yzxzscyl#nZbjIV_+5}#z` zBq8HSPDK`2-7A;?i%mm4&%i#rS|lZlG#ypRv=MyCw!_G_Z958W`_P<$%U*Rb`p~Tx zX0w6|yWhL!%)4HZ=Z=$&TPx$M`u#L}joiR&?1VeGi{MBZCo7uX>Gh%r&~aO>G+WO5 zJL8e>V;>On_~pzeo8$;NL+&OoCm$e8Y++-dBOwE;Lla9JmMOu*z#-F%@*gvE9T@U}u{4Ow^F`dD?zJs&mz@` zXvK+2N>@Hp>87RDoSM~@T~9`(@}gQ)d9jH4L~>A%f$)_s=U@R?jM>sy0m>ZBvZcc) z*Z}s!V5#=w!^`l`UP zese%=2V=;nyf&vkIUQSQ2+bwVzRLh!J2N0)+VbP+Df z+uKNYkKFVR zzC-C+U|SHohT{Ob?sU};VD#VnbI-%A`yEKrt*sNMx3-1@81(C{Yff*~!yz2*(e0gE z&h73}+}^(R?nT{)i4hwKycicdMrtLCI;vZvF7`p*$R%U>+9QvA?Q83;@Z!b!+2+R| zd8B!Ee(_@1TL0SD{`irHzxK8DW_a;pdA9YjhaYKOH@|o>Y_5OpYr5=6zw)c_@0g3= zfxcuWQ_kV(O)e4UZlP8ZptPZ;`B>A}ye4Z{XV12)#`V`eXEb{g&tCiV(-4ZsI(*w} zUNdT#XV12(=JnU&S9ass-$j($S4pKaQHsxTzZkcby2D z&9${wGjbiF8+!BKa5S##@d&36b{x3GAL~W75Ex(Qx}FeLf8!u$KsQ_c2!*g++YT(o zU9>Gk%SM+oE3j?%H|y~jU_7qt(HLMns=0}g{K5j*S=x^QxB3Mnj|$Z{TihX(hSlmF z_e6>St^|;FE1NR5FtqB(z~KY=A~fp7CQ5BO7R57Qn!azM%jtbA0S)>r@Eg+MZ|Gktc*{S?;78x|VHi+Lr6tt`Gv;L*1xp`u7*z%kKXt z2}-4RYDjh5;zy6Bflg5~HO``k zt`&Ga8Oq{DeGtp#rw^qUVo&v#Lc&K6-{)HvbbCan2ll#Pnf_-D%hE^5lCD!9-i&4# zy`b9(28OQNnvS|rs0=Pzmj9N`xQpz!1g3TPubP&{xnZuHOOw5z)Ak2aLtV3V(;UYc zK1-i}!He*2@&qB^px=-}X2LgHq%{jV&OtS=EIaXbFIW^DnHRZS1>NGAY*EdtMnOFm z?s*9k6|R3Fpr&|n+10)FXw-Mk1>v9vQb0BuXGWsp&w9ScrDeJerA%pCc4+F6ZCOI| zJ@?(NVF=qaZSHxdJ%@f8d#)JAyVP-9O$vOa^j!TSyvw3_G(I?g{;F?eqoYRv&fRqW ze4-Rk%Bc;y?m6xDaBERD9Hm-W60LXJE!$!Y92fr7P(@l4}$N*C-s{*^5EK z2}vbNNq>)?{K`{b$+p8DoP9qlAitbH3Fn?PUrh6d1&V!ow;y;Xl_@;8lXX$J1^{y< zU17}Pf^$=dcf7WqGy9l&tHc){`%71sj7_+$ebqtgFL8l?TTedqm8bsfj7>`_PrOno z&&krg=3fCe@^v7n3Tj=0(1G zm`^9g)TvGLDzA!pF)8NRq?&9(T1}=L7jUa50J-STjFwLGRY;|fshr4dI@yNFbg>VU z>7<<1k(WgoD_up#38>Ty*FQf}Ee^`|M1FasisD28_M9ivc?I7E)Lqu~w3&J?GYmi>fq2bR51c=KB38pedcN`;8=%!*US4aon(b?L zcUrILu5aXHgfm=<@bDhH)yg(TBV8Xog}vU&a<7NK^NbgUVZ(KRGZA&V84SWkBi^#@ zRa(w(?R2~DwGVWcmPQlLlbSM-LY|*q6THFeHvzNk+9y|9Er3>Q<)<|v z0UWpC1))1=w;e(V5_08PByfqe$uZQDs>;$T@OCpNsl|}dFi3Ndg8pvzJ|wavx^f2A z0d&Xd-RKyGVK_Un*GK9C{Ky@H`0Yj%4#$@CT+=e6d}vwlHhN^f_L$zo=yY`@H4Fz{ z?HESboNd)d7z2MW?97ZygqJQGUM>qiNMSuy)zAlhEfa7r` zDbtr44S*K(V$q%=4nIbI>#f7+7fh3r7It&%)x^vB?A>A1@ZOS?d58lhyK4 zr)^1On&gwkVyU2iwSCp;o$U~98{A_DH=nAL(HP~Z$HbvTnqfeX(4fJ(^&!2}{Q zAy^=og^wDXQ;MkB?YoOs8=%u(o_4zqvn>GIUg`xw;zZG=8Y(UZ#bQz9IcT~74XOT9 zItb3F;P9pe!0OsHCzh5BL#bV0OxH0K!gEayplM>wFr;Q4{@8-Cm6dZkf_~eqgcDNN z`4b$015o;e^CJi@{Xj^`0>LC82*CqEExwSExbiG~J*SEGZE~Kxh!8yU-f1BKFM7sR zYY8c0)nk~JQ5W9dqZaj|jKdmuIb9Q0H7%)x6!Kmza3zfZ;ZQ~4<2$s9rTzdg8?CN1 zh3D#9=r{?zG=3*4MAER#v+`i&M%F$7Ol?)SZsLWa$QF zLNehvCIUkZY}>Y6ha)0~uBJDevpSA-eWbgtwgs-6d?4<2DGvID%rp%>wJR-&zY?@g)nF+Paq;dBS~PHdDxKBlwqXviYJqEfdIg{ZP_*ynf{e$;VW>7=!A?p zE9Hv0pF#B4$Daq&Prl?saQU%Y4i9lD^?&u<^jOAmg#$GCkuq?dfcIk8 z>9^Y9+=_xA?;s{|GQ9f~gZ$WwUUsJ2yt*hLZrgSzj*(yYmUd@L=Wv+ zC^QL>MO~CqAbGibm{U9K8ZB@6li2%wH^MK*A7A`!M`S!qA71g?j^eH52T*3j;nhesxRLj?~>AP0O0tAh?F;5s6C&KPICwapU%y?dUQY+`Fo;KY?(P8Q#rD<)Tk3QH zu7{wpd9>3il7zbP#%8^_ih^?ipU45SbT*sK#up={RNeO;BYrr4EGsGriay42+B&R}VzH#Z& zlqCU#TL&tcZcwV?mUalT3wlYuw>O>b9hppe{{}Edx4CxzhfggpbxQ}pXngSG16KbO#g&!)9Ysge zNvpLvzHSE4?auK#ocQr$9ILq4hfJzkj$>83P}UM29KY$lo4=(#e*X5uKiv3_!`r|0 z^nd(z<6Ad>{7dDMXo54ikz}gIc0^6-t8-D`W z;j^s6SciQ8Sex@UgG+qyHO2-5#s&j{ISZLRggC+w5h>@o=jr?fC{`Mpv9Ap{|C9Sh zmStI^`~HM;&JP$nm|{H>;_Km!{D8F}$PH>E6oDG@%6xNM~cYce_5tsnob+E+clWjsND|(%P>s)ArS_xUbjaGBEz0Qo3xHi7`!`~IE^S{vG}e#7%X zxo#ZwdQt4Uit5JN5zD42g6pcp^>7#jjb@y2inu@?*QsTZf-E>F3Q=@v)GQt&@8Y77 z#bt$Mah|75!#jQ2Gt94EGii~|E5=1=HpVZXogO!u@VA~}USk^GcvVV)vc}_P1HO9= zG#g{Pwv8Xci_j(k8IqikI;(1<`r}{z@{jKy&FAy{=&!mp9QJctzYiDT2U%3Y zz0{O1-$>leNgSz@hYsXt*yeBRI;+Xy}iEPYC@~Iw!VE~ zHiPfE;puDIci-K<248y~;?)bQf4aJQ;f)X1b$qQyc3nUG(DrtsfNs?vx$VtgIn%!T z?$(*_zj!;Lq;=&oddzE7J1~zXR%*vuN?&Boq zns74RM=;14_%57A=#3;r-2B;1L<+?*3dhr)Wu@?VH4svYLG?KJhX;U(3!?u_KPB)? zwt{i~v5#@iKp-xDiuMl=I(Tfq#R1;hf4p;WxZhumsuw?te;-dJIP$i!#oSWU2j3Pl zk73CK;6k|w<7&Fv)J3JIhsE95*sL~nfq&5zVlY??y4_eBBjav&Fdq(t=+4sQ>Xm1o zy>c~4XXih0c=&Hl7t6!__4?>rKk7`3AuOe+m?TOLZ%P(E>JkNOEi=WkJ>722iJI|TuxxeMz_Bh^ym$N5>t2WVoPTTP`&-^!-_Op!6>kxEc)5HS;{00$ApZAs z`p|6lO~=O%&K&v&(`k(DX5YKv<>nSF%0l-#Ra7;iBDyKfYE~@BojbRmbG2+{e&bJ8t4s4DPyFohmeDlKvzVyb+gsF(LgUI#I|UWP!DW2BY4-JS;lf_3 zpS%sy#EzQP>XFU;r;aftQT6*{#?BUtDzZ|i&8#Lm+28N`K)auPe}V(=b8{zg6iH%U zvmYf62E$3v#=qRiQguNA##6Kh{Ouz8p(nk}5jue(fL=kDyZ;NO4bz}RNn>)QL;AC-7b5IAjp;lgE5K_hAK8X4BOLI+i)V@9lAhh1{?*!;h_YD zVO+IZK1Xt&j&a1Fmr=wB6cZtiySyL92#9#pP z@-d3v#a-_S?@f%-C>+FzVE0FTsZ%7)^xnS_Al)>p(Y06RathD!uS%<+FJgT zVJHHko^uGJv2!8g5P!`8ZG2+rw2x1=tqP;z$?4HObq#U7+XdxS6bc4o40XHJeyajI zKG}>zpEL5c5+EU>FbvpJ_uS(cRaJXBYjUZLD+`Z#?8UqI6z+P;yX-yhd05PvvMPrt z3#p{qZJTvdDt)VJ(N~w1;NFwH!uoF8NYD_M9rQrDM6?ts|4SJ1?(sNH*w|qU>}DhL7 z;tTM;?}SWD7zSlxTCIsQ-J*;tqIz#WZ#<6+&S&UR@2z5it-Lh(k#jy&wPwAsDeNf9 zDp&P#*XK561bkkYu=f^6Pk*~}Oj-iC!%wWdZ*n%Dj0uCmI?ohE(X6VFWy4_{Nr|+R zJ4X)p(X3TLMZV*_)62soNiBoTi&Dc6BHwo=4#GCmoU`W#>w0!_IvSG-LWxd$I<8tW z7!LOK`pzv+qHed1$=;Kv?e;WFnCeX?{cobsgkdaY5k zf5K0CAM#%Gyy>i&)w5>S+`ipziyrmlL}{6%&Ax|JvY0eR`RbM*!lA)X=zEO&cFzNcf zA4XLfMa~bpNhr8d#!n0p-z5owlui_nxv-2mBdc>wE;3o7C=U+GLRh5)ikkz3G>$PV zc+6Fz6@iju$BE1nfjVp^?P@LZM%W5wU7EH5BnAb`cT|C zrva*nh0bs;jN`F5BzL|IrP6_)WqzQQ46W}NALstg2yVD=pfX^dby*DHWVqxyGr!Li zi3zG+uL?{ef>p*c%_TP!J=*~=7E}t?{F-r-?D-DFr4!^criirUOplwz0~STyZWOU# z(f74rTxuf4m`}nb=^F?TvB>^`}Ui?9N8oB z;$8ea7u(Dyyl1>udvEmK?|D1xg*%#G#BQRhM&ADpioDvX@^`RW?wV@*JJ_rnwVTE2 zDp5^havBxYZqo$T*1MDe(&z1kZPo<8?JO&cY;ckWtE*1lxEHwhhICg~L3%RCijq6$ z952hXf06{tt4`jy2e|i!a95W>a?(%Bk~{bB{@uU(cmFQ=^U;p(_ed<%6x_x#= zbar<8_SqTH+1c%X_hH<7L%3`Ey{wWWzm+fE_P(3)weVVZd-$Sv=MKC(ckFxK^Ox^^ z?_a**ZU6RdZ~M1zThZD4_U-u@O+%JG@L%FCe!{D~m3Q6qvXyEe!HbcsM)XD@tqATi zES|sJpbL#SYgScOCG~c+##~(k-kl-O2LHTU6v)u-O#k_;-NuEtKm6LoqA0=Zp2Z|qqMy2dDin@yh|SLdV%*2??c|Vdq3#?ZSQBj&v^d!2k92*mdO1DRoP8^Q%$v7!;tD$w4jS?v(fe~lIwCj4`n511L zAOmnI0EROwUF^p~oPWybDB{x;@yh%%?q|O-2 zKHhJdDlZB%3XB0u3fvcCZIA&agz2g@ZMDj>)tOHFeTuXqFjB($BN%`vCX%`?+lVuU z;~N@5SXTM>MartTio$sK=0We^@DPUXM4T(h1^)8Ij3^srjPlXkwX$rqeDDvR^!i|{ z_3d_hedYAEX=i{| z|0R=jFL~(L{>)W28?oBE;(61KF(fYzj1IbL<=uzNJB#@(#a&F+v)ybbYxx(;pB+Hy zq@RzAoGxE_?9oe?8BM1bE?$Ysa=M@8LgHg#QPgLpZ(JviU6j6!vA4aQC0DJrph>4` z7O&WBfX(*VdlvINk2*;TWLa6-OJx*-iWWzjRRZ7rJ;3)|pL(9>36FUmUBw-*=MBBu zdxQ5u&&!OCh{mV1>{-ovmz9gvCSUCGgVGBI0cL5hj&5nHNsqoE3R8F4q;}`d)o5Oe z@&Yu=gl?Hc_xq0?>t@!xCgw~8)i90_1l@il7!U5j&9B2NnGhUNbOZ#!tk$|JwJ@5f zD`c2KNWra*LdC2Q#xmJz8?#T0OKE;QAY%zjpp90N;l=Y`2EPI!Wri-Fh}FOGbg;>z-+oPSa#> zFlm&cpXe~gRdnt7H(n1k=X`J6G^^!oHu3l!eI%Y%4|}p>)YV~9j^cd0TuWFO()?-_ z|3jzs1IBle5K?mK;)wIa_oIlBWehgXasn~pZ-{*5oMEg$@_Bp9G!sHFc;k%nqxob! znN%J4j5(u?Q(7}dI?B@QylS}5qTgm(rOu*4D#p0T6S0@LTs-j@CM$}yW&0V{h8-Y)2Iu#Lo{c$R+YQxf_^i@5pfLa-0}mg zVl*vPH>uSX63&{L;>tFs**3GqBvhfNj431{65Vhs#XLEVV7-_-|EqSR%!}(kw7(2| z=r)EMZtef(R^gU=DxnZg=v~<1L@BGalhSHq2b>GZxfC67^V;cwNXj@4qmW>fR4&Wo zxl&RnW8Fv3?!V5x6>4S!KQ~H&d48MJ6{Mc1W9ORjMm`7TE#gJgif-Q zs&<<|oEssMwu`OGtOVd&W1u96ob#37hcH&6+WtHdrue7#GS);9#E*C-w zA%u`Za4v)pq06!?WfTJ1xj2>59V@N05EEn=r z1m$e&s{{5lGASik$Fh429RgP}N1iQDo;`@;ScvlVs@v`N0|wqEa4D17l`Ge-9;8BY zP}?Frl=+~~dGPe8K~=&25XhLmw(Y3pyCmM%s&YPnk2XnqWPOfA$xq|^J?@p>ksLpI zyZ80p$F=W`RdF3q@xYCrl~?7EHqsifP=p{SJi@NX_7o!6W<9AF9JDCc(S-q}n;Y)8 zPnuby>Rk{$Vr((hP`wzJ09zygRS7j;jOUA45h?N3#`9u+5dx39D`234g1}QZ@oRO5~{ENT%BOiJ2=0{%n%IBW@h&EEy4}OG^Al(eLeHC)g6Z4Xq+Ty33;MTEC6p!NSC4FTIJfI8 ztK}-cjOA*p;p?7Ct~c}De6g8rZ1(t`6Gs$j4e9dL7XVXIN}&!l*UDt zr&h;d9*#x8mVpc3L@vsz&LGdFVhke?u~yZoqEJbKlxYyDw_~L5hcPBs>cI!y>UV{( zE=@-r=ZYxS0vv0TB&4&UQel+0iYiIdq{zFSB8`J2h^EpVe8#SOpD%V2u)On|nck|cnKiR&o@Eywsa2)w3=?k0ugXRQPW4o| zDwk8+qpMEv3|@17zMnkq)INyu&Ns}mY?@gX#X5GW&&V&TGVrA=EI=wTHg`mBYF$wZ zCW&BUpV*pfKx;~j&3*RsC1{$N2;#)xy!KH`CuR!V!a0-zSCm?fjbk>D0QyB*x~R&8_bCEO=@}^jlV+w{jDCQ=J^d zfkA$UkBg(@t5;_YiQ}WISDP8(p%RytXTwVKm%{c$Xr>9R(-*y%)7vZXu z_sZD6Z*Xt_@m;m6?(U1nSmZD6b`u|(K0ST}yf`w! zFH)38!tBKBc(r$&O+uf?y)X9u()%x-x1-@!+YZ5vZO2Tp<{Kw>Y@6v)^{*#3P@LMl zvt5`d&3J_2tTefw4Q?e&ry#m&H6{)ItUl|GssS|y0$FiWmS}FnZHG&!R_NWS>!4^? zk4e!sx!U^OiV~u{p+&A=2OM`c8^gZdO5?25{>v?xvtaHElfcGFU}MCI@zdD2^wYkw zp;I=%djjIV5AHW)4VX3bc%WSrXcx&$sZnR(kH&of!||jHF-}rYE02?dVlhA2?C;Z1 z$=3ZMHkzg}D5IqWv(_aXTmj0)4q!qErj!c8P#NDTf^>c!SyC!Eq0CFh@Wm~n{gF$Or*LsyC z!)P$v`GZ0AZ~#WePtz=mVwXtCAtay~`2b^#z!?)#`N?!zX;uUwkn$ug@+e}8q!B?7 zc2q)?h`el7LQ}w<3!@;EaTsU;q|b+G;({!3p67YYE01 z16~kN3Vg(uMI?!R{Qp~qQh2}isrSxtaNNN2SS-xUAHiL3fdX0qV3^uaHj|41=!q6VXIN0wq>UK_=UNbp+ zKIINk)_LWXya--C8IJ;zr1zoOBKc8)xaXp@{DvGg}0=!;dkygZyAO-{~l_!_x2{u z{_dWG1F4$*#0OyGzo9$$n0Mm6())JLn{JwUvBSd0U0D~v%0PMGVyGE_%e|^xQD9|3 zsqRhPy3=zKtfss*L#{iNI7-4J&LX2EK`Sin*Sy^Uio~szR#uG1N6T45f(ysG-CmbL zy^`APBF4w9Qi^wby-D%Z zMqSkHj*?nT>UvLrGy^|AxpMjBR50#>z_P($(C5m02DcblF&-T)W;3S1p^Y(+z9vNz zs;WH1`+acu&UfHSNwzng&!>CL5CMz=addR?^4XanFhbz_0fZ3dA>s^-{2&OZweMS- z<8prxK~R=vDM`w27Cw>RQgZK6?{mFx@_x|!xtt!1;EuSXnb%bmEJ|!%AQqA$e%g6+E!(eC8c_dmy_DsRvU#oR@U2Oy}Y_^gqCNQnAD32-cGpP zZ50FOf@=Kn`Q=1PDHHrsDy5X^`EQi%juQ@%4j6aNT)XaVmSBzv9mgsa*(`N>dZx+Q zqCbt$8-y6z#MaK=L-w&_=Zt>&SHL*u97f2f@$n$>-Xy=b>#vtb`Axnq&xRlBH7e3d*QhYd-@>7vg?LZJyK^O#L*m0fCfgkwc za3r}Prl<>$>^e8EvdjiVG+MF$2L>HJZB0r>BWOHz{`-!BJ1u}J&+lC=f;eWpxUKr% ze1v~rqrY5rfT}edg|!rM$)zBI2DOv84I7e&FT)4_D_+O?MizP?$tr**lSZ%Pk66GeXUhWCTFrAW!Ai|a)LnEi*Rxk%9(+s zMdJ*!U7R`9{B4s;sy~|n2>7!ZBKL7-*Do`G4sy_I&VPy_Ocf8!753{$Pf`M9d7iPC znJ`pDMjJ__o%^zFy$9^=ZMJ*A)wVFZSBH5RwsBzyb`OD12>$|c(*AYYUzQT35tEWd zQ{(%JNNH^t=`i@Ov{!Gpdo@wLx82rzC3RmTYj}a8j zyhvlq)wW5t?!R>5@-`QD>~GHIi+w|tY%Iog4iAnGtf7yNU!akWw60-~M%McPw=s)lOYU#F~g2)fz|6zyaGv zM7n}%Cv#*@?9LF;byRo0T332uRaSW>(m3{0M6_#4RjJ>TN;VOi2-8#CXl4<;S50-D zl)bH0(u3jeG0`1XQ_X6cup9o_s5J~mul$`}&FAUmJEoJPI%;Uz(1>82W9)FBuHRx$f^n@GL%%iv6PC5O-;O*F zZKKd=%o>m1V7%pxy^G#c`99Ql+iEB~7-Gv`?K+y32r?G43%`}BOr<>XSRegrl$9F+miJC3wVz70VTQkv1b_7bO~_}@+{masL0i zI8sq7%0Bv2DN(w*c?PvUv#(`del3DTpiMPoB?`gUN&l`A+chh@m#K!jT z_WqXlY0pEtp10U+>se8+29t}@!hY+`R?VtnwOgr_yOKp-)a%WBu_aw! zcu{W-W2G6=cqaAiR5LULIXEI5B`K)Lz^X@QfYd53t;%id^?)+1zCiN?=Yh`!z(wG5 zerX1!bX-_XY`x71&V?Uvz6t#CFz_FtGQ$kg>^08Ek|K8vK^KWqHJoLH<~JELRg5r| z0g#*Mk*p+YrkLYR%^lIJi-2<@oy$w#R}Lue|Iw>Ca_=8YnG{kcwzmnUhjc8`?i0$l=5hF z)*rwA>fybUHl*lCY@-i!Z>?%*pt=~Z6sUGThV zA*LHKRXe+Np)QVK8}5#Pq_+*j=X9E1#I`%SbAI>yE^gq)KRWB5oNRZ;Cw(w}`-vwn z{(fh)8K1`OcK_<+3+{QzqYpf=!s6iOt;Zg_dGj#N{>S!Le|7t-zxqJ`sNHV24;i~) z-R&%+(|#2MboRluF~iY)7+jm~0egGb(})YG>MMC`E9JLi@~yHhILh=@XV_KS-5IW9 zI5q-S%_#(axeC8@{;PwkB`=C39^k_4mR%aXtIEpsU>#oyv*NzYe2y5hFb*A=7Js$G z$C2fO^M5*kRNblp)`L95`QHlP7Wp@VtMhmmr-Rq`#XIYZ7O!c!@HFNEMqbgOwEggOtH2u%2 z%3U=%!)!C#;Z;SevZ!|HHG@aGGutfY#kyAx26N$j(WoqY8ci)Gs+{sB@S(e-uP)t5 zcLI3jE|qUoNQx1RH}BoE&mT0Cg>3_Kgu_RPPak^qDYcj=+`*DTZ>jxk_U}V69uR|& zrZtO-5@pe|Q}X>1vN0z5BV}1NY-jZHmhXrmY6W2kXcPXpqoqk&(XqcbW=tg{IE|-_ zbOuJmoa?|(HKXyEm`;(1BuN#JBUNOhP8j4S^dIe&R4P_hrYWWA*k!3E!KB|)Q4I2Z zu4Lw%@rhW{YH=KF@4N4wXP$iGmS9YN(~o`WyDS&FZ@Qff&W!i=j5Ma_2uf@5UrQqx zCqv*o?UV0M`f&`XI1hYc0RybzLP}6p4elGkTH`w+K}zL;F{td{;+zBKYrmFp27>w&xtEEQVW>n~($o+LJiaW0B zoO4}g%v8Z>L==FseZP{z!59R!l$^P)Z=LJZ1xu@UvtC6UAx zaO`i3>z}`pfpTbYe0@7Y?0I>bDlBN-8uN;dE8YX%Q=XTBnwZ^(N!OJ) zB;iKQqrK9*`dVx~cIyfg1j-uHOkZo67+S7tM4HzTRUMl;)0G`meiIx z+1cY54)Aw>w;U+~>=sdA!XhtnKIXdF3;|lEX7xnW-6~{}SIkzctJ0)l8*H|l+2#kB zlw~FbX+=Wh9ifTDwZ>XV((wJ^+=PydZT?UllQnyLkH2JZ&sp-VRVo@+mfIK0<;|PR zr5Je)7Y@9PB=Zg9WYA74GCCgyp*i#cFrB7_91I2n-7jKE!2j_PvQ`_YghtC(d)*Au zngehl1MtD)fYC&xw6^~9NIvoS-k!14xKv>W5VLk~@5z@R?DL<~%+93|4m+vbHaj_C zez12M#kz{4!#y`;T*Hqmt@9DDwRB zgPpcNYqu3Za<4tL^<+GjH{=HWqEHhcg24VNd}b(v!1_==1*CDl@)ElRh36A*d3|r< zHN0fAw%%p$hIgO$koVYi@BFi`-P|7pvBs@?ckaCZ?Qh?odiu^ESZwj}AHDDY{#5NR zP4oN>67LX^LS)+ROj75T$ss9!zf?<8H>4JYUnyj%>)=6_=iP1`)AYUh@`rX8dOdBX z(+e+s{PE3Jpsuf6dEoE6qoXTV4~~rPZ0^7PlE2rDW48J05uRtgzZCn;wQCRDTrRuQ zEWdW`xrZ)a9*^1Izj8Jojl-koo_n9`_pjru_ZxeM-hJNFo(I)A(s_bpWb&*AD#dNc z3o*O0l~nkGkN7siHB&F}-d|gFyUn!I39Qz}`P$MWoD1=kwOU(ijJ3yD>E0nMc`U(9 zkBFwTowY~ZF3`$hjPs4wE_g8SE0+-9&itSMiefwRaT_ z(g{zwfY!A~=HdaN+K}trc88as)vEVetyXKVZnf}K%{?%v_d0_=lzw>KvfS(KRV|=Z z?M*NHFAL_@d4W!QZ!gnzS)xyNtT*9~cjmptd!P4V?;E`D{kD2nQqU{UY(2usLMlmp zte!NRdXhf#WF^sAF~SEuvyvzUqb48Qo!i~E=_4I7J45W;L#1lwSJk_pwOOMkx%QLF zZ&A(umHo}OS=SS1tJZ~NJef{=M^$AJ^yS{dktWE1~9$vg)TLq zOO3a~b}V2!79U#=hip7UuXi**KF*Gdf^!peyGN{`q(~7ff8Rk*io!*4JRA+vUOy$6 zG#w4v?a^sw&MVvwo3F8Tk8eLbM+N(SC$|n4SSl&!Amu;3;Lj zvTXs|c7Pl2gu!>{4g#<5Exl*GH+Wy>{UDod;o4DKZLbS{UAbu9ZriBU@;Y3Dqt$MG z1TA=uTFGivs(hjHMXu`EX3dgAU*RqTDU5SWj(TAzzB_eX?oUG*MIB!&mu3I`QAY74 zPDa$67ml-eu9Z~9#Z-pO=m?Kwn)c$r=UwQ(ns=cy#gg0#L6&r;$;c?`yjDV!9CLt` zjs!mUj_<3|AKxmYLt&kU0&s7JVEJH`LIA(Pi6EO_IxjNo2 zY=9_^B0{o`tiwcqxv|mf6zbP1=o?VV>?`PTC(G~<#6SvSutDmF&Y`y-ItSQ1CRFZP zm-l8xSga!a44aE+64+8dPwJw0*XIYXeVtse&6aNi{7=6h_wlpkH}?Av&BFL9 zPS4m`E{{k2Dt;0i%)PpU$Fz4HZI6`Ej0n<>XTnZra6Cjf=W{&hbi(|e$=TViyYwp9 zot;hY$-k}@MHuvtkNX2eQTwrGR+M7>Eh>vy^Qh-ZuYB2a+m^d}Ue8~UB<;KI zax-7d8>!}tWx-IYv0N=zM!Uhhm_yc0&Nme=SDUr1HuHMU12tOAn)$-4M6q)O9QqpT zomA`HcC&4O(4|3#F;YUEmO@=|cf(YIu5zm2^(T!L0o#XYXrsLc+Qd`!q-OJwmOeqG z)Sef4wOlO|$SfDE!S>p1ce2@5^Vo}fG}BqLt)5R*mDOyMqAs+m;d-&%nKon{6OU0S=(Kyq=Fv^>PcOH)Ra_C;%uSx*{)4#+n{AG(JDR?^K zUX+cJL@Vbs(9PUlj~MtgbAb|E%arj%bMsQxn;snWdKu^^5 ztH5b%^4vJV8EFET&jnG&Wylz33gKW(M#qUGUoD)GLoEytI zKm_zo0i=G+!NcAWq!j{mFzIPx0Ei?L9Qb6;7?EWC%ykFjDvmUuiXw@7GEGUay@gS6 ztG(B2aYk?s#Hi)RN_RUmhBHAz`F>!01`uaq6gx%$0&AeOjuQnK#tA-wveak9m^4bo zM(H51z6%APMu?(V0gT2`D0oZ+QVGC{AW74{{fR(Bq(x$t)P`{)5GXdp(o8FG21wrz z!+Rt36_Fm(?*YiAB zXl?AS3)IPt8XX@+ocF13)~rsKJ}O#6^+ZFeb{p{LgP> z%m-GhxG3U7=3E))MS9b$(7?Tc9eg5A@5G(+J76HGfAe1Wn<6Dr`MSz7t3b({ejqf~ z4nx-$5nyca11srYAD%8b&@=D?YevH-rZK1bTESg>)@Ht=_FnG2%JV8OD1n)ASI$7l z273M7a<|y-YPD*LTHzT&3{)vAwFCzr!_0B@qt$Y^Zaj7yWudC#JNoCtEbUUM9g~&j zG0sW1+A|$S;ji|S#QkLYzN3f6vf~GwgN%Wc!E<4!QxuSbKM7I5%015`ernt88S~{g zr0>$izcEvBS#o0BNjFUrk(GtQj~E>eKl`IQgh3cG3s^sn132669Q}?@jFcQ(+f7gu zyR&Jr+pdeJAA0E8 zHGE5YaCqV64?T2xiWkuDpPlUnW#!T+YMS*+uU+qS+kf@yS5F?gdiCm$T{t*Q+uhFf zYcE|lO%$cBDhJ!Mvq2v(;PmvNhhF{{uYR?M4H$2~_*r@bKF$xT^?J|4%t+Lo8PcHn z0QnlRTp`_YTJtfT)GBmbJekSw>M5l~oi)QT3TJidZ9`JyjF}QCQ&% z(Q$}k=i&&igO@$^(kFpM8&wA|0f94&$6y>37@$+3y#RjU8_xd=lBC^EVjzjz?IZz` zq}@(pAc@=UB!TCV=e_t@ndYHGZ|O5k?t?ZjQs++@oHW^_QJgxIh@j(-udP>`G8)XDO<-@j#mCX_FPB%@WO95w9y1IEtJT$j_jAub?&lA8C##3s=^ktl zgS+?`-@uI0^H6UpRg~k)H8Aan^nPwZKkS=)duS~tc%r#PGhKMXZSQsOEs46 z>eQp`-mQ1dbc^z82N`(Pty{NlJ$mcbcTW|B!Y}e%?1eTYio*K*CDOUxg}1%$sizLo zZZ~5B!8umve}(_c%a{M@)vMod`SJr-u3WkDdQHUYo(;=>zh$U7KCW+V)~_S2M#2K7 zclozN9=LKvE~Gy@c4om9?>;2xN>eoBq)F>4nK2EC${XtX&V|a`IpbniDMqtSRKI8% zdgV|N8MXF(iqC%Rxz=dZYHL-oEZ^H(AGg~sWpUJR#Yqs9WV9Z(D#7!-E%=4QqlAFR zCue7WMOjV{UKPhjhaD+R;7_v5LD#l9I^C+W%O`L4_74u`2L}}o%kizuvTPD|@*Ifc zRuRWsYR!D#RfEB>BgFO7laz4d^SWK=BMhMY_p13~IqvtWo@TIZYqUG#ab0)1&hrC} z-^Ith!0U1+joIheOp^!_&DaSvV`ec>D3<|k zgvDvFdNZ>2$~XPT-mg%3-e*yiF6%w{N1f4V%%d>fOA`9Y;ofu%rNV<=&%I8_&B4B+ zaXJ{z>Oe}&9dEV9xs-LcC#X+pHvLBk!W@`%K@r+k{@$qF4tQA(ePVd1)LMzM9ENek zf2+lLXnVa`)M{0q>$?z5>@^+R*`VEV@vPHTbwFfX>c_HMlO}-DR%6!3Y zU^HH?E1z5C}SZZwn_h)lFekJw$-BCEttMb zFdDvrUOnRrDe?{G3ps)}cDX1Ac_9fg3TMijMAizf6bSli-78B$qzFKZ0KuVED+uNJf2^v}#23Vr)-p}AR7)Ye+MelX$Oz9|Qc z3w#12ZHa-Lb0mfzFUA7+A=BLUNkkZ0&U_!b+Ory{UhOzflQ2w$G`1*=MJpgeCFEWZ z`92^-C>gk}V-_ag>nHJw%^ z%#GLT_+{H2(QtS;KdtdCp67Y+su%C#0C&BX=S_F@X1&|)R+~vPt0zjTqApg&YJ)0# z)^~$_ltphh9^r{6UjOk|Udh7zqdMI+R*3EtV1SjCc*e z{9hU2BDw)Xj3j~2z3+Z1@@cR8Ued-!Hdj(S`rrd+XGHhi_ttND&_+>s$(YBqlKep% z#leEF2mB1(y5}w1lhZL%Dl>r-f=gkDD6h)Pm!EmdJ-6s*-yIS&$5LJqQkrkOFH0#+ z-$UQQh}V@3Xy~CX;)Wn~U8{;baP>x+hG~oB(GfOd+_`b*?kDcNqI2gHckgsMujt%3 zzjNo#opao|ft@>dII(NSF?kjF|@QJ?#Py40z`?!Oz^$xwO-b*}hw^DI^K8C6V z!vGP0f)(l*KbOru&LKuq?|fzS5>l7{Uf%+0FvFXt?GEk}(oeY%Y5a&6er?aejLq9f zmIL1&9$9}NW<^lU#Ne~5?`0(9q-O5BIadAGF@({H&ZM$79TCy_|DACA&6=70-{8c+ zCwT6}mZd$J+Sx1|d!Fan*JSx#8-GJDc;2qYV9={!4)Ipwl3}lcbTn_F=}lqjPO5p( zS|oiY?PQ&^%nb8IUd_R+GRPO@)J!!m=8KgFFN=AR7v&-^@@ih>i;@p1u`J5Bo>!GcIaU>&WtA`H)x64&l3C@8axpK;MOl<qxa!SvK zhRDuWOZ95{q6&|hReG;-s~78GJF{IMOZ4_@*L<~HY}bGr-xe$v>)m=c-^~~6-F&xR zEH~@jax>q|SL@w+wO-6O&VG&UX1iH)@OrUbtQXtOdbL~c=9}ea+d=Eye6!tbckA7J zG2g7WiPo$2W$F zr+6LkZMK`WI&9_D^sa5STy5wr>%uS^DK}M@{SaQZp0JI^21oB!WgpW6E@N5zM#*`} z0QTPBk|hWGFym2*VmBlX*R4*cwLV~^6c?Op&G@l$eknJEW#wagQ2*dyfk>FC>F%E{ z-9l=}l^5OS$mPL7Z;=5o$kJ|NCpOH7`?ivp`2Fn<^N^Pe{YMZrwq|&xe~I8(EF^$|6T%HZQZf$CjS>9%6ZBe^Qz+3JA_Dk# zcCEj_9bfYTuY6^>hZ$-*9kb{bOs9K*n}xRPVf)vVyP`VsLN_-^1o`~S^v)GPpeL@M z|DP%wCPq9mFxJ}sBf=!ZtaY0Ktn;y{OF9XGS8x>sN=O?L*uu(VnhhYPvg72(wlhqLeI90tDclHME#Lc6jkOBV{BYj?7J{;K!K3&Yi`)Rh7+s3dW|3x>m9Uumh* zG)+w}vCf5~VSh1rOJc0CSzfk-kO|oWyL#pM=dWC4?CO>0FU_6yJdb($#b2Ta@bli6 zdSB^%%=0i)vMP(rAlI-#xo9OftKkr6X4fi0BCIhEsH(xB z;%_Q$+<4}`3l~P*SkYfCuixJ7+RvMIZl^)W zxgQm?*=WT1Xf&G@kdr_7|WkF|DmPBPqo=2Yd;%D(OeB7IQbI+UBg{)`I ztntZ{&z$N52~&dj8R}wHRsku7!@a?5ePK2Qrn3v%{cAU$yS7}W`1B}TF0Rjyj`t7- z`~F+ryKbS~p5Ccz%w`ua&Sq$?-^3DmN%Q=$>UQWI&*EUXXm{+%g2FqDVUJ*LWMs{L z+f7(jW!29Q^37uOKI(Nb!S29iCf=B+^~`Ei0NniY+r3uvMcq$(wcOyCYf~k89(J80 zQI_30%fvS$id#t}j{e?0pt5|>v^!RT27}c}3sC;J(;aK-LM0qLFp7YFx0g7`u-hG+ z6zT`9KWB&ILKL_D2yt>Yf5krHCL4k8eDfOe9a@!*Vd_)BWegfMk&VPOWolkuC zOTQf5^FM2S?bjkc|C_Hx^mU%c`JC&&;9C7o&dZ}|Bh*yg5;G8us+2h6#D9Vc@2F0;Jo^^+<7LeuLvp5EbQur=r81`-YpQ$X*sp5oL>I+Fj2BRPh12V7( zrDtInaRT~T3i_r_t5sE<&Ty~OWTdT5{el^E@jUV=RiItQq%v zS;~~M{oyE9q;wnvQIzLN5*K9^MR0jeG?+{pKkz)yOFeq=E?@1fKJeDw3*P5?Uy3Vu z0x#e__%PM9rpxpwy^P*S@1?KuyezL4hSaLg)<}0(S;EGBaP4)vg#qz2vD#1AGf&&8*%@Wn7GR1P|cdg-t{%P!f$h zrZ)3BL{D|s4{0Tll3 z2Y$pk;{q%b~G_S0cD7@IIQEC`${!4!Ps&i_IP zofsWjBZzUvQa_gLSTUhE2RY+o#5l&25*@i2f|QI)K^9{ikizCcCV|{Eg0M~b=cJ!27$2F*Umbol_cNmT+n_XIkW-{ac;TdJmXvIhj3*&pc*$0 zCY4L9Rm7l_lUbI=y)@Z7@}nr`DUk9wiu|L!Bt^x*iRln_C%-mUq#$jr0tsb(0sl#LhwpE*~WFi=VXOlu{HK`1|vT(T$*xQimkgE(T6 z%fMFxjHJ?<0VrsZDV<{;7q!T$lxF{hr{kApuB76vmK(HMKH#@n1HWop zlBJ?;t>p0Y{t>}0L|AJ3@F+!Z+n&<5zNG0n@GdrVlwcIrZg$LHNAtwT%0!9j2fqOQQfF2E!b@ftHX|Fy_jrdGf9`!?&ew>1sU#2JTt-i z;BwF|xAR2=9_n;b_$aQji3}I>#a85n^{PeggN=HrF|YHQ^*C%B-A$&Z7&WCdSdm>; zz#_gXn5y_{tt+an7b}9kwciTGs3B}|0vSz~i}7ayVO?mA0fZoBoz$EWF{88)igCsa zAk5oxgK^^vrm5AMP1`MUfVNyJFVJ?76-+V#gXS5TjX;2695BLi7$r$Xl96JZ4SrdJ zIHNHJLE`=#-wPy79h01Ko;tIJ02m*Fy%+;XC@oac6iFyfPAS2;JY>5P<4_t=I-k$y z>7P?QIXS5(M5FN{2!g9jDY|F}S&I7!uohtO16*uBuDB3fJ=O_=|NA9z94juQG>}ef zKaA|?>Gjc(wOUKRM|zl~HH(M&XmeM;^b*D3ct!{IoX)C=D8dXcVxTQ^1Z=DI=KM%O{U zU<2#sZAi#mW3{X&YSLDfOIWhpL&D&-a<%l`0`3PbkG(v-e++bKrP+#u?X2+z4|dCH zvprVZ)pECNYLyFLu!2`*Q7ZiW`PcG1>-X|Z;N2|Cy1gvr(?AN&gbZ3-RGdd#KwDIU z|Mt%4dIEw+oL7RkRxe0G5Udd(Xzfc752R#V%Anw^U<5(Z7*OUwy-g|Gw}CN|1c>FF zga`sDIg>Kr1nFxHf{>g^f`G)`ewOp|ujN_V>tz|oJ4K%L&fofk?k3|T7!ho@+X<{C zvNq^+yB0)DkkHq1(ZWjf`&Zu>E6I$OK*%wJ6O^v3svOiNilPi{U8QWL6O%1$wB&T=WlV6RS+_Ffc8(YrcpoUc`d!E!WAQ>l=q{lR21IaqHl9~Y%OZW?{4 z&tFY1o{X2|{A9<+lXBU?bnn8luJyHGV2_b!5L{(0?B`{fDpf`y z5RN;`-hg`74Q$?U-0B^OSIiR`NYpXp1|8_zBp9A2N!et zo16=qW`=JwR(&HywO0gh&KGuv#>x6K!E2g^!$qdK^%z^rf9&FCe#t1~a& z#Y5!^U+N#FaU7*cT$;2PGY-IsR2?539f_z^8$wlKngwH{3qMI(oEce0oN=keqi45@ zA^~vaKyi?Ziz0SHa6pmPlkuZ5hc;RR(UWJ(qLfN>eZ?5*UawktL@E0HgZ=$UtHrgD zp$QmIzv$lEgMn1ct8iC?zrd%n=Dqhm=KVDsI+$UNhwubmfv>=KRmd1AkK>0&@&baYwcTJ_b@=79GXoFUiNQgG z8zCzQ4!9WUOG3gT{wq8hE(#wvvLfdqD$1g+@}n??p>wUQYRGqi z14hZWW4@U^d5nCZr$*)^tm<{+R0!FiNXvb-qDR?Y@1&Y6>XH@a>7KH#ZoR9vt3{CMsm*+4sAtqG;YsDG0=XSYP*Oeum(4)MEIq~*Z1a~Jy%)q&5EP-$ z(cD(08bSqJhvZZVQI-^h&U<5KqaRS9PFiP$kXj0`dNuJ0r9krhFWL+iJTi$@+Jz;TlFD^Doi`T~ zB_#(4ipC6UAncStLUS#+%Kd=a$Jy))NlI(RIk+*d-KzT2yQv45uCNh>Fw6RtRMi9LUKvKm(R#>B?-~kA}6r6=`a&asy za(?t9N}pZ`8k9vB%#4 z#&E0xzXYm8sjrL5vOuR*>E}tgEDQaik{J^RS=(;+II9AmGvZPyt^>}KXnpDOVUnb- z#druv%ef1~mMQWc&%I)FLRnRDCZmXPXBp>=NN^W2#-wmjq9l8{sut%-gs%h>fM8s3 z9geKg=&0gEy|U!3ZmVKUNr}>0A4t+P_%)+Acj`&xSr$7BdN>~m-}ylt^?FsBx0gNOdF^YMikXp(5vO$ao3BoXh za90jh{sRbt7^AiTgc4%UIA`Dz{)H9lX_6zdzd0cNqKrZ*IG5TeMWmhf8R5aeIszAp zTNjg*;s#@k`>7B~=rf*>4g)KdGk^#sQI^;Pw z`=;q&c=4e8F^=3xby;2#QHSWSt|?X%C0xOCES6&rkO*UcBDl z%iM8eeFsnw%3}FDs)$;G$68YbAw-`&;9fZv%e#|tGR_=;QB{STRZ-1?QZ)z1iZwaG zW|0RGqN9Sg&wcV=kR-i!9I1)UN*uoKQabSmU1%NIDhz-)>FwuZn`A)OcB2qkHe~oS z@(+&V2-YQeMy&t!Uw?z`=Pjbl2`PmMqqZ6tls#UYNo=``!cISmcsJ--oXf>~`JX4R zZ3%*jr~P-o*d+w$|GaqduH@J;=x4m4cinr=d%yQl@4Gy26bRWfsWr2vtJ70*WuB_0 zWnYk>n!tu4|1(gj*HdP6Xw~VeWr3t^5QWWDc?D4vimY-lG7Dy>xLc)`%^a~N4^&yf zJ*qC~{qM$=(i7|0;(=4EngDT4q21O?f)c=`ZxNlAITnjP2Z?thy5d_%Y ze>^MRvlTejI&{3mw9tLsNtuo11j z9{N={m*m!3nk8?(m9i5hw%6IUC?7OlcaIQLh#KHH&&|Sae zg3tv(dSe!sHMoP1TXDPVCkym`w;JU;nq74NDCnDtVz`%OSvDQ!#oM#Npq&HJa}Nig zyfq%RUy4T$^L#Y&a{k%0s*vZ$k9?#6s-n}$-u2eJ1<761_`SD14cmW~wkOjjeXutJnorD{Q)`R8tiZHoL4zhA8I6 zyjaYOd9|1?%8Qs6%f-C92=Pw2!1V*HJ9+KLEUj^A`Z%aR7LM^ViVQ zHos_^x5an)D>=^J|M=ri{OH;Ebn(yZ$o-8(}liP26{^3q9>pqut!_(8#Z+otrJ%^V+pyM^(CGTnPbG@(gyeXww4D+>L z&!`S1huEwyV_7t#*9hz9sdcT`79A_E=9jVDZD#eZo~UA-9Y@$qe?ga5v95iZ2t91( zQ7xtIu;qxEBaE42%n?S+XHPoD9An)fm}969#|;F)@7qA28KZkmpBiR(qRAu#ARkx55m*a}@=EwG|3LucElNN-3pREs2h7Q+ibt z2yr$GGF8ka);8j^=1#}}$>P2o(wM97_{mQ7yi*cOtlgZN3pjsdOeG~iYY}+b}$@RKs zm`bT8{9U7^x7+z@w+qcy3yOj&MWNeWYvAD@qhZ2XF!XlEby?rCY%O0JMG>5Z=l_3A z*A+Tazma|Ohmy0SBoRgx{52jnGI>_DT4&d~UAT^_=e*D~U--r_2sI%!h#62yPg_#9 z+e=^dAC2Rc%kZ;sc|5NQC*VuJkYVB1ips*5zN-BqhMzt7o=?NUpa1#K4hH-8-n$P6 zSI8L1U3X1pU%YtuCqV#YbcNLQH^=`WIDpGB%9`iMM~Oe4nVM>#`M{n&435fCkW%F4 zLHUT80POkukeb!4XCjVNDd*|pN8pWA#o3MS(IqbOs^f}0la7?OercZQ5fhB^p>N8~ zgb);rAVk}-5h!PjN}Y0Gj1idQ7^dhy&-32ud2ela-ff%th*Q)>bNNx0?MN2sY?9 zTkS}x7H1wsw{Nj7_Td@QB%9AF6|MI{6ZF#ZxU5;^n=$~Ola%=G=n-~&|<2Xhh$58~Rlv2pz zIEvx1NABSPTs-_-$1n`N`@dV7W*FTc?i#vobf0SLnqhPrJ>4+O&TsZDb&Frs{-20F zeFzmY96Vxmm#alRYG9AAUhK!2uH85pjP82twc=2?T% zZ;cZB%(r$1-m?S7e#qfJlkw5e&WKk!qbAv}tW+J3D^c6EfiHV`6k3dd&wqhxTxj@Z3gB%+YD#r zRQ4ZM^D6a&nJgl5NAL%N-)N9#DuNU8V7)L&%2_>`&I?$HyWRM~wSGY-(}RQQ6pP+k zS+4$n<-x(sFxIEjb;G=UZOz)3nIPj(?M zi|7P-1tCD@Y@oQc8z4yQrN+ww&3PyStOpE$iLq943sLr{Lbd%DrBYlR_XDFS;mI+*Oz)I?RFbTu2hvC;l zfbi?O@u4VQUA9aBUGH}+n*nbiAiwn-#!0?rnE=}(+d^Os4iH7Vci<5|W`IBuIY0;T zxxoH_;^T;qBmEYIo-Q@}cR2w6-7Q4aI;Q%A#C)z{Jl9OV6pyLE!ZLVVRT>=1WiGf z8yLy6F+F?n5*{4hcky5_xODO0;MvOugTY{M>EPhv<-y?c;NpGvUA#27c=5jb?z`_I zF$f_?@gf|@jmWt{ZXs_a?O%(`rAIY-HczUcTNSa+p zR5s4Gu6)kW5=0_+Xd%7{mqiwrQ&m>kqpenjK^OUC4FifW~8xEoM zDeU*tKDHqY;s9E--^=>Yf;b-Z`-x?>;Ipv~%2^saT5K4arc)6r9TYgrxueCVu1SN6 z;Ky4nxR0AU1F*By;hM<+oYB}hBRo$^&l8(62!sd%`M-9%t^H=}YpoVE48yb%jWWh$ ztCh!wnc;blW!7pHeh`FXWtgTFx7vm82hph2${GzRd^?UCt@Qv*=mWNOt^t5I6f;9m zX_x>3TF?h*x4@T=6s=h=Jn8D1(3{XiY&Jm`n%;#bK(jkH4975bOw%(AddKoTZy_!& zfPU||c?D<4o%wI&cpv#3`7!b<xRA3}Hml$%u=1XtYmDb8e*yQ4EhU&p=`V z4BR_!q9Wh2E-QkkV-J=Bnd7f-YRe<)yqZ>n#VzVY-A4O^ZjWhtlB`HA3^O4dw+W5L zP}AaQj6o0vG_BXaasX_>aIm&EnXIi1hG3cg!F~4~_@;IE_nKx|nl|;<(A6vcsMP>& z?43WqXE1={_uO+Fo&ideWD9-IG(GTr$B|$=wu8vo3M!=-jvoHvH9N|- zEL-hdGaja$O@v7&9gZJ8_&$#>&~m`0{sy()xbntJl(rgufWB%nW+U3;UMp=RH_QdQ zeThuTQF1kZFi%R>)j~r8Q?iz;Nk;QqprAc$E$u?H)@U1U+?;rfZ;O^f3+cn)^ps5)K z%(o_Rws&Oj`WH-wz20#0b+ZA`Y`Ty1te!7g!avovEHfpyEYon6q8LRDGS;IOw=ibv zC&{aA63~H!8o4ql6V6hmuhfc5mNlUiMU)1GTR3bW{B97%1q84zZQJZHVS%H1RIJPZ z@rE!hZmi@%%$BW$*I~ampy+p7E&K&wGNi2S876c(Ylg1tbSp0ql4LOG4>I-kpa|$k z5&Sp^(e5dfatH$&g;e#>_Ys6>_i3wntizan0dxa8*lKmUMi+e_4^zghBS-i!r*E^X z5oj2pWk!Q6YlOO_%=CkxT1tmuD32^jOJ}svn9Zis$V%dv!Y$}~^p7wKDM;D>BM`iU zzK2P(Nkj77Yg1~6jCo#$f_G%Ocl7H>;Kzthl5Aj9nS4Ab{me&#^ZE7H&*wOO)FHX! zj{jZ=;_z!-fB0MQKM!LJWf7LzL$`(bqNqr zXC~8PUU7UQ{FW%=^a(b zAGfZJ)F<)S6R&#G$EkjqTg?leSJV2VjvSyoGT{UmI_T80Q3r@n*T4Z?#|S`2+eQs^ z9Y?!8F={&4_*-DWI@i;I4mvmQX9|Ap{@v@Y+vP0Kq-phh-!}rOX?nDK-F3UMrb}U& zvF{&#d2MZTZ*OybeRFSb^C#_jTODV1D!PuS>!6`+p$;L{bQmdg9I6rMG7k(BG<2Nh zkLjR0y3RZGeW2^0Y4-U3dW-WwYNpxul?pu5*QBn+P;bSWt_jnO1Eu^AZtm@EE{}yZ zOoN;KTf7J#C(j|zC*MQ9LH+?;n8I0jjF5U(PiHmF#A)dyv>D7yrs-5z$zMov=_wX< zI!&i})?qAN!@*=aX{eX6rCn3g=#3$SWD3O0s;iJOL-5q+;NqH|OegVVb$!BQR7#CF zolcB7puNxJdSEHGrogsAdM5!C1%DEYLF3$g=*DB2y>>i0LZ(YV`@Fp92+t|ur6e`&e* zb_hbWO!Jq9!(oFd#B4d*`8e|}3vI?x_q@>cJXbJ4y%WV={KH@ceyDT~EC@PFvl&o` z?baTyjUEXd-S@hVZF4{^Gz|bJ40~+>Xqq-)zg zUCRv_)7)0%dyLvn0y?EZkR-OtC}pPPoyeztXuiJ`dvRyG*+NhN z3@oI^;b$T6+e}kch*`Gj2#O*sL8T!WwYXW{tzp0r{)n3#kS`8%#r#Tu_QAfr3VvFNL~fSmF%nmJlWd5I_UB@xLjhj2WEk zfR4s3%1nT_0YK~v0l>JSYlxD`{OiAteYDjgQ*zA}uI55zi(rQf)nRF6Q39BiOTX}w z!MlVM1$SuCDksxAc3k_$24Yd*uHiWFTOVmfrsp{irYrq4>kTxiKg*aIz&(S}xVh78 z0Can6hu=)4^gQ3kH{aiiP1kcauDkv^Qwlhvs$nikj!8l0_&Adbxe!o=id3Dv|J!2OMFT&f)*Dq@a%p&oi?BX$j#!sZsw& ze&+E1r~1F&|2;1h^!#g?rb!9l|H>VYO9nUU!_YA48XAUs_<0Y}zUhBBj*B~>EqVQg zuKw;jho2V`!e7#Z(DMLxe&G*vDhOeO^uOtG3xs!%1S$}1k=dfjI5~6Hs;s()>kJeROmf?8ytL(z{7p56E5E7mdmaUc`4BO8|(>mBoCcBa6!E-Mu%hWvY<3Ur! z5QCRKHyLRJH`$&IO%tB`0Tl*9)41cPF@#}9GQxImAO`=h;kq#Cgb{eIdN_7$;d#Qg zlV!(snwv*|6D3vwpY&YyaN@d5(}ZKIW!rJu-A1F|aNS8K4B_24bL7&fTW4iI3r2O^ zm?a5V)x z&+prc9p~c-#*PhA8dpnc{G)VQRQvW*^(IV3LKYdXDk<8?s`cWrUd~E6UNF+?is3tE ztF>0G zmh%O7zEWJY+k#tDPbBQ=X`U$}LC!9?(I(G4EM~-Ul1K$9P2@Ez7{Bkw%DsK>Vee($ z8@=~=o~V^Cs2EMgdc;f@!bua}1I=!W=!Sm{8oU;3UaEm4+?}DMUJq<;I!K?{^s!QNOdp@@-~-M-^x+3Dd!F#{;$6DN1yMBg z&b-%SL_Soi1r4_cIl{1yS+B}7mcA?Xq;Eu|AKBowOvyrGGOB)IC(VIvwuIDnSMdII zFnYPM)}@)_)@2`-L&aWvLS|HvEq2V1KpT?d_Gl<-tLvh-8u^e6`|9 zl1L&|9ULrs<=)Ms3gXJj!NKYZo(n(X3may21YM#X0#%|oA3k#;OQ-7O_1g4Pcf7#XHFfRH zx7_hT)AP*lv2|V1R?B4%b?V)tyWZ#rAwK6hU$*V9hd~H0Bg7-*%0Izncv)ZSlKhxy zLU|mcSwToE5a5* z9vk>$OX*!FO&WSjDyBrUAJYWeQ4B}A(ByfaxAn%dmO0&c!zpe#-K>{xUg?zK@?Ldg zTAnz5`x>Mh#oF?ylXXWj>8S2)S&#)c2aTX{P1o&so}F65btBiuyZWX%J+POZl^2Nv zz>w+f@ zT-+QxSIWbk`Z3%DA;W7&DN};PVf85WsAc!)_!70K|Lo*qaq?zx`(Xf(sPS$-1}O4f z*a{7vIAJU$LzJ!?>-idbqeQh@YpAu89ap-J$C-)iZkLbTH3E}38{la7sh?}U;dk$2 zmDO%%OP#K^FxFO&9$j1250AMVebaGG!(!ZX9L;S}IW;<+e5K#xbFsE|yey2!btNK` zS`<17H^M*yNC_YbK|%;=^EkvMeMS>R<)>QI26;`nZoW6&wtDQ?_EvEC@^YLrzB!oS z>U3HxIrpj4r*6D)@%N(Fo0Z3SJ}&3ek8WM>r`c?F@Z|ZMXEO~a5OSf?%jGv&z_?~r zkK2>>hRYx518#1f2B^5vk@ffY4*y3z8X=BG_2T)RFW^I~TUT#R5GR{g|1<;R5B6Ug z6^sP%;*Upu(|qj;hVR4MK9(i0;WUO50)%uVGBtlBuF;q_?&DRA0 zw?Ih0BTGpaL?4rVm_o5*kR$+ohS45h;I;VuLhcBDQc6wSEW|xhepG1dlK+34%U>4U z_+4a7{0I(;KLjSgXxn@HHLjW zRF%B+nyP=BMx*&+G{S#Hl6E-btdnW2Oq%9W8I#UBX@cK~(@O$21HM5&Z1XH2(;sR+ z8qs6pvH;SoU%j;n*&F9PCBJePKif@GIGv_>rnO>>@ev_Sx<5NE$|=+5fTbI`DQg9u zH=PiksPqR>?DV!iR|$Z{ZK5J%nLlMPf(L*M*K>J3g6q(^Jy8x#E1#8>%P753*X*{k z)m?{BCtB1JObOb9$EsDi=|NC?l82A6jqdpPmfwdxgG3%^@CgF7iaIOM^ za|}e3s5lA&FfbF6bvY;?C=~|IF_bN<4Ob3404zZn6~$(tHPh|a+*S-Md?pBtDM(2Z zPc~NyQJTg!FVa*qDGn~Q79v#0k+dlS#t2$!zYr$zi4+6*ObCMe8ZpVVo^~Ev6k1Aa z`$6b~ORae8*ch0^L{<`U6AB{33|eFf&4{EKdLH^Z^k2(ewt1+ENbVd%EUV>e7qRQ8 zu9Mm|yQX>^K{4Dtu@&{32 z`e}hHnDU3H{Tx!y6aZI0FHEngDm?<+cFX7w*yBT8*XhYr)}p$A0BSRZ4<10_>v3J7 z_*iK8+HoW^C3a!92U(0aAEC?+ zr7l91OrsJ-3C}Dl|{cqix%BTLAy&a;$C8bIrvNb(hn9t@;SJZ9fD1rn2|>B0fn=J_7$&9=jOhk2 z2Ie)j@7Hw?u~%Q{LA!;{)vG;l99Zo^yM@lxt37ZWNOj#7h(|RC_g?mkZ3W0}%|5t} zhVEUQb1rcqrrH+vt3nKbt_ioKDVjp4URLdchv(Y&9KJD%6CYmvJnJhvD=YFI5GMuv z^$^}8^6_FZ&IL=;ZMb9@&ZlM{evGB*cJzS;hT8ul>kQwR6L?-mLgFQ2s0f zhr~VhYmLYfStAoNCtESc-iz0g8^{H62f2qlLS8^#NnS&UTGUyhiYkkvxSUriOH`R} z!c$Ptg#TR{tJhYQGE=%90pLaBSrwNRl-^F<@U4m*IzJ&r%9)vvbrhGA>3k19_RwEG zviYseBey^DNc18q-X1#sV~Ecals@t>?~Bhve2fZf*qt2y_TL1~;h(s{Z~XK`@Gmem zw8JkWa``jwU=-lRPFOwi$Rm#opx=jYSQev{ZQGXaWtL%Br~IGgOL#)N&%N1bS|2nl z%lNvnX&u#0As#+t`@Rh?<{xu^&2}g?jj^Fq>gnegWz-6MLWzClGQJ2dlRfefc`G3x zlmn6G>gfR-cq z;k&+R38_)a7}FR>+;w%vnCHw#6RuNegXrWe@;dSX@&)o$@^j=j;RIYDq*gf8pJ5d# zE>H@GQWYZ5{e^G{tJgQL=2cN+7Vi4-@Um72hr536=!1-ukjm6Tx4R!ND}_5XJza=r zA*!SUMLgg`Wigf4mB`R2_GB6i)6q0hgIFe1KWlpkxiyB$a$)aZr?JkhKbXnR9myN&J`r-a*72{sc)B0@ z+l6l~Uoi5@B}o@909dU{S}Y%ac)286E+2k)xu6z~j&9yOIwCqcx_R^H2*1Mx1%BtdYIj_(e+?_}6YJ`?4+ zk%)7qIG5MB5ES99lIMZ4sC?oq7@HV=Fp}I9T_4CyWkptHc{1##(PR|4>7EnKOkg&H zm^H%IQx^^=QPLTtSz2X<34=f>#bVQ}n`7z&tC^WN!kDa}tu9 zKuahsGm_mmq@}u5kvba)5ndbh|G0kZHNI6Kg{`fYJ3fAG*?80jAf2X~HR~2(H3kwK zvZGiebsjWTfY^fGx>e(ex+<$bf-$4l4MBNExcBv?lwd{9q%7WWFDTD};p;}mq#9wA zWnl!ZO zr#&9GI~0W>^7pldB5X%m^F)V zUg53|^-Fglalsm1PiY1S-`oj#0}#sLtqOK!NPUPq&nQm{>s9X(YKzxI7uUAguF4@Y z9wflKM0AH#7dlg;L01yf(;g?tIJ{zFr5m1-H^%l~4rDiuCu4v$_&_1@`O zy#fi|?py|uwOVV=!}!|ap(Gx)+pS8wFdBs_&5GRTB=`0<2*Nnl7V{$K3^?xZH-jM_ zm`zpBIrC8n35+D-L$ zqR>168w`0!F?6BYH=TcHaGyTj`1~Gp=*F$nUM@u7Y`}}y*)q?n^(I@F2)O zp7||jPriIzq?=wZ%4x3qWr<&SO`e~|n0l0O!xp0TUckxJI`*FNzRL5y-tEGA6_0_L zUu;1@KDrKR)On^_)NL}Lq~W|{kn;f!p;}FsIEzBGV_bAx1dvt=CaYg zGUDpZZRc=-fN<;tXio^|3$aJw{x}RP{#kaeUE`yp#xNxa_j}Ph=i2oTw4J>GLOAvX zFy+GcxtIdNA4LRQu&%xL0tErRJ*>b+K=iQL%kW{MAk4ro;M*w(XsoC5-W{6{#V=^d8&s>{Oe2kAx)It!--4ZQTnnia!7|nNrkbN51GXP3{>()@krwgU z3)3m(ELe)+-i6r=XqxS#TpMYu&3Z}7nS>!`x#SlkKQT!}f=lN6K_VG(PF!$nO2F4j z{I#YiM*ieM{Zv)b$;mx8&rXR>PVd2en9eTDMq(bY6uibnv*uGuV*MXo2YIGIz8?iz zGYDv*Le7|FTx8a2MhvwU7PFsqfOv$;Y{f(Pp{#szdUVgpG2!&|);%Z3WCJvqd$%$~ zQQw>av~=qXbp+x~qX@+iA@_GwyCGKBQH6&-bsfqit+yiPI2xje@X6V#iBO*b26b?T z4L_)Qhg)skRdt4lhA1K`3XAdOZo9jT>(suU89D>*_E>KFN@ayprSh{}>z>P5ug7vb zP&&_iSt(cKTJ>E){r9!VYw=po|3l*gXFJ~H+c0UGA~+1ny=fHg@|oCfWm9aTXu4PV zhkhlwV{S&o7@W*{JrgJrln9wiQWzG-<+;{9SMW}U7p`k`RybW~KTnnJ`UUIv zS>gAz$unP_#BsY7$8p?h$8i$w2UR_bqjj|}w_Dki%Ot92Wq1(f&0ZL<^G2>uCCN6xp1}6=M|a{Kd2jXJ=Xr5%hHAabP&(@g5py+JX90Dq zD2EWjcvzJ~oQC~o{id{1?3gVk?OKo{4-3^~9;>AfX}`RF*wgoi*;_A8Ciuhg;GTPd zx*1kvU?|J8G|OQC!-~oL$%?%*vebjc{PMHc03_Ce5<<)np?ds@dsCp3$(|(&iwyfe z7Ki7**V}CF`9t%Mex4BEHi5J%TkoYcK(GGB|2X)o<+R%cT?CvTw^~HSLFa(jLw|Gr zyT5cc_TBvQwbgRqn|h6(_Qu}5-W$Cy@giea0qxdx>L=3$3{nf-!#n9mByOQpD2Z zR@)IRu3f!0u0D7$97TSTSjC9sI566k)9GoqtSHOd?euRmmc_B+1Y3>A><_CwA$%oL0PLoRwD^E{6{dhxDz zj=Ns$^*nE<>fNlF5g^$}>P<~V5cqq{wfT;xZ@e%mavU9Ae{y$v+OIpEU=4@vfA}-M z6;CD?A3xYX_dbIFozC^Etu}b;+p6rvyEw&N&v;(7VXG=zv7-Lq=kK0;)%puoH$H*G zKSz1~LqDWTo8eudJGjTw-W7Hfg132Jz=n{OH9VFnRZS}1&eg|V$#uA^ZEH3KVMM~A zSHdH@Xx2sL+;3_Oam{*DZPSuLIV8PmI;M_*UG4Pz5D?g`s@yHM*CQZ@fO?`>uHNJ4 ze&FzAbYBaht?NgDl%dkv8L50-l_L$?`_^!c;D`M(_Gb?RasPdwcTx$ zEOv=h#zlOw)PiXYF~3;zfwF+N0FTzSQRU)hR-4n?v0Fy5OH+9`iLJJ~WgjQZTifmy z#cH$LNVYC?6JEwR?YCO}dD=pi|1lT{$rBhI7=tTJX(&lh+VF(@<5ez{&Yj`hnNSL$ z4HqiZ_N(Cg`Kss_zK>VXEO8DQOY+VXG%9TV#-fdOxko%?jPt&o{&^QWbgl=WToZy{ zFP-FhueBkp4IYM4QK%#=>zd0X2Bc|GgbAUxJs?W>HuwFnI`jRaHOyj7UL=~R+XLeG z-r*BZyiP_)X!0gMq*3?9yLcV1M7wT!k9sfIcBsvZxyfU1XGFs+LoJ1PW4cOxTluQ2 zR?AKOli>IHX_J6PR&N(uR;Bu7>m1}bvkqjPCC1rTv}Xrty2^q!xuZ!xvaak0Moa^1HDnB=27y<*p+Q<(BP1kv@H}AzUAS6dI znQRV@j%H0CRC2&{~?svO`^FP^NuTR>8Vb$X2Klc;IXQ$)+&E|A(IxXU}(_@bt zuzT^v|3i21A@8#HM(^{z_j_OOeVg}b?_Ya=i5N95;0kVdo|v3rw$d;Eu$C(JFq_xL zSpCgbexTk*u3L`I;Ei_MD!+{7V!N5uvdA$<`Sm2iF?9M?ufuD*SBv2QM~ps-G^w$z zWKDKWm>11Diw!|DU1wv$Owz*OR=V$s<95G~_T=Cyrc}LmDZVo!FxiEgEt*NKCVk|q zXl(6OG;DW$#lx;+t1{o}qr8q!+2tZSyxDa#uOnoQzKyyGE1|WdyPJ62OQ5#GL2;3WX3;7&52fic|z#y<>u3ozW? z0&bMt&v{g*H8H-30{_+%iu9pO(UPqX2m zEClym70PaxyZw4nCS0I^7>}+Blog3HqOuwe2QA-cVxOa`z_*i))%9ezyYI;h7uZjI z&aGR4Znfu&>(4#(@I(gp-{*^Xe^gbRlBCxzawo$3@3%Y}435X$PRtn?S9&*J3`tzN z%vt~9sMY2o30tk+X^Z&fOM=>G4?c5ce%5JgcjfA0KF52z z_toAvdf(;!fcI10uXz93`y=l^fuZm`%$n_PzS=gkMr5UTwn`zYo~lZuYUq%DRjZFf z(IDbjX;zAto+8UzBI*Zotg6x}GZD=(Q|UBF#LTv=h!2^WsqL=8^t?Y>R=%i#H+Tu$u5G#*y0D+q|9%mEb{(ftR(04a9HG08jvvu{K47o zp()rwQs%{QIA)BPQlmb`^EWFDNQmQZ7if15zp~e=0-tjYj3;>|<-4`6DruD(lr625 zva)M^7gSYM19ke?GVnCHo#stN< z-%@hYk2s2=*2YGWeRq49CIRD;Xk6!&5bZdMq9_XD4^iY-RZqz(tH%VzQ!Z>2TCMhq z5~!-#w`M^A1VNTP9|Iy{LY|DrzO%M3CFeuuoIe~MX~S5U7gbdj5s@)RgMsg?>jSd< zTMOB>*7>8+u~MM0ELv5OM=xs`BXzgi2%%Z8E#$urd=h09245gp5ClP0+*f3IMwDfF zkr!DGWO-h!f}p4b3xY?2APAVKigzR#kR?}@wH;zWyT`QF({@{({|_RU`)L%#KBLia zG=6OvXr)^1J#94gI$X5l9LSPE7D#PcLbm%%NjVZyyV)_9X#lrdav-l#rs9?-+6!Jc~f5d z^%fWdd>+}nda_ntl}%9>tFl?U2Y}ERLmbmFi34z zrK;%-AROj0r}!`dAd~qaj2h>OBB}5e#tTa0q{#NVae_Scp(AHBimWL7IF3e1j39{5 zzeC~S&yEN>$Yn;TDo_?$(~6Ab^zS(sJFwG9IX^hl_s}IX{`R7PXxpL=#4A68V16BDC2&@m-{qLJv}z5lFfq=%o|} zW#*g!I2S5FGPF`649n6waT(#?W%DF(p;n5zkjezUpUhbct-uA*gn>`O!1r79t?e)b z*aWx?5`GZ$QVN4Ib52bDr0+vnG)+;aU5hUvAymyEQX~~oa9%8&$2AuDV!oL#&qWWA2j7&ZB2yZ5Twh2f>y+g&l=Z7&LB z$OXY$P^H)-m9b_vvu3?{CCh^Ap}U+{dWqGi%8g<$=Zkso-md1m5+c7!x)t3obf`); z>)m`YU4LF!GbDFkaON=^r@;RlcA-yfL>ypb3(moUz_|{HaS$`5uc-uSV~mg-WhUCT zL&mHXnY;ij!Z>yadyFdyBxNg2mFo5`J-l8!8%KNfsvpN(5@Tdd91Vwu^IqSC7cSm+ z(CiQQtmC@d>*oPLh(@E(*V-TTduamA7-NBx3{qIFGA)Gwz?rX9V?dlqBFQCV znczy=L^_*65+ZAfa|!gMNwx89L8597f`FKmOag-YKB20P&tDqFkui)XRn8b=0N@5+ zK_rwC5>Q+!kw{XCe?BKbDj_7aQ7`9)#i%Mabsz9_z<6MZj2~DIMv%tZRx9y`YqOqV zB0ob)k>y2ULnTa>1!R5{ItwA)n`N;qW$<03Bf`bG&5}6HvyRQuPJ2)@)+&4bs-;LN zp&6G-Ybg+ChX+STzF&o9*`IWK!KmHN0tY}AMQ4y@Ob33q+v~-tEy$x})JxLDD55HG zE(rX9%%)*MWcNB{NkL$p;94rq3vDRSZOE__@%DO`(hNaheWF%AV4SO<G*jrqcEZ@t$g3fM5&@Q8z7*=C@D2UV_1gVhC(D- zwFSDKocTDE7kVCQ)zn?oVpZ){4tT>$F3dmq+0Qt5`KY}~YK6`!#cSgVR zE9ZX*AIffwTlzj^p7CPO+pQY4Q(3jkSl!gB&VKHZ*=+V3qfdTv^ys4Vw(k6cfB(7X z{_3Igzk2O!k)QvUTeq;s>3z(5hVEcL!!A+kRo)2eWuE`w{YTH+HMOdDRo$pnQ#G6+ zwe2>mqTWT^Q!Q#kpUSR*oS-D{Z)`oT6t$?fTPuCKMcc8`9n09M%}#AM+s!WM67o)$ zY*y8(QLEj`OYHiSV!mjqyvnPlDgdX1o2rmXh`ZL!rYa1h*?Qv=EjWKI5#Ystw;a_xyI`pxv<^#?yGgfYG!hQ4o%5JDJj zL4FwevI?0(M4T&StaT=9B z12(*jcj5$B@g&{|8$gYEF;N7j!TX(^FT_;>C2PHBum>#{NbHGzGb3$7pi7wfyK<=z zEK>4Hs&eW=W{MEm^bA*p-XgmdYV&M_8WehuWNL6s)ST6`g)j*oK@TRcP7ED8C?>Ua zNac-PuWEz(dNM%dvN>JM7ppN$ehoZ&H(#uB4QG>IVkHupnR2(?OsbVr*Rh&f`+PCq zZ8t(%gbNfb=8Lj$YB1x}(-qIFW{xV}R&&0j?QU)n29ZolAbEM}`GW31a2Vq(q?7`= zX&RkKDMnII7{rkf2!bFW>wL!`eP6myEF zDT1%*E2wa(odc9&fuA3xDXgiwVF)5)q(DxLM{yK^(f|F2WUUfFYVr#tLI_D@t#u%! zP`NlFr9sEUrG82qA+a_WWHf$J146Jc1O+|^=g=mkFp>;HR%Hxh4!W3-K~NS3FJfR} z(C1FtM?x5-S;&cra4;Apf-@;3iefq)kC32^I|#svTsscIL20Up;0Hkfqlv;ufTgKX zfY9w$2xB0m)=^x=pgIc>a%es!IR}Eo3IPKp8PmFk02fqc;7GAAC0P`KT2*9eRmLF| ztk$|5gN%VvoSdUeEJ>6S#mG#HmbF3}qZGav&ME1FvPv^Voi6)m>7gg90$JCNw2nf) z6YIVsJHEfY_{F<;JMKoiI$0%8E?JFQtTwln%Qvi6Z&@=iXbV(@MW+mhq<6^-<7H;t4$36 z?1(HdzXku$Q$JeQupMHqoBf7ao?gr@G{X~ohi^1>I}BR;{Y#e~x^!t6rAo#|K|q7I zLP3yLeI_wA%_qfq!_(nli~JoJjfT4y?`F;i%UQd^XVq zX0qn_f15BS%EMnKQWM|Y3sBYxq>iF@L2JL=_O-_Q-}bhD++74-aR&sx@B2hVf%Ajl z#XASSJHGGx{sW8)!P$Wi_`{ElLi{i*Yz##3UAxsh)R!uWhGn1iOLr#`EK>hfk#j(? zjpM}R`6RC)U^Lrv^cUCnvy`IbD`&=H2v*z5%58F|ik()n-w#L226=Aih|JG697p0LwK$FR{Y<6s{6~cGs`QzjB-;T<%EW2@nFpLU@ zxZP^E=#nWi3gevUrExqOrD>jzM`_v#ti{Xm43sh%`@W8$<`}waGlTv_m$qyqp(0;t zrTs5EKE|2(y4-hwn6T{nEC{~ib1dk9fZzc$wf9=MLmh-wX^jxRL%8n%-*2_76~a#H zssgHNvY+K}V*@E8Ws*p#{!QlGKQk-Cvh1+Qi!Xw{rG1yCzQg!CJkNvYUc8I<;I23K zylh)7tFqc0>Rj2ZnTs}DURxzv4K@_Zz@?Dm1&h+17Ty2-jN&`vK>y1YJ-ogINn*MlHmH48{ znmDSec95lENc#snyff8Ws3dLqo&5_Jw3|n5W>*>5YI*J2^b}f^_33F{6MDVFgQJ1- z?Yf-2@*)rP4t$w+=DpGTGVeFMzeXRg@jOLH)y6HAbbg(=lOs&(S^Yg)vu537BbZ6h zec=&i70w@>N6*|^Z`O;=)C8m>?dDa~EVg#XxT65oY3?Q$AKvdo$uH(y zjQ6OLostw7LqPI zHruNzCyjbiPXGt=^H$0E>6y1>ClX|LW4@-La+RwTpPBh$wh5Wy!nv!rMx(QNr}NZf zTsXzW*=9QHb_fL^MW=nxJaH3*@8w0pq3bxHoPn^81L#f$p(X2&7$f5R3{g3QZKt3=e!?Yknp; zDeLmA#QF%Pz4J>clSC=almP@IDKiOtILoyzDVX01v=ZT0j_@E* zD%mSq?bbj6hlGgQNgPK*T$af&R7$BZJY*WOog^bhDs;d?p|sJO3vfWlEQ(5NIEw({ zTnOMTO6E=w?ht&}@^x!{9738|{%C1M_UQBqsz=w5Cc)MCQ2u#~tfgyB0 zm218E5+p^g1vlL!#CIu`ge^}GrgYXZBBrq~FVprfU`!k*J;idL~(1=+|T*Q~LU~z-M%zl-z70W)9I0vsINmCbpCis?6a=sPNiXgL=?XF_t28U~wgjl*7y=Oq3H|RuJhxXiLS2=4~h0R8QEj!@G-tMQ@p zpY2e(+U($VJEW46JO7t2T>JbdKJ^2)Uby?rd-1)9lg|0ij<7Lqcaj)Szx&-E{_y$V zyz`wO`Vdcr-_c*hi};6L#~XTk-hp>&A%=$&iv~O_le?ncT&AMl}S*vf#pAZF0K^e0$^{q-; zAkyYzsxtfkumi>p*sI%n-HKk`UjZd26Qu}om-X-mwtdOBvQ-TksM~9D<{T5FO~Uzj zT5v>FJCDKRL<@cXf0I@#%fJq(Jw6)@f#Kk+lcq@0PSTpfZ}zngI}~y4=L#@k?AI9k zbn2d9p!5Hiv9B^8ct3NFeNhDVRdxQh%C(h|KuG+AY=kgu_oGS&Atl5ovC!PwPM+O? zF=ch|GX(Z*hT-7sbU46|r&+t3CREjKn56h0TKm4yS_i(?<@31bwdfAs6rf-5wImjE}OzW3h!259#0z4z(Y=k@FZ4;~%?M~4qS@a#|Dx4u!vaecUA z+~K@w+x!({U5aK9x)EcJGq`H_lVe?o*z*h>Kx1sosQ_fWD`Yqx{`r4Cr4X$?aBCc= z+0s&$1|Y9~ITv3gdA_-s=ZX5`(e#Oy;BXai-h5(>q8qlFf%moE+6%s>M~i<=hj8<9pg@0*W2y!J7s_S z-f?Yzpi`<3`q$ne4}AOV`0%gjXXp>N4U}GD?9$&S3hzsj(I`nAJN~!WcETX%JP*P_ ziNpU#siIU#CU(CFUrDKYW2L>Zm_>cbsl~BUvPbSAFC_0FpC!+bU$-*pRekFUuyeWO z@`VO%VKtuz*0L-_<{kB9o2Uvi&T? ziO~QmshLgF;(Ca)gEwr=1ov%Q(>FE|Fz)Z} zZtt`$$1wuC-LcHkJarRgB_~?(H9}yY9+lu_y|Pwo|UI_4|Fr zI4(zFz1X+(w{S)QD5DgaltKVf*On5&8n{lQ)6SQBea~NMwd1(e>UD=-(Y3&DwML2S zfnj)lMA3KMFzOxt3qsgx`+<%efm(KwG>?K5n#LGXQwWI^gw!lcdV+hdy=*x)rIFAC z0HcD#{iX!YD5KOeW8E;`sR2-?NpLM2&}TX!ga9E|{s=F^m&omefRIxmr$P!TgAv+|WGVkxVyD^Qx-a zw(K=X!s&c|8-Sn{*Y~Q$q?*=A0@!X(>$0pc2;$iESLpMt7RAH7*G=F{S+i*~G?HH8 zn5JY@24RFrGSV~;G%Ybr6PUP9LxVBhK=53OK+$}3Z51fB?OxX~0Yxw#t!##YhVh=h zRsxSS*`l{(3<1()*~Y)Rw$dR$f3UT6^&MMVfZID4ZaT8d2v6+r;g`SsVPX1f(0-Ps>8oHkthY{I zvsJTMau)_$Tc=NKZKWx!)7{;3x9n_Fs26wNy1gB5qOzr|kH=iGf5~!712VsaolIqh z){3(#E$XC9>bd0!X-d>m+XM7_cVQv*`%t1X-(|UHkuUiCbJ@h5?F)NF5k_#gjH0Bw zoTlwgmr6wH*z0TeUG8m8*6-EAAnc@_L7F6*;E|!5M)F#*yL$^f1A}3`b=4|(pW)Wl zsr*0IAKkLEjnHT|ntZu!JCNtSG=XL+3LX_AidNr-zQ4DsOrt0u8OECCQPdgZT;FcB zFYFxI2cG>ca++L2p0K-0&ViEiT4iw=#gSAX#Qe&IDddWZx`yW!SvjrCDnp6Sv!N(- zOR#KvMY8zrnXP)jQA*qKt*tDDuYCWwu)TxkF{V`8$g;H+Wk}n0k}%Znyhx*{$ag(} zv+Sx4<#E3gn5sB3(!@=JQP%C~aO?Iqinqcu1O$mPqV4zpeb=qw;QN%U-|bOAyEkjL z(Ai*=nMQXDWV4|Z{#@9zbfEzBO$%VzFvlBF#2DcA_N|@fk>f|V@|*g!xq1CTKT(LH)Iz9dU55ckCv>D9ZEg+jeLz^8Mqh zYUz0AT(r7!^49Hb)E-(R@j+*+uz~_9!K;=xRFdG^1JNjhr|vT@l%uTQL)_lJbkP>gtUvE99I2w8B?xE7hlY zol+n6aJWTPz*L8XPPUn@_iS_=$$z-LZdy8>Of9GXfcC0c8AZtr45FyhY4~v*jhL=G z9oxQkZ63vxwl_9*e*RfENxY>fj=ih8*S6Qzstem&R0gk`>+mQR#opfW%nhdPj%7;W zujOyy^dzb|jFhe;Y<4^F;Rl-l-ij|coeo!;4WL`w7urqv%+xlGw#Z3xBRk_)Xl<#l z4(CJlEG|3XT2f_I2|l|lS*_58<8NK2cHj^D>aDE-<4E_)sj3Q^4N4o$0HP4MVp{G$uApi`+@?^Vn&_L5HyZd|5 zxi#Ea-`w#$-_2LU)sP%ZdX2mDD{ZYXR~X`2TSbUf%Zu_T!>an@NT$G#{Sr6t5T-rfj; z%_ZMw4A!R8b@5U8eXfcx3W)0B)457iJtyWgw%CO@lPTN+BWA&Tns~ZulcJbZksO6i zeP9J~RK3%f&Z{EUiuN=XGOJ3H`jBd>EL4b0Ohk&n4ZCtqxMuzA`fShGiT{6L`rh^Hf&(|F$B~lFxV4O?NkQ9GmaRDed%6KcF zD4#f@1L%OZwR0e;e!ne~H3|CQZb88Sw5P7-HSIP8s*R!z5UC8MlNt0gU zFQcerAId6|SuA9}2U%V$cA=WriHecJUOAV}LZ2%sGpVj4=cpUVI2s0WhK7!Up>CiC zsAQoq|U%Tp#8>-U)E z%_mIr#%;s6!_on?wi0IybM<=DJblJAZ@StvcMeSRywVV~H6>=)y$HfNR_gj?j#=Hm z61U!}MA20OkhP(TO9{93kDDrs>ntv-qRQ(~57_|rTP#@EfX3S_Sp3W~nDrB1dE$u` z^=kY^uz%bJuoqzcgoR))Ui^@SOP{#ylb`&~zcr7NYsdu*brm>sL{MboSwOH*x1hv; zmZ%11xd6?1 zFmxOJKHX>r&0e1hX+ORXvawEBuyo5YW2*@H+(PIE0eoVz_mP(K6Hp`Q* zQvn@pN!g|>&+M-WtpZIL5Qszzt8t{ zqX~}NU_7vGz>Z;9&T+?hYVq^02FGbO9S5G@mzx_1QZrfrTq}YQqIfijBQVTnz`0>| z_! zY^ljKt_5LiktblA3<5Rh^`y>R3OL^D7#C7Ss>mbuu#>4mrriWw)#(6OQRs4OBl=y- z_Cx|blX1=sLm>DskV!Jq4cl=Bp#y-L61K^hEnP}sVCX5Ii(3;X-zWxM+hi5d?=WqaV_wo(b+zo;to@h>ZK7X~={o&N1<*k$AuD zCJ_8CXqutxjC=S&D@lCD2ECpo05#2bw7>%Z3_}4hid_f6i6_(P>aZIIwgASBX6MMY zL(}r55TQUy&hfg%z$zxY^LIlGhJj#?HH5hLO8Y@B%{JqqU~S)K98qu^3>~H5;yz8h zbZO9U8aY>jn?R`(_XnY6Mg4y4A_cG~owj8ww&hhdRtQk}VIkyUsKiv0Mo zo6a3Oo)>^8jz9X~Xt?x(6U(Y`xK58Az31-T9mJE2YPx~3p^ykMPLc$FWh+hLFCDY* zc|p*zENE*&utxjO>a|st7Jh8dT3xHp%q#oo9@npZQ9BzgJ6rh}2ZK}B4k$3nK=3G9 zSq%fu;G2Gbu$0#TjKvA#2xp`aG$9xxT1UylhMNt;kjU%eiB)(@-->7FpvTa&W#Gv3HUJtJrun8lr0Tw1dyW} z%KKFc;QAY|;W7rA28_8+x|A7J$Oo3GJjdqa*a7(#L$?QpVc^8vj0C}f3%wm9v~ox~BvSpdnANzx14AzeEYG%?Ox%tc$9lkii&N%#yP|a&qEPe;& zOvyUAiE$(gmsnl7mF#-$?y>K)syAigXWia(ws*&oT}pS4-0}R8@RP#1X3vZ3k!p6h zZ95igx728nct@{s#MyI*=dT~@FPLp+IkwF^tz=Zk-rhB~y#74ExwC%$uHvwarB)Jqmw(rPo? z{)zo1QS-`WD7a~kOyUxiHH*YPxX_2HFnjpDNh%rd!zSD}%CeiIvW%9OZ_Gxcn^#ui zvW%g#wzm3;U*6gI<=g-_kMY2=a&gF$$s|IKSEBDC&^RfRpj;LZREY= zqh9a3cP#0@M4?n<6X=dG$W+Yq;0BqHYPzT^6$@F&R1Py%Ke;^Fx~TFV;8Qn@^5{(o^L;a~PU6+^wT)i5_BbVJQSjv;yvFgFA z6cbT-M?MJSDTbMd1*bk17?d$h+S4j?4U~s3Xkn#9+)5@f$E8k=h**pQX#{_ z{y-Lj0G2^X=XatY^rIvRDq%W?MXndvJ+K=Ldp78~h?$NNRgff+9|qA#fO`F!vHiot zPMFzV@35{~#`k^Sw5s~B*RxsJIXv8FtnT*+BJmyI{3P)m;QS>2j(o<1PB5(#g}*Bf zRTzx&LPkjv$s!+xfePbZkqw}=))-`YAK%waE?s)ET_su#{VZfm>!fNwdFfKp{bnY6 zR$a2KCI>%_Dm`LkNWUdkG7EpadJv}8SB#YfZvM4Jdh7^Xr&v}iitSZK4lx5BpEQ|=Jh@woY zqC7cygumqEq$rg{8pRJ?+iXVTqo!%KaAUQs>oo0-$NfQ;T{$}H_rd^ax)fnVb7OX= zXAj)IaFH{Bv5OaP-=3fDjG6B((-cA2>mMCm$+E#w3AmfmVCg9F0et%{3&+ z2?*v3yNq@J7!fB)?0LfLzjzlvguD0zeg*#?=hX7NYPN|&0D80pRtZ}fT9|ph z=6W%^uBail+fk5ADW~(yh3JKv>&z{a7>ERJRF5GPZnm}d0I3x5b7L-Na%}!_l zuxDYG7&55=9IeXhSlMppmxX#f_FtS2wd8+tp+|gCPcB|s%)V#qoGesQ6=}3K#i~3c zBB^FCdpc(0S7iYj0f|Lv)oJYClWF)gbsfI%o5)@}cD!EDV z1up4RRk@QY(p6xX%%6)akw_i6{~o7T3`F1*0V%wl`O<$U^~4HpdrmVCWj+@M8~OJP zftW!l2ubyj$hr8jGB^M&xiB^~EU{OonQ=$J`b{wIh!Uy))Qo57fDyQEfwo8=!w5=o zrX42T7-=rK3;AH65)2Ytkl>s#ffH&bF)pko#yF#;6rUF{a7NOXXh#SIn#s-cOVo+@ zNdRH{#w8cRNSpSFfGffTyO#6?0~e$eeN}_0{W<`X2?qx{YIhL9LI5f3St1~U)wl7W zS!|JG0q}Idxk|-NS0(W}n2giH*{i>G97Y`^X%GFQJQo5*-f2fSn9{03j+mcbbe!AXDM*MwNq2>K(q@KB zW~|dZEF#9Egmd3A=7KB*e-KKM+U*}RmH`@`?MOlp5m&}&CamGBL+J<_9 z$F_HaF(%=8&*G98g_qfZ#FeW!XIwLtDy4jfcaU;ck_reHu$)5(FI;P3i83yPOQZ>z zsMCt`^JmR3ZRRDeI*kVJ8b`h(q!shuR7v#`)Zrb%2=68$fw-mMyPe z0Rgq%1icS*?%w)GIr;IweALTyPOJZVmC8?dJpIb{NN=&Q-b$(;pd~=4Pg=r1^~j5X zvv9~T^kjr`f;wHN9(|QZDPW5{iI zOlsaG^#t-seZAP)^i9lH+tqqAtLqc!OR(#OB1v|&+|3uu&3d=Jj-?waDAVa3MrXU4 z8z!NetDXbJXEr$Pyn5HIAMIkI1e+lXspj>1GryX{;hNfRw2PgM;x3<=hY%tuTp?c_2vot)tG+8bEMsfxKE}vvP%`W1a$pkTM9O2#m$?x+U1z`#c0)Aat(C;s{b`olfH@WcrwGrU;VO&}2w5PKk)+1u0r)a!wFp zf80t1(=rQ~5ovcEfjJZ8o#xE<87Ff7oAVYCV@cpx0*E;iaK;lY!tXW@No2H97R@|e zy>>8R6XQO~Y)siW4xYqXIE!sb7sc6SJ;s#P%GU?VW{gW6U=q+nk-;7VOPV?Y>>CZq?(WD>_= z7;IlIYm8z{NU4nRos^-IVzv<&3*tDaa1o{oZN#L|{F)5cV1}92;=^plq)L-^1?GfDc@=BOzZ$$R?loxLU8VUtL;UM$=z;uVF9>5Y5+|MxZuTlU^}0b;J5nyhEkMy=F4rT`6(gLTGa&t66*L$NExNj zil0SySnKi6}%j@m-*3k*aPllh-`eXNA@Q zW!!;S%mq-kTv1WJ(A6{ws-=3NJ~})(KHQt$I#rU;>kkG(#_?uSFe;P0Dv}7R*#$+C z4TpJJ=29M>HAh+{QIT;;G)W^)SzaxNLxRs4Cq@`*T@Hn4A3Sp9)~yRyMkQmN_Te9B ztqJgbe4rbKh?Fo(V(=MpfMjwqnD%1Fxo<-u2!IvNGVLcqjH;YV8Ae4*FrbN?C4WX)o9W?bh5hzlrpDX_dD+0fBAkP?!SEh`~2rR zo#*`b4cj0Hg5Wv-eV<*<_V#AWXJOs#bkah4OPy|wkAG18x(8$TU%vnK|KGWs?d|MOQcWvE`C!7nwt)=RclR)%P{ELVfCZgu7+X?ZnKxM%aL+EFu?Y}It*`(8G3V7!t>3f%J-_^o?zCwJzw*81Zu`JrXi3q^O`19M6FQY40o*VTq{L*KxXRC{kKX>H{ z{o|s=Wvg&m;(4Cuyxxm<@u#@!eZu?O-cNg<@_xztP4C}$f9(B*_cz}E@jOxOs$#p_ z?kd0xkTs@C)u;wyhrg>#=V*Zt&DM zv&)sN>;nhIu0r?`sz%K;2+U4@Rn>h5Zg$nKx{hYM%Zps?a(Lu+zKP>5*p*e?O>b!B zHATO1r`pY$yvVDDivDQ6QR`iDq!Ha6JQKJQWJf!ED}~P+{LZ2@LqhJsJF69qSqh!ob$-K zLFOD~S=>%jl(4*GShmTh+NP74RQ7l>&`DAR(K-ySe*a}FA$%d6^B;?yW|5NPMxLc3m%2uY%dvOuV$-->)SkY(BSt<;^py=i>{XGeN6 zQxi2-MNibB)Nz)@Vo(v;JWUy*sEEQ)_VQfVz3EvpsjoG!yrTF_EZ!f-as2*;m~nOG zmCd!fj?bohR^)k4hGA4h5m=h$mZ%ztILl%!!&>wTHC7Wfo9K~sIH{+5dmSyU-!4lz zP<~VtuXaihX}3%w#(f_$55wT0d=HAH-BZTXL^Du_e%vWRH14}{o`}pyCeCr!+xMRI zzRdeEPFdVV8*;UpU4xaZ7A?lKuZl@CYceT4%HxDmNfiPaFWc@`tq~0@TA9a$JP5ih zk+a5Bs})+Ym9o1ncM#gEn;Mrp9?^_~UES=S!71*O?fMalQWaz@t zQLBYXuSah<>}eO0FLWPQdE@`VTn| ziK7Z=RR_YDC@j$HO`@>VsrQb+&;M`h`1l@x=%lXWqAWNc5pmY*h0#>0j3~|1jGgBq z|HaSZ@7-Gq!}h!*Z{uC}Ugv$n`zh}?aWCHLdDCrtr|nf)srf~)KcpqDTf3~xoauLfirPmUOGOLhdHuWr@D-1jRk|pnGN*mT*p_RoVGcRTH(CG~4DiK%7=>DCOpJ z3VIQwq1aHvB+at{P=VlJQ!9W|LpDkYP&qAV7_!zGw!7sbUr3b`h+>v@aD&x+1+pKu z*b16&@GuvQkuie!R)NAelu*)GWg-&Ba>QHnV8bZMVkrgWzhi=N$+feIg&PP`&Ilr{ zIY{6btVKIxzV?09G=AX~kAcDPB#=T1bdQe@4%4g^N$@;tk8a+&adSY73n|V&lSUCy zmKLStT9;WBa3M$sK{Pu#=?Y_jJa63`{QoG54oh8{_SzjmoC}B|OsqSo>xdwQ2pJLA zN)Zc!NJt@NoI+?N6(hhfPRJAoYwBLlAePejgW+%(gGPIMEiMJdSqjj%cl%%j6NCW- z15o7H?Cn|nQ$V={lo+WQgqD^wA_gwFM3ct45{Y13NXA6Y5^3JYNC;(vKxw5R88cE@ zDT46ZG7~@%Q!MZ!UFAOuRa6x5cr;Kt6;cS9SFO|2lhevil1`G`Q+cQ(mrcuSSmz&*Yx7k%iRaC{l8jr{K6;Wrtq0<>p z{`25mzS8Mjx%~g#8jo*Heq?M;Wv}zs=K0O>_~x_Br!PNq`H?JpGUF!X75`@H{DO&6?A?$j`#lL{O>%nSQ0H4k376s()mBdbhZoX z49^44BhDuE|8xHwxEpDAio~GvgLF^33ZhO*qGoE>6tcfB42#tU6B-Wd(I`%OX@-v? z%O|IkEW^q1J@*_R6At#TmWQ8w^4y|A+}gh7cfVW&zMo{HScfp^@b#sl+e)%@`NY~9 z;@aAY{na(Ow7;Kg+uP?aZ11q&C3dcYUxok2(S7R}AzX9`u@VkbLjpoiF5EShNMTXh z02eH&63yXl)r$f?c>LTx@#wzyD$1eLea_wygjQ>5X>Fb%J_qtF&6j+iQGnrKW3o;$ z=5ku&$-7S}E0(TXq{BG&f(FGu2N<}Hj$S|74+GCv$QHY@)XDE4fp?NFDWhYxq`p9j zO;)BH&7EFF!qkO2m;5HBCmNw7xAtLC@EG**W?0SZDM?r5X?55wrmCmc#~+|%sS83) zf6{RR|5I)hxvu+hH;UYsb-TT#qW`IX3;a)cVdMtB>-Lt4-uF1p;eUMU6Z^RBw_oeA zz<1qGIZoe?yY9>SMbYneKlSJv53=hA-R}4J{;i)Hb%p9T!R|{ux!TV)d9+JTkaK#? z1#}eBDFzo@-i`6?PlCrs<7$_5;CnO_4-6hM=cbf}nfC^9FyJT9#>LnQ2*OmS|E+ zm1t6G2|S}|PngjkMdp*5_T-CV?s~Wff$#hHP{v))aq!_Zy%`-Bhk(A1d5EoM>jV%r zTNpsLR5WHz1sIpsA%Fy4Ln?AN=b&!RL8{u*Rb7i0ey334lp(B=P-;!~RE~7yrQ552 zfyiZn@O?d%=x)2^d+nB|C90P<8-P^TLnjV8?dV9WxfiwDp=zcp1{;l{b<7xL`VtgI zIx>!Frr~$x8m!B~K(51@?2dvadH}*}0>8UrS%{Xk()9y~lc8x^&DK2MU9)X~ssga> zwPQ=AYG}GPRtdcLD;dJ@B`+BQW4gBLMY{CgV=`4TsizMPQ03=sS0;4Qd=z84X;pfj|aLac5%abc4V_b6A&^0#*;QVB-6D$u~v1hTmme)0@e-5r#BLXb`F* zY3dqh-$h-EI2x1!G9fI=KFXM`Cm+#oc{P~QvJ=ffq|(q5+ma@{`c(j?FwBN-N{VP` ziD_vjz^e$!o#01&PBncg45!ApZYq(@Pk-TjuTvEBc~LlM*~}XBS62E1i`f>!tqTwT zde+N~S=-EJXf5TPDYj%&W|RADMPJU>$@NO|1`>Hsm(Ql&_z2`;at8p!FVK`0REttd z!4~rxq_3jfy0U+Hx~S4ZB`*+J?3>KSCHji6oRzadjYvgtj_L}5KbO5;kq?KKH5?R0 zuO|djibC{yMKKs!)^M1=lZzr!{#ow%-~-%ld-L5G&VPGqsTlDN6JUt zIF5V^z&*kFRe9kDnr{AK36!Dq1RrXR@WL+Ko~aA|d==~pni>i87Q^KI??eE8O7J&o zrKXiy|9M=T;IR1dw;*Hu%`nrnLs!Ztd+*}ZM#ftIi5KBbBqBqyWbcx={wu=;w;j6+ znpHBZ6t zdLb*2l#9At6nQZdK-XQQMBBo`-Md%zpxvZA%S(+g^XA1c0?aZnggS=Y!z;zyF@)As7ZkF{K_A%{9gx zid35Ijs}Ja*UlJa5`2Gj3>?P|B1VX_p4}Y^4MgURRgLyZKAX{JGY~=Z5o+QBI_-K8#E#+75dfxNO zC!f5{FoL`ojUWnphd*XJt3|IDo?4o@9>OJv!rtL;_QD7tjCx^1C8<(?%|^4|Y#=HX z1mO3>vJCs!ZfCY*+yAo{MsWCNz8@eas?|gEeU}hIT*9tghX01kPmN;6DSW-Gi=U)2ympQ|(l-T2^_%B5{ees!{kvr>b(-#T?tsn%QF4 zN{QX9k1BT?HQUV>JKqFCczdWOX9%p@U(Cv#?NwRr>SEbk4SeObYEf2!R_)emjX^O} zF+74J2F?*XbkB~_tk&d=)|)V;%|+UJ!|P~fk!DVBce3&eMTqQfFa271uo%S2Y&nV z@o}e3NHQT}2pfw2N${9TNJCCPYD zR#GEWoJyNPK?Fg2e0B<{aNIemYoE%%m{^Quz7!?M#ZgZ>1N66z0wGGnco>>i-}f0w zO|0A9B% zttID>hS^Ffl>i;Kq>P9`qQ@bmVFE&=$;c=qA^FPKf38Nz*Y70Y#%RP=*`G$`Sp*o) z963v*xZtD`!K3am65r?UE%FIJ@D&3O`!fTcn6zY?Tt*ZFQIz8f1QZ8{XIJRrrB?~g z!U##C=ecTn#G)l-5%?MwC`l00)SXm$*MYz z%f@#S!1n^cEwm|XU$*{!4+0CNW?GvZ9dBCj-~!xWrr-Odq9FlHI!N-2gVlUxY4 zQdC5aAY9T)G(cP`4d#5`5EPUoJ-}>+)R%^s?+2j~(#v9!C@>c+5k>L-Js$$bB1vGh zvSvLCk2b|jO^Z-Q=F7Qyss9ZqWwx{S=Mc$D+Z5PxMVVh$hoWXD&~uI{+G3K=0Rcga5Z0* za@Y0QZtYwHV!T$(hBI%+Q2xQCosYAZSFx_jUHsl(Op#y4tXVE5JN!D0s;oBG?AD}N zH){hMC?hyoDC9LA-L6r+-Bru(E5B5+g8_;ZE8_(Az!n@S#M)(}YNj_1NcdiCv)!$$ zQli>j1~q85B>h3Ns!!SY>WvtG>S8SYkFl^!0h-exgh$W@HR&!Ngf?n*Vyi$z|~>d9)pqG6e0kuRiQO=*|3>rMYG z_4t(XElA*KQ>B_LX4(dgB43pP=I}-n&KLE}Cji0^uc=wR#EGWdEtZQ??R3GS+(^-L zY17Vk{EEf_z7ypW8nG6oFYA#J&&KYPUP8a=ELj-4@S0W9`#E!n7zQGuqGM zMAfNwbhMrqgs5GaK%ZlBVTqJ1xE}~6m5~9h3!cW}ir_G9AQ;pGTJu0#f5dj*H@{M* z(#~EsSehmY1wk+1JlTVpR1{??$lCJp?5vM?8nY<%72}dI7OInlQfBN@oLdT^wN}0X zNd|Bwk%^(T-;ILna6=eZj0w@wHSeebL$InWe+&SP1utQgej41w??zkNR!dc>=j>7Tkk(u*x}hvQ>z+}2M6{! zMieQ|$S0}r7T>`eJ0K1Whw(L(Qjf#E%y^~zmy$8uMV7YOX$In7@}(Ry%c?4gSgYSJ z3Ifq&a(dP@J|mGNc`MIYeqrZp=jem+=WI0Wq#&RbRzcWTm_R>pf&nDC&oa$#Xq$z; zKMx&)H>CKZmi#x`8diXlrP-l=9oas2a|u zPDD{Q>GcSB=;057NQ(HJh5&XTEiIcbh|yHwofNV11aI0KqQRM zxC*Vundhaj?cm?x=t8U#6#==I0~l+>JoM?A`1 z-Mf2A0?|{X3k^Wbh%>=_B3Q;@NE}QEf^?sRv`vRRG4AH32$IsUL>emD=V~j-IN=OJ z%A43fA>*z^^DcG^ElwfrATYydRRb}B7B7-uQ?2Q3;KJ)#g&^m-$W!5xHVfQ@p|$|t z;=5>C2ENf9(JXx1h*%Iu$B)G&^@$cisWD)hNbBDDU&rdR&C)VW1xTf-5n0ja4Mept2w|bxO{RI=GN`SnBB#5C}EPXkt!uv9@+ z%8WeJ@+xby5R+Ipi*#PEEn`qYy>4e@%jI)_-K1~LPerpEFr(pGo8Z-S)@F7|NF}Ua zn3eBon>9{oHx_G~q&!`>vvO@GB5Q&z)Qhybo}4!nhZTJ2zve=cqTsn?|N?*2$x|3 zn1!CIMMwz|YT|t`7mN~2G1E-3nAa8)lwcw$h%$x|HLHkWOa&OA08<7`AWoqmK&uO0 z1RyBUR}TS>|2WMI+rwyeD3y}F>T4}rAjI3kIG4g97!y}I06C$LT5r1a?h)dC@6>P4 zj4^svX=BV3BEbcxv3U?ruJ3O1B;|X%Vq5fDIYKBsy==oOEHI%UjYkNHIHy>r0E}_j z(HOv=3lRr&C`2V_l<-V^2F3~J6qGtifQeoqhKJ&jn@XN@0l-=3m#7CAV+Vtjt_~8E z_B3so2&9y%fg2N>?-9g&70RCHPsKO+82)Wu0&gaM3askbVMG3>b&7eQoiwmwO@_-UpYdlav&lwxTnK1<2e;9F%#^?Z@ z^VO!(<~aK_EUW2w(uD!2eF)swFA1Yg7q4LKmQYJc$WJ1*ysBphkm;uAU7Uwurj#4K zP(CwKKq37JZCl<^vAP*qEArj+$q_&866*g zUP_<7dfFB z%_TrDzWCycUk7n~VmKNWNs?dy&%-2lTxNnm6GF8SQRKRgw3&2%yxZ?*zVBy*aHb7s zf#7u5XN+^#CD@Tt065ZBQLMF6j;oR+N!;6RAwYm`p?~_PfBL6?f-imX#TQ?E5t8`C zkkG_WQ;fm)2q7sOm$cnRi91UC9 za+!kFy4CqM!gCbt(!h>sqDgEzFK43nrJhd2?PH;ZgL}KI05JGvwI>F3W4jkX&Q8X> zPTTnra8U;^qJ1kxHfxGBJv9VpbVBIb4o+LWZWnDskEXwFS0A+hVaypNGNjljUz(+h zx?GDovCX=fw@p&>G!-aOo!Bg$s&0aKmtZNmcS9)LR0$r22SQLIKrgg@o0il-@2NXm z^|RYL5xh>3rf6&Mz_zQnTA|_|*sPYca_3tLouXLxP_wb6l}!l+uWTgF?W=aVTBb92 z5dG3+IVps$Ex;`Vf?fyK`VG+P0hsi9T)fdfqn4p`6vOZ7S?! zRnIE!h;3bwO25IZo|Sc5XSNn?HP@&Iai@s+IjrV&i*g5>1VN$r^O`kL1!kpX7OR?`GQ)Mlb${mQkuls+QOY-96nI_pDX04UBXy=JH1UNTiY>ArmD@;L|_Sp`SOa;bj(LkxS02r4bLkuT% zS6@oicZ>yvWmfjIXpcerf=gonEp;$5VQtW7uqDt)0MVmiq53OukIoFOIHVMUkyP4n zVO_ukvLF~aA`Z)X<1!$pLMwvSo`bUuNNXoyje^9sU3W&5gc2IQlmSep)w0NiO!*<_ z;UQh^Morrib;iN0(jem;(-0sdxG(~W+W;wv6O$1!+b5y$ACM6Cp*jhSlhUlL3LE*q zT%0M1E+Zis50sJ+Oc7r@7Gi;w61o<7ez1RYe>CpB?722qSyq;rz&Hu6l9f`C4_|A? z0L2J0*akEKxF`?BUe7Xh4Yh9}`-79`?!9L=1IClvx8L#G%zB!j z<%Rz8Dsj$8D?zH-4+>^)gpf`!#&r~`M~GxNC`uuMa7HpZN)pDitm8}2PdUYT=R12i z6ZYHKc(OM&fWKHix80ip?be`|0m(42E?|Q=j!F5xO(Lja8=6Z)WTn`h9Ctc6{{u-R zlUQ*kVXXVA^tSAGg?BC-pJ%XshMlo{p&EXNXd<2Tq`47WP>!Dc%g}`&q#sj%nt+2c?Bx=j3i=dLnRWBk|0=>2#IE# z!GZ*9Rf4}u#37eKNH>Lwg|Jit@{Ss09GwYYMyKR!5I<&MOoJp-R>fJ&xuBqc$OmcPaiz)HWH4yAnRSUN zvX~gd<0z;r#L-lXIM10R!5I?*WM@th#Jxo1-0GR&=v8`J45TDtGFB>3B!t#&KfP>+ zL5nln7l&pqATlbXBVQ8WwBU5LPZ}t0Ud@cbc>EA!?}P?34G~L|*%w1d0$CCgG#;;( zJIff0k2mXPMnC4r53~>hQnZg^J)B`Y3XA@HE1)M3RWIJ9gS^v@Kk&Tiu2v3J##Xy* z#qgWYj4u51zZ(71ZyCM!pN#*i`PNtCwdZdJUO4|JzkdFM_!iIeIv#uRE?vc^J>z9D zU*30b^WN)y#QR$B2fR;v|J3_k@2|c8289T1yd7VIAEAtnXhYZOd3vMgT}RdI>PFQ= z>|SkDsd`f7Mc&A(SXbN3jpbN2>&;9pW~wN6i*mQ#Y&}Q0%eXN4+)SJ+1Jhk&yW7m} zixx;iUc8E(K{oXUnbvwom=sE0#&WZJ|6se})IcdKT3(!aeO#MGZ#|$~E%)JSdv&4I zY=U~Tg4!4D>Pa86nG(yUt;(=AZG@FzcU8axQY2=pmQzG^XYa5olL9(HlMATSFf1V^ zVOq&bQRYh6Bm*fpt`a-b%1lvZvlcVbQtM6T47ep$DiDiy(t!NY^0VSq6=hXl)_0{s z+q{;ItRwQ(r3^R6?%7TeWmf`W*K<4BsWOTK%nIvOm%BiEHBQZHwSMeQ=~_dHf9X4d z`b@L_-$Lr$>8n2T+liETB@+pbnh{I@;7{`c;)&34?n2H>#!Ai)6%fN=1pU;x1UX0{ zBpw4(+<`Mr7ljcxDlQ(^jCD9yobmsW#YAyNRQ@pFm53rlk+sg*Q-j^blHU{2fy7$p zULKZ0vTPJtIBOk#O-t|$N=fqfk~EZ})7jhG7h=ED4FXD~3=fZXXY*0z91B2pI~s#J z?S9|&mPK99<=7cOB2|>#+RlGJ9TWiWol?E>{QF7kq<3_*I6KQrA-dJkAqj4=cyA2L zv$L!cqF3!zC69#QMk>h}GjeZFwHbpo?F$!z76{I?_V%Ra#kd$H-z(%>gbE2p`d3

        {{{ each tokens }}} - - + -
        [[admin/development/info:host]] [[admin/development/info:primary]][[admin/development/info:pid]] [[admin/development/info:nodejs]] [[admin/development/info:online]] [[admin/development/info:git]]{info.process.pid} {info.process.version} {info.stats.onlineRegisteredCount} / From 60fea51b36e5dbd49af6c36751d976f7c5674c77 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 10 Jul 2023 09:18:31 +0000 Subject: [PATCH 028/300] Latest translations and fallbacks --- public/language/he/admin/admin.json | 2 +- public/language/he/admin/dashboard.json | 6 +++--- public/language/he/admin/manage/admins-mods.json | 2 +- public/language/he/admin/settings/advanced.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/he/admin/admin.json b/public/language/he/admin/admin.json index 7fe66d9af6..7e52ea0d9e 100644 --- a/public/language/he/admin/admin.json +++ b/public/language/he/admin/admin.json @@ -13,5 +13,5 @@ "max": "מקסימום:", "view": "צפייה", "edit": "עריכה", - "add": "Add" + "add": "הוספה" } \ No newline at end of file diff --git a/public/language/he/admin/dashboard.json b/public/language/he/admin/dashboard.json index 5b1860d8a4..b5424de62a 100644 --- a/public/language/he/admin/dashboard.json +++ b/public/language/he/admin/dashboard.json @@ -27,7 +27,7 @@ "running-version": "הפורום מעודכן לגרסה %1", "keep-updated": "לעדכוני אבטחה מעודכנים ותיקוני באגים, וודא שהפורום שלך עדכני לגרסה האחרונה.", "up-to-date": "אתה מעודכן ", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", + "upgrade-available": "גרסה חדשה (v%1) שוחררה. שקול לעדכן את הפורום שלך.", "prerelease-upgrade-available": "זוהי גרסת טרום-הפצה מיושנת של NodeBB. גרסה חדשה (v%1) שוחררה. שקול לשדרג את ה-NodeBB שלך.", "prerelease-warning": " זוהי גרסת טרום-הפצה של NodeBB. עלולים להתרחש באגים לא מכוונים.", "fallback-emailer-not-found": "Fallback emailer לא נמצא!", @@ -35,8 +35,8 @@ "latest-lookup-failed": "לא הצליח לחפש את הגרסה האחרונה הזמינה של NodeBB", "notices": "התראות", - "restart-not-required": "לא נדרש אתחול מחדש", - "restart-required": "נדרש אתחול מחדש", + "restart-not-required": "לא נדרשת הפעלה מחדש", + "restart-required": "נדרשת הפעלה מחדש", "search-plugin-installed": "תוסף חיפוש הותקן", "search-plugin-not-installed": "תוסף חיפוש לא הותקן", "search-plugin-tooltip": "התקן את תוסף החיפוש מעמוד התוספים על מנת להפעיל את אפשרות החיפוש", diff --git a/public/language/he/admin/manage/admins-mods.json b/public/language/he/admin/manage/admins-mods.json index 5fb5065795..7d86808d25 100644 --- a/public/language/he/admin/manage/admins-mods.json +++ b/public/language/he/admin/manage/admins-mods.json @@ -5,7 +5,7 @@ "moderators": "מנחים", "no-global-moderators": "אין מנחים גלובליים", "no-sub-categories": "אין תתי קטגוריות", - "view-children": "View children (%1)", + "view-children": "הצג ילדים (%1)", "no-moderators": "אין מנחים", "add-administrator": "הוסף מנהל", "add-global-moderator": "הוסף מנחה גלובלי", diff --git a/public/language/he/admin/settings/advanced.json b/public/language/he/admin/settings/advanced.json index b271d22ecd..bf7d161cbb 100644 --- a/public/language/he/admin/settings/advanced.json +++ b/public/language/he/admin/settings/advanced.json @@ -32,7 +32,7 @@ "traffic.help": "NodeBB משתמש במודול שדוחה אוטומטית בקשות במצבים עם תעבורה גבוהה. אתה יכול לכוונן את ההגדרות האלה כאן, למרות שברירות המחדל הן נקודת התחלה טובה.", "traffic.enable": "הפעל ניהול תעבורה", "traffic.event-lag": "סף השהיית לולאת אירוע (במילישניות)", - "traffic.event-lag-help": "הורדת ערך זה מקטינה את זמני ההמתנה לטעינת הדפים, אך גם תציג את ההודעה \"עומס מופרז\" ליותר משתמשים. (אתחול נדרש)", + "traffic.event-lag-help": "הורדת ערך זה מקטינה את זמני ההמתנה לטעינת הדפים, אך גם תציג את ההודעה \"עומס מופרז\" ליותר משתמשים. (הפעלה מחדש נדרשת)", "traffic.lag-check-interval": "מרווח זמן בין בדיקות (במילישניות)", "traffic.lag-check-interval-help": "הורדת ערך זה גורמת ל-NodeBB להיות רגיש יותר לקוצים בעומס, אך עלולה גם לגרום לסימון להיות רגיש מדי. (הפעלה מחדש נדרשת)", From 7c588fe9a3e9e34a1c40bf458b05af51cab112a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 10 Jul 2023 16:13:26 -0400 Subject: [PATCH 029/300] test no escape on canonical --- src/controllers/topics.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 7e6ff393a2..fd3a3b9966 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -261,6 +261,7 @@ async function addTags(topicData, req, res, currentPage) { { rel: 'canonical', href: `${url}/topic/${topicData.slug}${page}`, + noEscape: true, }, ]; From ed99ea20cbaecbee56145a934f80e24e548ad0dc Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 30 Jun 2023 11:07:51 -0400 Subject: [PATCH 030/300] feat: allow FormData object to be passed in to the API module Currently, only objects can be passed in, and it is automatically serialized into json and sent via jQuery .ajax(). This PR extends the module so a FormData object can be passed in, and updates the module so it uses Fetch API instead of jQuery. At this time regular requests continue to use jQuery for backwards compatibility. Use case: file uploads via API. --- public/src/modules/api.js | 80 +++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/public/src/modules/api.js b/public/src/modules/api.js index ed0c7c2d2b..4266b70e18 100644 --- a/public/src/modules/api.js +++ b/public/src/modules/api.js @@ -37,27 +37,60 @@ function call(options, callback) { } async function xhr(options, cb) { - // Allow options to be modified by plugins, etc. - ({ options } = await fireHook('filter:api.options', { options })); + /** + * N.B. fetch api is only used when payload is a FormData object! + * + * This is because the passed-in options are different between fetch/jQuery .ajax() + * If we updated the code to use only fetch, it would be a breaking change. + * + * Prior to v3.3 there was no support for sending in FormData, so the addition of fetch + * handling is not breaking. + * + * Break this for v4 by making everything use fetch api. + */ - $.ajax(options) - .done((res) => { - cb(null, ( - res && - res.hasOwnProperty('status') && - res.hasOwnProperty('response') ? res.response : (res || {}) - )); - }) - .fail((ev) => { - let errMessage; - if (ev.responseJSON) { - errMessage = ev.responseJSON.status && ev.responseJSON.status.message ? - ev.responseJSON.status.message : - ev.responseJSON.error; - } + // Adjust options based on payload type + if (options.payload instanceof FormData) { + const url = options.url; + options.body = options.payload; + delete options.payload; + delete options.url; - cb(new Error(errMessage || ev.statusText)); - }); + // Allow options to be modified by plugins, etc. + ({ options } = await fireHook('filter:api.fetchOptions', { options })); + + await fetch(url, { + ...options, + }).then((res) => { + cb(null, res); + }).catch(cb); + } else { + options.data = JSON.stringify(options.payload || {}); + options.contentType = 'application/json; charset=utf-8'; + delete options.payload; + + // Allow options to be modified by plugins, etc. + ({ options } = await fireHook('filter:api.options', { options })); + + $.ajax(options) + .done((res) => { + cb(null, ( + res && + res.hasOwnProperty('status') && + res.hasOwnProperty('response') ? res.response : (res || {}) + )); + }) + .fail((ev) => { + let errMessage; + if (ev.responseJSON) { + errMessage = ev.responseJSON.status && ev.responseJSON.status.message ? + ev.responseJSON.status.message : + ev.responseJSON.error; + } + + cb(new Error(errMessage || ev.statusText)); + }); + } } export function get(route, payload, onSuccess) { @@ -77,8 +110,7 @@ export function post(route, payload, onSuccess) { return call({ url: route, method: 'post', - data: JSON.stringify(payload || {}), - contentType: 'application/json; charset=utf-8', + payload, headers: { 'x-csrf-token': config.csrf_token, }, @@ -89,8 +121,7 @@ export function patch(route, payload, onSuccess) { return call({ url: route, method: 'patch', - data: JSON.stringify(payload || {}), - contentType: 'application/json; charset=utf-8', + payload, headers: { 'x-csrf-token': config.csrf_token, }, @@ -101,8 +132,7 @@ export function put(route, payload, onSuccess) { return call({ url: route, method: 'put', - data: JSON.stringify(payload || {}), - contentType: 'application/json; charset=utf-8', + payload, headers: { 'x-csrf-token': config.csrf_token, }, From 8a53182657fef6536476b0134a38d66dd3a921c4 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 30 Jun 2023 11:50:37 -0400 Subject: [PATCH 031/300] fix: fetch handler not passing back errors or success payloads --- public/src/modules/api.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/public/src/modules/api.js b/public/src/modules/api.js index 4266b70e18..ca619ec16e 100644 --- a/public/src/modules/api.js +++ b/public/src/modules/api.js @@ -61,8 +61,17 @@ async function xhr(options, cb) { await fetch(url, { ...options, - }).then((res) => { - cb(null, res); + }).then(async (res) => { + const payload = await res.json(); + if (Math.floor(res.status / 100) === 2) { + cb(null, ( + payload && + payload.hasOwnProperty('status') && + payload.hasOwnProperty('response') ? payload.response : (payload || {}) + )); + } else { + cb(new Error(payload.status.message)); + } }).catch(cb); } else { options.data = JSON.stringify(options.payload || {}); From 7415b16d2a7e094a60448d9c629010dda10f7f5a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 10 Jul 2023 16:32:16 -0400 Subject: [PATCH 032/300] refactor: use fetch() throughout, instead of jQuery .ajax() --- public/src/modules/api.js | 124 +++++++++++++++----------------------- 1 file changed, 50 insertions(+), 74 deletions(-) diff --git a/public/src/modules/api.js b/public/src/modules/api.js index ca619ec16e..8c9485e557 100644 --- a/public/src/modules/api.js +++ b/public/src/modules/api.js @@ -37,123 +37,99 @@ function call(options, callback) { } async function xhr(options, cb) { - /** - * N.B. fetch api is only used when payload is a FormData object! - * - * This is because the passed-in options are different between fetch/jQuery .ajax() - * If we updated the code to use only fetch, it would be a breaking change. - * - * Prior to v3.3 there was no support for sending in FormData, so the addition of fetch - * handling is not breaking. - * - * Break this for v4 by making everything use fetch api. - */ + // Normalize body based on type + const { url } = options; + delete options.url; - // Adjust options based on payload type - if (options.payload instanceof FormData) { - const url = options.url; - options.body = options.payload; - delete options.payload; - delete options.url; - - // Allow options to be modified by plugins, etc. - ({ options } = await fireHook('filter:api.fetchOptions', { options })); - - await fetch(url, { - ...options, - }).then(async (res) => { - const payload = await res.json(); - if (Math.floor(res.status / 100) === 2) { - cb(null, ( - payload && - payload.hasOwnProperty('status') && - payload.hasOwnProperty('response') ? payload.response : (payload || {}) - )); - } else { - cb(new Error(payload.status.message)); - } - }).catch(cb); - } else { - options.data = JSON.stringify(options.payload || {}); - options.contentType = 'application/json; charset=utf-8'; - delete options.payload; - - // Allow options to be modified by plugins, etc. - ({ options } = await fireHook('filter:api.options', { options })); - - $.ajax(options) - .done((res) => { - cb(null, ( - res && - res.hasOwnProperty('status') && - res.hasOwnProperty('response') ? res.response : (res || {}) - )); - }) - .fail((ev) => { - let errMessage; - if (ev.responseJSON) { - errMessage = ev.responseJSON.status && ev.responseJSON.status.message ? - ev.responseJSON.status.message : - ev.responseJSON.error; - } - - cb(new Error(errMessage || ev.statusText)); - }); + if (options.data && !(options.data instanceof FormData)) { + options.data = JSON.stringify(options.data || {}); + options.headers['content-type'] = 'application/json; charset=utf-8'; } + + // Allow options to be modified by plugins, etc. + ({ options } = await fireHook('filter:api.options', { options })); + + /** + * Note: pre-v4 backwards compatibility + * + * This module now passes in "data" to xhr(). + * This is because the "filter:api.options" hook (and plugins using it) expect "data". + * fetch() expects body, so we rename it here. + * + * In v4, replace all instances of "data" with "body" and record as breaking change. + */ + if (options.data) { + options.body = options.data; + delete options.data; + } + + await fetch(url, { + ...options, + }).then(async (res) => { + const response = await res.json(); + if (Math.floor(res.status / 100) === 2) { + cb(null, ( + response && + response.hasOwnProperty('status') && + response.hasOwnProperty('response') ? response.response : (response || {}) + )); + } else { + cb(new Error(response.status.message)); + } + }).catch(cb); } -export function get(route, payload, onSuccess) { +export function get(route, data, onSuccess) { return call({ - url: route + (payload && Object.keys(payload).length ? ('?' + $.param(payload)) : ''), + url: route + (data && Object.keys(data).length ? ('?' + $.param(data)) : ''), }, onSuccess); } -export function head(route, payload, onSuccess) { +export function head(route, data, onSuccess) { return call({ - url: route + (payload && Object.keys(payload).length ? ('?' + $.param(payload)) : ''), + url: route + (data && Object.keys(data).length ? ('?' + $.param(data)) : ''), method: 'head', }, onSuccess); } -export function post(route, payload, onSuccess) { +export function post(route, data, onSuccess) { return call({ url: route, method: 'post', - payload, + data, headers: { 'x-csrf-token': config.csrf_token, }, }, onSuccess); } -export function patch(route, payload, onSuccess) { +export function patch(route, data, onSuccess) { return call({ url: route, method: 'patch', - payload, + data, headers: { 'x-csrf-token': config.csrf_token, }, }, onSuccess); } -export function put(route, payload, onSuccess) { +export function put(route, data, onSuccess) { return call({ url: route, method: 'put', - payload, + data, headers: { 'x-csrf-token': config.csrf_token, }, }, onSuccess); } -export function del(route, payload, onSuccess) { +export function del(route, data, onSuccess) { return call({ url: route, method: 'delete', - data: JSON.stringify(payload), - contentType: 'application/json; charset=utf-8', + data, headers: { 'x-csrf-token': config.csrf_token, }, From bf2c429a1825c1fa08d84f3db995536e3313d727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 10 Jul 2023 18:07:04 -0400 Subject: [PATCH 033/300] fix: #11787 --- public/scss/admin/modules/nprogress.scss | 51 +++++++++--------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/public/scss/admin/modules/nprogress.scss b/public/scss/admin/modules/nprogress.scss index 4584a127d7..99807bf906 100644 --- a/public/scss/admin/modules/nprogress.scss +++ b/public/scss/admin/modules/nprogress.scss @@ -1,8 +1,8 @@ #nprogress { pointer-events: none; - } +} - #nprogress .bar { +#nprogress .bar { background: #29d; position: fixed; @@ -12,9 +12,9 @@ width: 100%; height: 2px; - } +} - #nprogress .peg { +#nprogress .peg { display: block; position: absolute; right: 0px; @@ -26,26 +26,13 @@ -webkit-transform: rotate(3deg) translate(0px, -4px); -ms-transform: rotate(3deg) translate(0px, -4px); transform: rotate(3deg) translate(0px, -4px); - } +} - #nprogress .spinner { - display: block; - position: fixed; - z-index: 1031; - top: 165px; - right: 35px; - } +#nprogress .spinner { + display: none; +} - @include media-breakpoint-down(sm) { - #nprogress .spinner { - bottom: 15px; - right: 15px; - top: initial; - } - } - - - #nprogress .spinner-icon { +#nprogress .spinner-icon { width: 18px; height: 18px; box-sizing: border-box; @@ -57,24 +44,24 @@ -webkit-animation: nprogress-spinner 400ms linear infinite; animation: nprogress-spinner 400ms linear infinite; - } +} - .nprogress-custom-parent { +.nprogress-custom-parent { overflow: hidden; position: relative; - } +} - .nprogress-custom-parent #nprogress .spinner, - .nprogress-custom-parent #nprogress .bar { +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { position: absolute; - } +} - @-webkit-keyframes nprogress-spinner { +@-webkit-keyframes nprogress-spinner { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } - } - @keyframes nprogress-spinner { +} +@keyframes nprogress-spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } - } +} From e72fab54179e935d109178722e7814b7ed232d7f Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 11 Jul 2023 09:18:33 +0000 Subject: [PATCH 034/300] Latest translations and fallbacks --- public/language/ar/topic.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/ar/topic.json b/public/language/ar/topic.json index 7ec59eaff4..22e96b3fcf 100644 --- a/public/language/ar/topic.json +++ b/public/language/ar/topic.json @@ -1,6 +1,6 @@ { "topic": "موضوع", - "title": "Title", + "title": "العنوان", "no_topics_found": "لا توجد مواضيع !", "no_posts_found": "لا توجد مشاركات!", "post_is_deleted": "هذه المشاركة محذوفة!", @@ -12,12 +12,12 @@ "notify_me": "تلق تنبيهات بالردود الجديدة في هذا الموضوع", "quote": "اقتبس", "reply": "رد", - "replies_to_this_post": "%1 Replies", - "one_reply_to_this_post": "1 Reply", - "last_reply_time": "Last reply", + "replies_to_this_post": "%1 الردود", + "one_reply_to_this_post": "1 رد", + "last_reply_time": "آخر رد", "reply-as-topic": "رد بموضوع", "guest-login-reply": "يجب عليك تسجيل الدخول للرد", - "login-to-view": "🔒 Log in to view", + "login-to-view": "سجل الدخول للمشاهدة", "edit": "تعديل", "delete": "حذف", "delete-event": "Delete Event", @@ -32,7 +32,7 @@ "tools": "أدوات", "locked": "مقفل", "pinned": "مثبت", - "pinned-with-expiry": "Pinned until %1", + "pinned-with-expiry": "مثبت حتى %1", "scheduled": "Scheduled", "moved": "منقول", "moved-from": "Moved from %1", From 2d016af82f751cb74314ea72ac8e247dfee11b6c Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 11 Jul 2023 11:03:00 -0400 Subject: [PATCH 035/300] feat: simplified api module handler logic, content-type detection/parsing --- public/src/modules/api.js | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/public/src/modules/api.js b/public/src/modules/api.js index 8c9485e557..0993a8de66 100644 --- a/public/src/modules/api.js +++ b/public/src/modules/api.js @@ -63,20 +63,26 @@ async function xhr(options, cb) { delete options.data; } - await fetch(url, { - ...options, - }).then(async (res) => { - const response = await res.json(); - if (Math.floor(res.status / 100) === 2) { - cb(null, ( - response && - response.hasOwnProperty('status') && - response.hasOwnProperty('response') ? response.response : (response || {}) - )); - } else { - cb(new Error(response.status.message)); - } - }).catch(cb); + const res = await fetch(url, options); + const { headers } = res; + const isJSON = headers.get('content-type').startsWith('application/json'); + + let response; + if (isJSON) { + response = await res.json(); + } else { + response = await res.text(); + } + + if (!res.ok) { + return cb(new Error(isJSON ? response.status.message : response)); + } + + cb(null, ( + isJSON && response.hasOwnProperty('status') && response.hasOwnProperty('response') ? + response.response : + response + )); } export function get(route, data, onSuccess) { From 9b901783fac72aba36fed097ee408e3a32f53313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 13:03:54 -0400 Subject: [PATCH 036/300] Chat refactor (#11779) * first part of chat refactor remove per user chat zsets & store all mids in chat:room::mids reverse uids in getUidsInRoom * feat: create room button public groups wip * feat: public rooms create chats:room zset chat room deletion * join socket.io room * get rid of some calls that load all users in room * dont load all users when loadRoom is called * mange room users infinitescroll dont load all members in api call * IS for user list ability to change groups field for public rooms update groups field if group is renamed * test: test fixes * wip * keep 150 messages * fix extra awaits fix dupe code in chat toggleReadState * unread state for public rooms * feat: faster push unread * test: spec * change base to harmony * test: lint fixes * fix language of chat with message * add 2 methods for perf messaging.getTeasers and getUsers(roomIds) instead of loading one by one * refactor: cleaner conditional * test fix upgrade script fix save timestamp of room creation in room object * set progress.total * don't check for guests/spiders * public room unread fix * add public unread counts * mark read on send * ignore instead of throwing * doggy.gif * fix: restore delete * prevent entering chat rooms with meta.enter * fix self message causing mark unread * ability to sort public rooms * dont init sortable on mobile * move chat-loaded class to core * test: fix spec * add missing keys * use ajaxify * refactor: store some refs * fix: when user is deleted remove from public rooms as well * feat: change how unread count is calculated * get rid of cleaned content get rid of mid * add help text * test: fix tests, add back mid to prevent breaking change * ability to search members of chat rooms * remove * derp * perf: switch with partial data fix tests * more fixes if user leaves a group leave public rooms is he is no longer part of any of the groups that have access fix the cache key used to get all public room ids dont allow joining chat socket.io room if user is no longer part of group * fix: lint * fix: js error when trying to delete room after switching * add isRoomPublic --- Gruntfile.js | 4 +- public/language/en-GB/error.json | 1 + public/language/en-GB/modules.json | 16 +- public/openapi/components/schemas/Chats.yaml | 16 +- .../read/user/userslug/chats/roomid.yaml | 173 ++++++++- public/openapi/write.yaml | 2 + public/openapi/write/admin/chats/roomId.yaml | 26 ++ public/openapi/write/chats/roomId.yaml | 2 - public/src/client/chats.js | 349 +++++++++--------- public/src/client/chats/create.js | 85 +++++ public/src/client/chats/manage.js | 106 ++++++ public/src/client/chats/messages.js | 33 +- public/src/client/chats/recent.js | 22 +- public/src/client/chats/search.js | 48 ++- public/src/client/chats/user-list.js | 48 +++ public/src/client/header/chat.js | 26 +- public/src/modules/autocomplete.js | 18 +- public/src/modules/chat.js | 125 ++++--- public/src/sockets.js | 12 +- src/api/chats.js | 85 ++++- src/controllers/accounts/chats.js | 45 ++- src/controllers/accounts/profile.js | 10 +- src/controllers/write/admin.js | 15 + src/controllers/write/chats.js | 11 +- src/database/mongo/sorted.js | 4 +- src/events.js | 1 + src/groups/leave.js | 22 +- src/groups/membership.js | 2 +- src/groups/update.js | 15 + src/messaging/create.js | 54 +-- src/messaging/data.js | 4 +- src/messaging/delete.js | 21 +- src/messaging/edit.js | 12 +- src/messaging/index.js | 188 +++++++--- src/messaging/notifications.js | 65 ++-- src/messaging/rooms.js | 239 +++++++++--- src/messaging/unread.js | 24 +- src/middleware/assert.js | 4 +- src/middleware/render.js | 2 + src/routes/write/admin.js | 2 + src/routes/write/chats.js | 3 +- src/socket.io/admin/rooms.js | 1 - src/socket.io/groups.js | 11 + src/socket.io/meta.js | 25 +- src/socket.io/modules.js | 111 +++++- src/upgrades/3.3.0/chat_room_refactor.js | 64 ++++ src/upgrades/3.3.0/save_rooms_zset.js | 42 +++ src/user/delete.js | 15 +- src/user/jobs/export-profile.js | 2 +- src/views/modals/create-room.tpl | 45 +++ src/views/modals/manage-room.tpl | 20 +- .../partials/chats/manage-room-users.tpl | 13 +- test/api.js | 2 +- test/database/sorted.js | 5 +- test/messaging.js | 18 +- test/user.js | 2 +- 56 files changed, 1749 insertions(+), 567 deletions(-) create mode 100644 public/openapi/write/admin/chats/roomId.yaml create mode 100644 public/src/client/chats/create.js create mode 100644 public/src/client/chats/manage.js create mode 100644 public/src/client/chats/user-list.js create mode 100644 src/upgrades/3.3.0/chat_room_refactor.js create mode 100644 src/upgrades/3.3.0/save_rooms_zset.js create mode 100644 src/views/modals/create-room.tpl diff --git a/Gruntfile.js b/Gruntfile.js index 6c02efa808..dcfa831cd6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -49,8 +49,8 @@ module.exports = function (grunt) { if (!pluginList.includes('nodebb-plugin-composer-default')) { pluginList.push('nodebb-plugin-composer-default'); } - if (!pluginList.includes('nodebb-theme-persona')) { - pluginList.push('nodebb-theme-persona'); + if (!pluginList.includes('nodebb-theme-harmony')) { + pluginList.push('nodebb-theme-harmony'); } } diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index a76f180081..4aa4915bc1 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -230,6 +230,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index 4a752ea387..07f0f4515d 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 91c41f777b..7f8f1b8b85 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -9,9 +9,19 @@ RoomObject: description: unique identifier for the chat room roomName: type: string + description: the name of the room, if set this is displayed instead of the usernames groupChat: type: boolean - description: whether the chat room is a group chat or not + description: whether the chat room is a group chat or not (if more than 2 users it is a group chat) + public: + type: boolean + description: whether the chat room is public or private + userCount: + type: number + description: number of users in this chat room + timestamp: + type: number + description: Timestamp of when room was created MessageObject: type: object properties: @@ -92,8 +102,6 @@ MessageObject: type: number newSet: type: boolean - cleanedContent: - type: string RoomUserList: type: object properties: @@ -132,6 +140,8 @@ RoomUserList: type: boolean canKick: type: boolean + index: + type: number RoomObjectFull: # Messaging.loadRoom allOf: diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index 767ea88d0c..4f8b26e6a4 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -30,6 +30,13 @@ get: type: number roomName: type: string + public: + type: boolean + userCount: + type: number + timestamp: + type: number + description: Timestamp of when room was created messages: type: array items: @@ -101,8 +108,6 @@ get: type: boolean index: type: number - cleanedContent: - type: string isOwner: type: boolean isOwner: @@ -139,6 +144,8 @@ get: example: "#f44336" isOwner: type: boolean + index: + type: number canReply: type: boolean groupChat: @@ -153,6 +160,8 @@ get: type: boolean isAdminOrGlobalMod: type: boolean + isAdmin: + type: boolean rooms: type: array items: @@ -166,6 +175,13 @@ get: type: number roomName: type: string + public: + type: boolean + userCount: + type: number + timestamp: + type: number + description: Timestamp of when room was created users: type: array items: @@ -300,6 +316,157 @@ get: type: string chatWithMessage: type: string + publicRooms: + type: array + items: + type: object + properties: + owner: + oneOf: + - type: number + - type: string + roomId: + type: number + roomName: + type: string + public: + type: boolean + users: + type: array + items: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + status: + type: string + lastonline: + type: number + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + lastonlineISO: + type: string + groupChat: + type: boolean + unread: + type: boolean + teaser: + type: object + properties: + fromuid: + type: number + content: + type: string + timestamp: + type: number + timestampISO: + type: string + description: An ISO 8601 formatted date string (complementing `timestamp`) + user: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + status: + type: string + lastonline: + type: number + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users + without an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's + auto-generated icon + example: "#f44336" + lastonlineISO: + type: string + nullable: true + lastUser: + type: object + properties: + uid: + type: number + description: A user identifier + username: + type: string + description: A friendly name for a given user account + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces + removed, etc.) + picture: + nullable: true + type: string + status: + type: string + lastonline: + type: number + icon:text: + type: string + description: A single-letter representation of a username. This is used in the + auto-generated icon given to users without + an avatar + icon:bgColor: + type: string + description: A six-character hexadecimal colour code assigned to the user. This + value is used in conjunction with + `icon:text` for the user's auto-generated + icon + example: "#f44336" + lastonlineISO: + type: string + usernames: + type: string + chatWithMessage: + type: string + privateRoomCount: + type: number nextStart: type: number title: @@ -315,4 +482,6 @@ get: type: boolean chatWithMessage: type: string + bodyClasses: + type: array - $ref: ../../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/openapi/write.yaml b/public/openapi/write.yaml index 101da200d1..e12e1ce2db 100644 --- a/public/openapi/write.yaml +++ b/public/openapi/write.yaml @@ -198,6 +198,8 @@ paths: $ref: 'write/admin/analytics.yaml' /admin/analytics/{set}: $ref: 'write/admin/analytics/set.yaml' + /admin/chats/{roomId}: + $ref: 'write/admin/chats/roomId.yaml' /admin/tokens: $ref: 'write/admin/tokens.yaml' /admin/tokens/{token}: diff --git a/public/openapi/write/admin/chats/roomId.yaml b/public/openapi/write/admin/chats/roomId.yaml new file mode 100644 index 0000000000..a7d2317cd2 --- /dev/null +++ b/public/openapi/write/admin/chats/roomId.yaml @@ -0,0 +1,26 @@ +delete: + tags: + - admin + summary: delete chat room + description: This operation deletes a chat room from the database + parameters: + - in: path + name: roomId + schema: + type: number + description: The roomId to be deleted + example: 1 + required: true + responses: + '200': + description: Chat room deleted + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../../../components/schemas/Status.yaml#/Status + response: + type: object + properties: {} \ No newline at end of file diff --git a/public/openapi/write/chats/roomId.yaml b/public/openapi/write/chats/roomId.yaml index 3473c92e1b..62ae9df2bd 100644 --- a/public/openapi/write/chats/roomId.yaml +++ b/public/openapi/write/chats/roomId.yaml @@ -86,8 +86,6 @@ post: newSet: type: boolean description: Whether the message is considered part of a new "set" of messages. It is used in the frontend UI for explicitly denoting that a time gap existed between messages. - cleanedContent: - type: string mid: type: number put: diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 39cf3519c5..c19773ecbb 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -3,11 +3,12 @@ define('forum/chats', [ 'components', - 'translator', 'mousetrap', 'forum/chats/recent', - 'forum/chats/search', + 'forum/chats/create', + 'forum/chats/manage', 'forum/chats/messages', + 'forum/chats/user-list', 'composer/autocomplete', 'hooks', 'bootbox', @@ -16,10 +17,10 @@ define('forum/chats', [ 'api', 'uploadHelpers', ], function ( - components, translator, mousetrap, - recentChats, search, messages, - autocomplete, hooks, bootbox, alerts, chatModule, - api, uploadHelpers + components, mousetrap, + recentChats, create, manage, messages, + userList, autocomplete, hooks, bootbox, + alerts, chatModule, api, uploadHelpers ) { const Chats = { initialised: false, @@ -27,13 +28,19 @@ define('forum/chats', [ }; let newMessage = false; + let chatNavWrapper = null; $(window).on('action:ajaxify.start', function () { Chats.destroyAutoComplete(ajaxify.data.roomId); + socket.emit('modules.chats.leave', ajaxify.data.roomId); + socket.emit('modules.chats.leavePublic', ajaxify.data.publicRooms.map(r => r.roomId)); }); Chats.init = function () { + $('.chats-full [data-bs-toggle="tooltip"]').tooltip(); + socket.emit('modules.chats.enterPublic', ajaxify.data.publicRooms.map(r => r.roomId)); const env = utils.findBootstrapEnvironment(); + chatNavWrapper = $('[component="chat/nav-wrapper"]'); if (!Chats.initialised) { Chats.addSocketListeners(); @@ -49,29 +56,31 @@ define('forum/chats', [ Chats.addHotkeys(); } - $(document).ready(function () { - hooks.fire('action:chat.loaded', $('.chats-full')); - }); - Chats.initialised = true; messages.scrollToBottom($('.expanded-chat ul.chat-content')); messages.wrapImagesInLinks($('.expanded-chat ul.chat-content')); - search.init(); + create.init(); + + hooks.fire('action:chat.loaded', $('.chats-full')); }; Chats.addEventListeners = function () { - Chats.addSendHandlers(ajaxify.data.roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]')); + const { roomId } = ajaxify.data; + const mainWrapper = $('[component="chat/main-wrapper"]'); + const chatControls = components.get('chat/controls'); + Chats.addSendHandlers(roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]')); Chats.addPopoutHandler(); - Chats.addActionHandlers(components.get('chat/messages'), ajaxify.data.roomId); - Chats.addMemberHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="members"]')); - Chats.addRenameHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="rename"]')); - Chats.addLeaveHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="leave"]')); - Chats.addScrollHandler(ajaxify.data.roomId, ajaxify.data.uid, $('.chat-content')); + Chats.addActionHandlers(components.get('chat/messages'), roomId); + Chats.addManageHandler(roomId, chatControls.find('[data-action="members"]')); + Chats.addRenameHandler(roomId, chatControls.find('[data-action="rename"]')); + Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]')); + Chats.addDeleteHandler(roomId, chatControls.find('[data-action="delete"]')); + Chats.addScrollHandler(roomId, ajaxify.data.uid, $('.chat-content')); Chats.addScrollBottomHandler($('.chat-content')); - Chats.addCharactersLeftHandler($('[component="chat/main-wrapper"]')); - Chats.addTextareaResizeHandler($('[component="chat/main-wrapper"]')); - Chats.addIPHandler($('[component="chat/main-wrapper"]')); - Chats.createAutoComplete(ajaxify.data.roomId, $('[component="chat/input"]')); + Chats.addCharactersLeftHandler(mainWrapper); + Chats.addTextareaResizeHandler(mainWrapper); + Chats.addIPHandler(mainWrapper); + Chats.createAutoComplete(roomId, $('[component="chat/input"]')); Chats.addUploadHandler({ dragDropAreaEl: $('.chats-full'), pasteEl: $('[component="chat/input"]'), @@ -83,6 +92,28 @@ define('forum/chats', [ $('[data-action="close"]').on('click', function () { Chats.switchChat(); }); + userList.init(roomId, mainWrapper); + Chats.addPublicRoomSortHandler(); + }; + + Chats.addPublicRoomSortHandler = function () { + if (app.user.isAdmin && !utils.isMobile()) { + app.loadJQueryUI(() => { + const publicRoomList = $('[component="chat/public"]'); + publicRoomList.sortable({ + handle: '[component="chat/public/room/sort/handle"]', + axis: 'y', + update: async function () { + const data = { roomIds: [], scores: [] }; + publicRoomList.find('[data-roomid]').each((idx, el) => { + data.roomIds.push($(el).attr('data-roomid')); + data.scores.push(idx); + }); + await socket.emit('modules.chats.sortPublicRooms', data); + }, + }); + }); + } }; Chats.addUploadHandler = function (options) { @@ -141,7 +172,7 @@ define('forum/chats', [ Chats.addScrollHandler = function (roomId, uid, el) { let loading = false; - el.off('scroll').on('scroll', function () { + el.off('scroll').on('scroll', utils.debounce(function () { messages.toggleScrollUpAlert(el); if (loading) { return; @@ -176,7 +207,7 @@ define('forum/chats', [ loading = false; }); }).catch(alerts.error); - }); + }, 100)); }; Chats.addScrollBottomHandler = function (chatContent) { @@ -208,7 +239,7 @@ define('forum/chats', [ }; Chats.addActionHandlers = function (element, roomId) { - element.on('click', '[data-action]', function () { + element.on('click', '[data-mid] [data-action]', function () { const messageId = $(this).parents('[data-mid]').attr('data-mid'); const action = this.getAttribute('data-action'); @@ -231,18 +262,16 @@ define('forum/chats', [ Chats.addHotkeys = function () { mousetrap.bind('ctrl+up', function () { - const activeContact = $('.chats-list .bg-info'); - const prev = activeContact.prev(); - - if (prev.length) { + const activeContact = $('.chats-list .active'); + const prev = activeContact.prevAll('[data-roomid]').first(); + if (prev.length && prev.attr('data-roomid')) { Chats.switchChat(prev.attr('data-roomid')); } }); mousetrap.bind('ctrl+down', function () { - const activeContact = $('.chats-list .bg-info'); - const next = activeContact.next(); - - if (next.length) { + const activeContact = $('.chats-list .active'); + const next = activeContact.nextAll('[data-roomid]').first(); + if (next.length && next.attr('data-roomid')) { Chats.switchChat(next.attr('data-roomid')); } }); @@ -260,50 +289,8 @@ define('forum/chats', [ }); }; - Chats.addMemberHandler = function (roomId, buttonEl) { - let modal; - - buttonEl.on('click', function () { - app.parseAndTranslate('modals/manage-room', {}, function (html) { - modal = bootbox.dialog({ - title: '[[modules:chat.manage-room]]', - message: html, - }); - - modal.attr('component', 'chat/manage-modal'); - - Chats.refreshParticipantsList(roomId, modal); - Chats.addKickHandler(roomId, modal); - - const searchInput = modal.find('input'); - const errorEl = modal.find('.text-danger'); - require(['autocomplete', 'translator'], function (autocomplete, translator) { - autocomplete.user(searchInput, function (event, selected) { - errorEl.text(''); - api.post(`/chats/${roomId}/users`, { - uids: [selected.item.user.uid], - }).then((body) => { - Chats.refreshParticipantsList(roomId, modal, body); - searchInput.val(''); - }).catch((err) => { - translator.translate(err.message, function (translated) { - errorEl.text(translated); - }); - }); - }); - }); - }); - }); - }; - - Chats.addKickHandler = function (roomId, modal) { - modal.on('click', '[data-action="kick"]', function () { - const uid = parseInt(this.getAttribute('data-uid'), 10); - - api.del(`/chats/${roomId}/users/${uid}`, {}).then((body) => { - Chats.refreshParticipantsList(roomId, modal, body); - }).catch(alerts.error); - }); + Chats.addManageHandler = function (roomId, buttonEl) { + manage.init(roomId, buttonEl); }; Chats.addLeaveHandler = function (roomId, buttonEl) { @@ -330,21 +317,27 @@ define('forum/chats', [ }); }; - Chats.refreshParticipantsList = async (roomId, modal, data) => { - const listEl = modal.find('.list-group'); - - if (!data) { - try { - data = await api.get(`/chats/${roomId}/users`, {}); - } catch (err) { - translator.translate('[[error:invalid-data]]', function (translated) { - listEl.find('li').text(translated); - }); - } - } - - app.parseAndTranslate('partials/chats/manage-room-users', data, function (html) { - listEl.html(html); + Chats.addDeleteHandler = function (roomId, buttonEl) { + buttonEl.on('click', function () { + bootbox.confirm({ + size: 'small', + title: '[[modules:chat.delete]]', + message: '

        [[modules:chat.delete-prompt]]

        ', + callback: function (ok) { + if (ok) { + api.del(`/admin/chats/${roomId}`, {}).then(() => { + // Return user to chats page. If modal, close modal. + const modal = buttonEl.parents('.chat-modal'); + if (modal.length) { + chatModule.close(modal); + } else { + Chats.destroyAutoComplete(roomId); + ajaxify.go('chats'); + } + }).catch(alerts.error); + } + }, + }); }); }; @@ -362,18 +355,16 @@ define('forum/chats', [ save: { label: '[[global:save]]', className: 'btn-primary', - callback: submit, + callback: function () { + api.put(`/chats/${roomId}`, { + name: modal.find('#roomName').val(), + }).catch(alerts.error); + }, }, }, }); }); }); - - function submit() { - api.put(`/chats/${roomId}`, { - name: modal.find('#roomName').val(), - }).catch(alerts.error); - } }; Chats.addSendHandlers = function (roomId, inputEl, sendEl) { @@ -452,37 +443,41 @@ define('forum/chats', [ roomid = ''; } Chats.destroyAutoComplete(ajaxify.data.roomId); + socket.emit('modules.chats.leave', ajaxify.data.roomId); const url = 'user/' + ajaxify.data.userslug + '/chats/' + roomid + window.location.search; - if (self.fetch) { - fetch(config.relative_path + '/api/' + url, { credentials: 'include' }) - .then(function (response) { - if (response.ok) { - response.json().then(function (payload) { - app.parseAndTranslate('partials/chats/message-window', payload, function (html) { - components.get('chat/main-wrapper').html(html); - html.find('.timeago').timeago(); - ajaxify.data = payload; - Chats.setActive(); - Chats.addEventListeners(); - hooks.fire('action:chat.loaded', $('.chats-full')); - messages.scrollToBottom($('.expanded-chat ul.chat-content')); - if (history.pushState) { - history.pushState({ - url: url, - }, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + url); - } - }); - }); - } else { - console.warn('[search] Received ' + response.status); - } - }) - .catch(function (error) { - console.warn('[search] ' + error.message); - }); - } else { - ajaxify.go(url); + if (!self.fetch) { + return ajaxify.go(url); } + const params = new URL(document.location).searchParams; + params.set('switch', 1); + const dataUrl = `${config.relative_path}/api/user/${ajaxify.data.userslug}/chats/${roomid}?${params.toString()}`; + fetch(dataUrl, { credentials: 'include' }) + .then(async function (response) { + if (!response.ok) { + return console.warn('[search] Received ' + response.status); + } + const payload = await response.json(); + const html = await app.parseAndTranslate('partials/chats/message-window', payload); + const mainWrapper = components.get('chat/main-wrapper'); + mainWrapper.html(html); + chatNavWrapper = $('[component="chat/nav-wrapper"]'); + html.find('.timeago').timeago(); + ajaxify.data = { ...ajaxify.data, ...payload }; + $('body').addClass(ajaxify.data.bodyClass); + mainWrapper.find('[data-bs-toggle="tooltip"]').tooltip(); + Chats.setActive(); + Chats.addEventListeners(); + hooks.fire('action:chat.loaded', $('.chats-full')); + messages.scrollToBottom(mainWrapper.find('.expanded-chat ul.chat-content')); + if (history.pushState) { + history.pushState({ + url: url, + }, null, window.location.protocol + '//' + window.location.host + config.relative_path + '/' + url); + } + }) + .catch(function (error) { + console.warn('[search] ' + error.message); + }); }; Chats.addGlobalEventListeners = function () { @@ -496,7 +491,11 @@ define('forum/chats', [ Chats.addSocketListeners = function () { socket.on('event:chats.receive', function (data) { + if (chatModule.isFromBlockedUser(data.fromUid)) { + return; + } if (parseInt(data.roomId, 10) === parseInt(ajaxify.data.roomId, 10)) { + data.self = parseInt(app.user.uid, 10) === parseInt(data.fromUid, 10) ? 1 : 0; if (!newMessage) { newMessage = data.self === 0; } @@ -504,33 +503,21 @@ define('forum/chats', [ data.message.timestamp = Math.min(Date.now(), data.message.timestamp); data.message.timestampISO = utils.toISOString(data.message.timestamp); messages.appendChatMessage($('.expanded-chat .chat-content'), data.message); - } else if (ajaxify.data.template.chats) { - const roomEl = $('[data-roomid=' + data.roomId + ']'); - - if (roomEl.length > 0) { - roomEl.addClass('unread'); - - const markEl = roomEl.find('.mark-read').get(0); - if (markEl) { - markEl.querySelector('.read').classList.add('hidden'); - markEl.querySelector('.unread').classList.remove('hidden'); - } - } else { - const recentEl = components.get('chat/recent'); - app.parseAndTranslate('partials/chats/recent_room', { - rooms: { - roomId: data.roomId, - lastUser: data.message.fromUser, - usernames: data.message.fromUser.username, - unread: true, - }, - }, function (html) { - recentEl.prepend(html); - }); - } } }); + socket.on('event:chats.public.unread', function (data) { + if ( + chatModule.isFromBlockedUser(data.fromUid) || + chatModule.isLookingAtRoom(data.roomId) || + app.user.uid === parseInt(data.fromUid, 10) + ) { + return; + } + Chats.markChatPageElUnread(data); + Chats.increasePublicRoomUnreadCount(chatNavWrapper.find('[data-roomid=' + data.roomId + ']')); + }); + socket.on('event:user_status_change', function (data) { app.updateUserStatus($('.chats-list [data-uid="' + data.uid + '"] [component="user/status"]'), data.status); }); @@ -539,33 +526,55 @@ define('forum/chats', [ socket.on('event:chats.roomRename', function (data) { const roomEl = components.get('chat/recent/room', data.roomId); - const titleEl = roomEl.find('[component="chat/title"]'); - ajaxify.data.roomName = data.newName; - - titleEl.text(data.newName); + if (roomEl.length) { + const titleEl = roomEl.find('[component="chat/room/title"]'); + ajaxify.data.roomName = data.newName; + titleEl.text(data.newName); + } }); socket.on('event:chats.mark', ({ roomId, state }) => { - const roomEls = document.querySelectorAll(`[component="chat/recent"] [data-roomid="${roomId}"], [component="chat/list"] [data-roomid="${roomId}"]`); - - roomEls.forEach((roomEl) => { - roomEl.classList[state ? 'add' : 'remove']('unread'); - - const markEl = roomEl.querySelector('.mark-read'); - if (markEl) { - markEl.querySelector('.read').classList[state ? 'add' : 'remove']('hidden'); - markEl.querySelector('.unread').classList[state ? 'remove' : 'add']('hidden'); + const roomEls = $(`[component="chat/recent"] [data-roomid="${roomId}"], [component="chat/list"] [data-roomid="${roomId}"], [component="chat/public"] [data-roomid="${roomId}"]`); + roomEls.each((idx, el) => { + const roomEl = $(el); + chatModule.markChatElUnread(roomEl, state === 1); + if (state === 0) { + Chats.updatePublicRoomUnreadCount(roomEl, 0); } }); }); }; + Chats.markChatPageElUnread = function (data) { + if (!ajaxify.data.template.chats) { + return; + } + + const roomEl = chatNavWrapper.find('[data-roomid=' + data.roomId + ']'); + chatModule.markChatElUnread(roomEl, true); + }; + + Chats.increasePublicRoomUnreadCount = function (roomEl) { + const unreadCountEl = roomEl.find('[component="chat/public/room/unread/count"]'); + const newCount = (parseInt(unreadCountEl.attr('data-count'), 10) || 0) + 1; + Chats.updatePublicRoomUnreadCount(roomEl, newCount); + }; + + Chats.updatePublicRoomUnreadCount = function (roomEl, count) { + const unreadCountEl = roomEl.find('[component="chat/public/room/unread/count"]'); + const countText = count > 50 ? '50+' : count; + unreadCountEl.toggleClass('hidden', count <= 0).text(countText).attr('data-count', count); + }; + Chats.setActive = function () { + chatNavWrapper.find('[data-roomid]').removeClass('active'); if (ajaxify.data.roomId) { - const chatEl = document.querySelector(`[component="chat/recent"] [data-roomid="${ajaxify.data.roomId}"]`); - if (chatEl.classList.contains('unread')) { + socket.emit('modules.chats.enter', ajaxify.data.roomId); + const chatEl = chatNavWrapper.find(`[data-roomid="${ajaxify.data.roomId}"]`); + chatEl.addClass('active'); + if (chatEl.hasClass('unread')) { api.del(`/chats/${ajaxify.data.roomId}/state`, {}); - chatEl.classList.remove('unread'); + chatEl.removeClass('unread'); } if (!utils.isMobile()) { @@ -573,12 +582,10 @@ define('forum/chats', [ } messages.updateTextAreaHeight($(`[component="chat/messages"][data-roomid="${ajaxify.data.roomId}"]`)); } - $('.chats-list [data-roomid]').removeClass('active'); - $('.chats-list [data-roomid="' + ajaxify.data.roomId + '"]').addClass('active'); - components.get('chat/nav-wrapper').attr('data-loaded', ajaxify.data.roomId ? '1' : '0'); + chatNavWrapper.attr('data-loaded', ajaxify.data.roomId ? '1' : '0'); }; - return Chats; }); + diff --git a/public/src/client/chats/create.js b/public/src/client/chats/create.js new file mode 100644 index 0000000000..9f532f020d --- /dev/null +++ b/public/src/client/chats/create.js @@ -0,0 +1,85 @@ +'use strict'; + + +define('forum/chats/create', [ + 'components', 'api', 'alerts', 'forum/chats/search', +], function (components, api, alerts, search) { + const create = {}; + create.init = function () { + components.get('chat/create').on('click', handleCreate); + }; + + async function handleCreate() { + let groups = []; + if (app.user.isAdmin) { + groups = await socket.emit('groups.getChatGroups', {}); + } + const html = await app.parseAndTranslate('modals/create-room', { + user: app.user, + groups: groups, + }); + + const modal = bootbox.dialog({ + title: '[[modules:chat.create-room]]', + message: html, + buttons: { + save: { + label: '[[global:create]]', + className: 'btn-primary', + callback: async function () { + const roomName = modal.find('[component="chat/room/name"]').val(); + const uids = modal.find('[component="chat/room/users"] [component="chat/user"]').find('[data-uid]').map( + (i, el) => $(el).attr('data-uid') + ).get(); + const type = modal.find('[component="chat/room/type"]').val(); + const groups = modal.find('[component="chat/room/groups"]').val(); + + if (type === 'private' && !uids.length) { + alerts.error('[[error:no-users-selected]]'); + return false; + } + if (type === 'public' && !groups) { + alerts.error('[[error:no-groups-selected]]'); + return false; + } + await createRoom({ + roomName: roomName, + uids: uids, + type: type, + groups: groups, + }); + }, + }, + }, + }); + + const chatRoomUsersList = modal.find('[component="chat/room/users"]'); + + search.init({ + onSelect: async function (user) { + const html = await app.parseAndTranslate('modals/create-room', 'selectedUsers', { selectedUsers: [user] }); + chatRoomUsersList.append(html); + }, + }); + + chatRoomUsersList.on('click', '[component="chat/room/users/remove"]', function () { + $(this).parents('[data-uid]').remove(); + }); + + + modal.find('[component="chat/room/type"]').on('change', function () { + const type = $(this).val(); + modal.find('[component="chat/room/public/options"]').toggleClass('hidden', type === 'private'); + }); + } + + async function createRoom(params) { + if (!app.user.uid) { + return alerts.error('[[error:not-logged-in]]'); + } + const { roomId } = await api.post(`/chats`, params); + ajaxify.go('chats/' + roomId); + } + + return create; +}); diff --git a/public/src/client/chats/manage.js b/public/src/client/chats/manage.js new file mode 100644 index 0000000000..2bb2ec41c4 --- /dev/null +++ b/public/src/client/chats/manage.js @@ -0,0 +1,106 @@ +'use strict'; + + +define('forum/chats/manage', [ + 'api', 'alerts', 'translator', 'autocomplete', 'forum/chats/user-list', +], function (api, alerts, translator, autocomplete, userList) { + const manage = {}; + + manage.init = function (roomId, buttonEl) { + let modal; + + buttonEl.on('click', async function () { + let groups = []; + if (app.user.isAdmin) { + groups = await socket.emit('groups.getChatGroups', {}); + if (Array.isArray(ajaxify.data.groups)) { + groups.forEach((g) => { + g.selected = ajaxify.data.groups.includes(g.name); + }); + } + } + + const html = await app.parseAndTranslate('modals/manage-room', { + groups, + user: app.user, + group: ajaxify.data, + }); + modal = bootbox.dialog({ + title: '[[modules:chat.manage-room]]', + message: html, + }); + + modal.attr('component', 'chat/manage-modal'); + + refreshParticipantsList(roomId, modal); + addKickHandler(roomId, modal); + + const userListEl = modal.find('[component="chat/manage/user/list"]'); + const userListElSearch = modal.find('[component="chat/manage/user/list/search"]'); + userList.addSearchHandler(roomId, userListElSearch, async (data) => { + if (userListElSearch.val()) { + userListEl.html(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + } else { + refreshParticipantsList(roomId, modal); + } + }); + + userList.addInfiniteScrollHandler(roomId, userListEl, async (listEl, data) => { + listEl.append(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + }); + + const searchInput = modal.find('[component="chat/manage/user/add/search"]'); + const errorEl = modal.find('.text-danger'); + autocomplete.user(searchInput, function (event, selected) { + errorEl.text(''); + api.post(`/chats/${roomId}/users`, { + uids: [selected.item.user.uid], + }).then((body) => { + refreshParticipantsList(roomId, modal, body); + searchInput.val(''); + }).catch((err) => { + translator.translate(err.message, function (translated) { + errorEl.text(translated); + }); + }); + }); + + modal.find('[component="chat/manage/save/groups"]').on('click', (ev) => { + const btn = $(ev.target); + api.put(`/chats/${roomId}`, { + groups: modal.find('[component="chat/room/groups"]').val(), + }).then((payload) => { + ajaxify.data.groups = payload.groups; + btn.addClass('btn-success'); + setTimeout(() => btn.removeClass('btn-success'), 1000); + }).catch(alerts.error); + }); + }); + }; + + function addKickHandler(roomId, modal) { + modal.on('click', '[data-action="kick"]', function () { + const uid = parseInt(this.getAttribute('data-uid'), 10); + + api.del(`/chats/${roomId}/users/${uid}`, {}).then((body) => { + refreshParticipantsList(roomId, modal, body); + }).catch(alerts.error); + }); + } + + async function refreshParticipantsList(roomId, modal, data) { + const listEl = modal.find('[component="chat/manage/user/list"]'); + + if (!data) { + try { + data = await api.get(`/chats/${roomId}/users`, {}); + } catch (err) { + listEl.find('li').text(await translator.translate('[[error:invalid-data]]')); + } + } + + listEl.html(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + } + + return manage; +}); diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index f51b261acf..0105c82666 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -72,8 +72,9 @@ define('forum/chats/messages', [ } messages.appendChatMessage = function (chatContentEl, data) { - const lastSpeaker = parseInt(chatContentEl.find('.chat-message').last().attr('data-uid'), 10); - const lasttimestamp = parseInt(chatContentEl.find('.chat-message').last().attr('data-timestamp'), 10); + const lastMsgEl = chatContentEl.find('.chat-message').last(); + const lastSpeaker = parseInt(lastMsgEl.attr('data-uid'), 10); + const lasttimestamp = parseInt(lastMsgEl.attr('data-timestamp'), 10); if (!Array.isArray(data)) { data.newSet = lastSpeaker !== parseInt(data.fromuid, 10) || parseInt(data.timestamp, 10) > parseInt(lasttimestamp, 10) + (1000 * 60 * 3); @@ -91,6 +92,12 @@ define('forum/chats/messages', [ messages.onMessagesAddedToDom(newMessage); if (isAtBottom) { messages.scrollToBottom(chatContentEl); + // remove some message elements if there are too many + const chatMsgEls = chatContentEl.find('[data-mid]'); + if (chatMsgEls.length > 150) { + const removeCount = chatMsgEls.length - 150; + chatMsgEls.slice(0, removeCount).remove(); + } } hooks.fire('action:chat.received', { @@ -239,17 +246,23 @@ define('forum/chats/messages', [ } function onChatMessageDeleted(messageId) { - components.get('chat/message', messageId) - .toggleClass('deleted', true) - .find('[component="chat/message/body"]') - .translateHtml('[[modules:chat.message-deleted]]'); + const msgEl = components.get('chat/message', messageId); + const isSelf = parseInt(msgEl.attr('data-uid'), 10) === app.user.uid; + msgEl.toggleClass('deleted', true); + if (!isSelf) { + msgEl.find('[component="chat/message/body"]') + .translateHtml('

        [[modules:chat.message-deleted]]

        '); + } } function onChatMessageRestored(message) { - components.get('chat/message', message.messageId) - .toggleClass('deleted', false) - .find('[component="chat/message/body"]') - .html(message.content); + const msgEl = components.get('chat/message', message.messageId); + const isSelf = parseInt(msgEl.attr('data-uid'), 10) === app.user.uid; + msgEl.toggleClass('deleted', false); + if (!isSelf) { + msgEl.find('[component="chat/message/body"]') + .translateHtml(message.content); + } } messages.delete = function (messageId, roomId) { diff --git a/public/src/client/chats/recent.js b/public/src/client/chats/recent.js index 95532a3df0..68a01b62ea 100644 --- a/public/src/client/chats/recent.js +++ b/public/src/client/chats/recent.js @@ -1,13 +1,13 @@ 'use strict'; -define('forum/chats/recent', ['alerts', 'api'], function (alerts, api) { +define('forum/chats/recent', ['alerts', 'api', 'chat'], function (alerts, api, chat) { const recent = {}; recent.init = function () { require(['forum/chats'], function (Chats) { - $('[component="chat/recent"]') - .on('click', '[component="chat/recent/room"]', function (e) { + $('[component="chat/nav-wrapper"]') + .on('click', '[component="chat/recent/room"], [component="chat/public/room"]', function (e) { e.stopPropagation(); e.preventDefault(); const roomId = this.getAttribute('data-roomid'); @@ -16,21 +16,7 @@ define('forum/chats/recent', ['alerts', 'api'], function (alerts, api) { .on('click', '.mark-read', function (e) { e.stopPropagation(); const chatEl = this.closest('[data-roomid]'); - const state = !chatEl.classList.contains('unread'); // this is the new state - const roomId = chatEl.getAttribute('data-roomid'); - api[state ? 'put' : 'del'](`/chats/${roomId}/state`, {}).catch((err) => { - alerts.error(err); - - // Revert on failure - chatEl.classList[state ? 'remove' : 'add']('unread'); - this.querySelector('.unread').classList[state ? 'add' : 'remove']('hidden'); - this.querySelector('.read').classList[!state ? 'add' : 'remove']('hidden'); - }); - - // Immediate feedback - chatEl.classList[state ? 'add' : 'remove']('unread'); - this.querySelector('.unread').classList[!state ? 'add' : 'remove']('hidden'); - this.querySelector('.read').classList[state ? 'add' : 'remove']('hidden'); + chat.toggleReadState(chatEl); }); $('[component="chat/recent"]').on('scroll', function () { diff --git a/public/src/client/chats/search.js b/public/src/client/chats/search.js index 1641efcb1e..bb0d160328 100644 --- a/public/src/client/chats/search.js +++ b/public/src/client/chats/search.js @@ -5,22 +5,35 @@ define('forum/chats/search', [ 'components', 'api', 'alerts', ], function (components, api, alerts) { const search = {}; + let users = []; - search.init = function () { + search.init = function (options) { + options = options || {}; + users.length = 0; components.get('chat/search').on('keyup', utils.debounce(doSearch, 250)); const chatsListEl = $('[component="chat/search/list"]'); chatsListEl.on('click', '[data-uid]', function () { - onUserClick($(this).attr('data-uid')); + if (options.onSelect) { + options.onSelect( + users.find(u => parseInt(u.uid, 10) === parseInt($(this).attr('data-uid'), 10)) + ); + } + clearInputAndResults(chatsListEl); }); }; + function clearInputAndResults(chatsListEl) { + components.get('chat/search').val(''); + removeResults(chatsListEl); + chatsListEl.find('[component="chat/search/no-users"]').addClass('hidden'); + chatsListEl.find('[component="chat/search/start-typing"]').removeClass('hidden'); + } + function doSearch() { const chatsListEl = $('[component="chat/search/list"]'); const username = components.get('chat/search').val(); if (!username) { - removeResults(chatsListEl); - chatsListEl.find('[component="chat/search/no-users"]').addClass('hidden'); - return chatsListEl.find('[component="chat/search/start-typing"]').removeClass('hidden'); + return clearInputAndResults(chatsListEl); } chatsListEl.find('[component="chat/search/start-typing"]').addClass('hidden'); api.get('/api/users', { @@ -32,6 +45,7 @@ define('forum/chats/search', [ } function removeResults(chatsListEl) { + users.length = 0; chatsListEl.find('[data-uid]').remove(); } @@ -41,35 +55,15 @@ define('forum/chats/search', [ data.users = data.users.filter(function (user) { return parseInt(user.uid, 10) !== parseInt(app.user.uid, 10); }); - + users = data.users; if (!data.users.length) { return chatsListEl.find('[component="chat/search/no-users"]').removeClass('hidden'); } chatsListEl.find('[component="chat/search/no-users"]').addClass('hidden'); - const html = await app.parseAndTranslate('chats', 'searchUsers', { searchUsers: data.users }); + const html = await app.parseAndTranslate('modals/create-room', 'searchUsers', { searchUsers: data.users }); chatsListEl.append(html); chatsListEl.parent().toggleClass('show', true); } - function onUserClick(uid) { - if (!uid) { - return; - } - socket.emit('modules.chats.hasPrivateChat', uid, function (err, roomId) { - if (err) { - return alerts.error(err); - } - if (roomId) { - require(['forum/chats'], function (chats) { - chats.switchChat(roomId); - }); - } else { - require(['chat'], function (chat) { - chat.newChat(uid); - }); - } - }); - } - return search; }); diff --git a/public/src/client/chats/user-list.js b/public/src/client/chats/user-list.js new file mode 100644 index 0000000000..cd4b5a8f50 --- /dev/null +++ b/public/src/client/chats/user-list.js @@ -0,0 +1,48 @@ +'use strict'; + + +define('forum/chats/user-list', ['api'], function (api) { + const userList = {}; + + userList.init = function (roomId, container) { + const userListEl = container.find('[component="chat/user/list"]'); + if (!userListEl.length) { + return; + } + container.find('[component="chat/user/list/btn"]').on('click', () => { + userListEl.toggleClass('hidden'); + }); + + userList.addInfiniteScrollHandler(roomId, userListEl, async (listEl, data) => { + listEl.append(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); + }); + }; + + userList.addInfiniteScrollHandler = function (roomId, listEl, callback) { + listEl.on('scroll', utils.debounce(async () => { + const bottom = (listEl[0].scrollHeight - listEl.height()) * 0.85; + if (listEl.scrollTop() > bottom) { + const lastIndex = listEl.find('[data-index]').last().attr('data-index'); + const data = await api.get(`/chats/${roomId}/users`, { + start: parseInt(lastIndex, 10) + 1, + }); + if (data && data.users.length) { + callback(listEl, data); + } + } + }, 200)); + }; + + userList.addSearchHandler = function (roomId, inputEl, callback) { + inputEl.on('keyup', utils.debounce(async () => { + const username = inputEl.val(); + const data = await socket.emit('modules.chats.searchMembers', { + username: username, + roomId: roomId, + }); + callback(data); + }, 200)); + }; + + return userList; +}); diff --git a/public/src/client/header/chat.js b/public/src/client/header/chat.js index 6b4a04aaf9..e384291945 100644 --- a/public/src/client/header/chat.js +++ b/public/src/client/header/chat.js @@ -1,6 +1,8 @@ 'use strict'; -define('forum/header/chat', ['components', 'hooks'], function (components, hooks) { +define('forum/header/chat', [ + 'components', 'hooks', +], function (components, hooks) { const chat = {}; chat.prepareDOM = function () { @@ -29,7 +31,20 @@ define('forum/header/chat', ['components', 'hooks'], function (components, hooks socket.removeListener('event:chats.roomRename', onRoomRename); socket.on('event:chats.roomRename', onRoomRename); - socket.on('event:unread.updateChatCount', function (count) { + socket.on('event:unread.updateChatCount', async function (data) { + if (data) { + const [chatModule, chatPage] = await app.require(['chat', 'forum/chats']); + if ( + chatModule.isFromBlockedUser(data.fromUid) || + chatModule.isLookingAtRoom(data.roomId) || + app.user.uid === parseInt(data.fromUid, 10) + ) { + return; + } + chatPage.markChatPageElUnread(data); + } + + let count = await socket.emit('modules.chats.getUnreadCount', {}); const chatIcon = components.get('chat/icon'); count = Math.max(0, count); chatIcon.toggleClass('fa-comment', count > 0) @@ -56,10 +71,9 @@ define('forum/header/chat', ['components', 'hooks'], function (components, hooks requireAndCall('onRoomRename', data); } - function requireAndCall(method, param) { - require(['chat'], function (chat) { - chat[method](param); - }); + async function requireAndCall(method, param) { + const chat = await app.require('chat'); + chat[method](param); } return chat; diff --git a/public/src/modules/autocomplete.js b/public/src/modules/autocomplete.js index ae435e72bd..277859ce3d 100644 --- a/public/src/modules/autocomplete.js +++ b/public/src/modules/autocomplete.js @@ -1,13 +1,13 @@ 'use strict'; define('autocomplete', ['api', 'alerts'], function (api, alerts) { - const module = {}; + const autocomplete = {}; const _default = { delay: 200, appendTo: null, }; - module.init = (params) => { + autocomplete.init = (params) => { const acParams = { ..._default, ...params }; const { input, onSelect } = acParams; app.loadJQueryUI(function () { @@ -23,14 +23,14 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { }); }; - module.user = function (input, params, onSelect) { + autocomplete.user = function (input, params, onSelect) { if (typeof params === 'function') { onSelect = params; params = {}; } params = params || {}; - module.init({ + autocomplete.init({ input, onSelect, source: (request, response) => { @@ -69,8 +69,8 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { }); }; - module.group = function (input, onSelect) { - module.init({ + autocomplete.group = function (input, onSelect) { + autocomplete.init({ input, onSelect, source: (request, response) => { @@ -96,8 +96,8 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { }); }; - module.tag = function (input, onSelect) { - module.init({ + autocomplete.tag = function (input, onSelect) { + autocomplete.init({ input, onSelect, delay: 100, @@ -129,5 +129,5 @@ define('autocomplete', ['api', 'alerts'], function (api, alerts) { onselect(event, ui); } - return module; + return autocomplete; }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 54dca63971..d1b5a8ecd6 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -88,48 +88,49 @@ define('chat', [ if (err) { return alerts.error(err); } - - const rooms = data.rooms.filter(function (room) { - return room.teaser; + const rooms = data.rooms.map((room) => { + if (room && room.teaser) { + room.teaser.timeagoLong = $.timeago(new Date(parseInt(room.teaser.timestamp, 10))); + } + return room; }); - for (let i = 0; i < rooms.length; i += 1) { - rooms[i].teaser.timeagoLong = $.timeago(new Date(parseInt(rooms[i].teaser.timestamp, 10))); - } + translator.toggleTimeagoShorthand(async function () { + rooms.forEach((room) => { + if (room && room.teaser) { + room.teaser.timeago = $.timeago(new Date(parseInt(room.teaser.timestamp, 10))); + room.teaser.timeagoShort = room.teaser.timeago; + } + }); - translator.toggleTimeagoShorthand(function () { - for (let i = 0; i < rooms.length; i += 1) { - rooms[i].teaser.timeago = $.timeago(new Date(parseInt(rooms[i].teaser.timestamp, 10))); - rooms[i].teaser.timeagoShort = rooms[i].teaser.timeago; - } translator.toggleTimeagoShorthand(); - app.parseAndTranslate('partials/chats/dropdown', { rooms: rooms }, function (html) { - const listEl = chatsListEl.get(0); + const html = await app.parseAndTranslate('partials/chats/dropdown', { rooms: rooms }); + const listEl = chatsListEl.get(0); - chatsListEl.find('*').not('.navigation-link').remove(); - chatsListEl.prepend(html); - chatsListEl.off('click').on('click', '[data-roomid]', function (ev) { - if (['.user-link', '.mark-read'].some(className => ev.target.closest(className))) { - return; - } - const roomId = $(this).attr('data-roomid'); - if (!ajaxify.currentPage.match(/^chats\//)) { - module.openChat(roomId); - } else { - ajaxify.go('user/' + app.user.userslug + '/chats/' + roomId); - } - }); + chatsListEl.find('*').not('.navigation-link').remove(); + chatsListEl.prepend(html); + chatsListEl.off('click').on('click', '[data-roomid]', function (ev) { + if (['.user-link', '.mark-read'].some(className => ev.target.closest(className))) { + return; + } + const roomId = $(this).attr('data-roomid'); + if (!ajaxify.currentPage.match(/^chats\//)) { + module.openChat(roomId); + } else { + ajaxify.go('user/' + app.user.userslug + '/chats/' + roomId); + } + }); - listEl.removeEventListener('click', onMarkReadClicked); - listEl.addEventListener('click', onMarkReadClicked); + listEl.removeEventListener('click', onMarkReadClicked); + listEl.addEventListener('click', onMarkReadClicked); - $('[component="chats/mark-all-read"]').off('click').on('click', function () { - socket.emit('modules.chats.markAllRead', function (err) { - if (err) { - return alerts.error(err); - } + $('[component="chats/mark-all-read"]').off('click').on('click', async function () { + await socket.emit('modules.chats.markAllRead'); + if (ajaxify.data.template.chats) { + $('[component="chat/nav-wrapper"] [data-roomid]').each((i, el) => { + module.markChatElUnread($(el), false); }); - }); + } }); }); }); @@ -143,28 +144,51 @@ define('chat', [ e.stopPropagation(); const chatEl = e.target.closest('[data-roomid]'); - const state = !chatEl.classList.contains('unread'); + module.toggleReadState(chatEl); + } + + module.toggleReadState = function (chatEl) { + const state = !chatEl.classList.contains('unread'); // this is the new state const roomId = chatEl.getAttribute('data-roomid'); api[state ? 'put' : 'del'](`/chats/${roomId}/state`, {}).catch((err) => { alerts.error(err); // Revert on failure - chatEl.classList[state ? 'remove' : 'add']('unread'); - chatEl.querySelector('.unread').classList[state ? 'add' : 'remove']('hidden'); - chatEl.querySelector('.read').classList[!state ? 'add' : 'remove']('hidden'); + module.markChatElUnread($(chatEl), !(state === 1)); }); // Immediate feedback - chatEl.classList[state ? 'add' : 'remove']('unread'); - chatEl.querySelector('.unread').classList[!state ? 'add' : 'remove']('hidden'); - chatEl.querySelector('.read').classList[state ? 'add' : 'remove']('hidden'); - } + module.markChatElUnread($(chatEl), state === 1); + }; + + module.isFromBlockedUser = function (fromUid) { + return app.user.blocks.includes(parseInt(fromUid, 10)); + }; + + module.isLookingAtRoom = function (roomId) { + return ajaxify.data.template.chats && parseInt(ajaxify.data.roomId, 10) === parseInt(roomId, 10); + }; + + module.markChatElUnread = function (roomEl, unread) { + if (roomEl.length > 0) { + roomEl.toggleClass('unread', unread); + const markEl = roomEl.find('.mark-read'); + if (markEl.length) { + markEl.find('.read').toggleClass('hidden', unread); + markEl.find('.unread').toggleClass('hidden', !unread); + } + } + }; module.onChatMessageReceived = function (data) { - if (!newMessage) { - newMessage = data.self === 0; + if (app.user.blocks.includes(parseInt(data.fromUid, 10))) { + return; } if (module.modalExists(data.roomId)) { + data.self = parseInt(app.user.uid, 10) === parseInt(data.fromUid, 10) ? 1 : 0; + if (!newMessage) { + newMessage = data.self === 0; + } data.message.self = data.self; data.message.timestamp = Math.min(Date.now(), data.message.timetamp); data.message.timestampISO = utils.toISOString(data.message.timestamp); @@ -324,8 +348,9 @@ define('chat', [ Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), data.roomId); Chats.addRenameHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="rename"]'), data.roomName); Chats.addLeaveHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="leave"]')); + Chats.addDeleteHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="delete"]')); Chats.addSendHandlers(chatModal.attr('data-roomid'), chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); - Chats.addMemberHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="members"]')); + Chats.addManageHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="members"]')); Chats.createAutoComplete(chatModal.attr('data-roomid'), chatModal.find('[component="chat/input"]')); @@ -381,10 +406,11 @@ define('chat', [ if (chatModal.attr('data-mobile')) { module.disableMobileBehaviour(chatModal); } + const roomId = chatModal.attr('data-roomid'); require(['forum/chats'], function (chats) { - chats.destroyAutoComplete(chatModal.attr('data-roomid')); + chats.destroyAutoComplete(roomId); }); - + socket.emit('modules.chats.leave', roomId); hooks.fire('action:chat.closed', { uuid: uuid, modal: chatModal, @@ -417,8 +443,9 @@ define('chat', [ taskbar.updateActive(uuid); ChatsMessages.scrollToBottom(chatModal.find('.chat-content')); module.focusInput(chatModal); - api.del(`/chats/${chatModal.attr('data-roomid')}/state`, {}); - + const roomId = chatModal.attr('data-roomid'); + api.del(`/chats/${roomId}/state`, {}); + socket.emit('modules.chats.enter', roomId); const env = utils.findBootstrapEnvironment(); if (env === 'xs' || env === 'sm') { module.enableMobileBehaviour(chatModal); diff --git a/public/src/sockets.js b/public/src/sockets.js index 6ffe0878c3..9325c0c595 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -159,9 +159,7 @@ app = window.app || {}; function onConnect() { if (!reconnecting) { hooks.fire('action:connected'); - } - - if (reconnecting) { + } else { const reconnectEl = $('#reconnect'); const reconnectAlert = $('#reconnect-alert'); @@ -188,6 +186,14 @@ app = window.app || {}; app.currentRoom = ''; app.enterRoom(current); } + if (ajaxify.data.template.chats) { + if (ajaxify.data.roomId) { + socket.emit('modules.chats.enter', ajaxify.data.roomId); + } + if (ajaxify.data.publicRooms) { + socket.emit('modules.chats.enterPublic', ajaxify.data.publicRooms.map(r => r.roomId)); + } + } } function onReconnecting() { diff --git a/src/api/chats.js b/src/api/chats.js index 2e7fe6dfd7..835117e235 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -2,6 +2,7 @@ const validator = require('validator'); +const db = require('../database'); const user = require('../user'); const meta = require('../meta'); const messaging = require('../messaging'); @@ -39,12 +40,20 @@ chatsAPI.create = async function (caller, data) { if (!data) { throw new Error('[[error:invalid-data]]'); } + const isPublic = data.type === 'public'; + const isAdmin = await user.isAdministrator(caller.uid); + if (isPublic && !isAdmin) { + throw new Error('[[error:no-privileges]]'); + } if (!data.uids || !Array.isArray(data.uids)) { throw new Error(`[[error:wrong-parameter-type, uids, ${typeof data.uids}, Array]]`); } + if (!isPublic && !data.uids.length) { + throw new Error('[[error:no-users-selected]]'); + } await Promise.all(data.uids.map(async uid => messaging.canMessageUser(caller.uid, uid))); - const roomId = await messaging.newRoom(caller.uid, data.uids); + const roomId = await messaging.newRoom(caller.uid, data); return await messaging.getRoomData(roomId); }; @@ -78,18 +87,46 @@ chatsAPI.post = async (caller, data) => { return message; }; +chatsAPI.update = async (caller, data) => { + if (!data || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + + if (data.hasOwnProperty('name')) { + if (!data.name) { + throw new Error('[[error:invalid-data]]'); + } + await messaging.renameRoom(caller.uid, data.roomId, data.name); + const ioRoom = require('../socket.io').in(`chat_room_${data.roomId}`); + if (ioRoom) { + ioRoom.emit('event:chats.roomRename', { + roomId: data.roomId, + newName: validator.escape(String(data.name)), + }); + } + } + if (data.hasOwnProperty('groups')) { + const [roomData, isAdmin] = await Promise.all([ + messaging.getRoomData(data.roomId), + user.isAdministrator(caller.uid), + ]); + if (!roomData) { + throw new Error('[[error:invalid-data]]'); + } + if (roomData.public && isAdmin) { + await db.setObjectField(`chat:room:${data.roomId}`, 'groups', JSON.stringify(data.groups)); + } + } + return messaging.loadRoom(caller.uid, { + roomId: data.roomId, + }); +}; + chatsAPI.rename = async (caller, data) => { if (!data || !data.roomId || !data.name) { throw new Error('[[error:invalid-data]]'); } - await messaging.renameRoom(caller.uid, data.roomId, data.name); - const uids = await messaging.getUidsInRoom(data.roomId, 0, -1); - const eventData = { roomId: data.roomId, newName: validator.escape(String(data.name)) }; - - socketHelpers.emitToUids('event:chats.roomRename', eventData, uids); - return messaging.loadRoom(caller.uid, { - roomId: data.roomId, - }); + return await chatsAPI.update(caller, data); }; chatsAPI.mark = async (caller, data) => { @@ -103,16 +140,19 @@ chatsAPI.mark = async (caller, data) => { await messaging.markRead(caller.uid, roomId); socketHelpers.emitToUids('event:chats.markedAsRead', { roomId: roomId }, [caller.uid]); - const uidsInRoom = await messaging.getUidsInRoom(roomId, 0, -1); - if (!uidsInRoom.includes(String(caller.uid))) { + const isUserInRoom = await messaging.isUserInRoom(caller.uid, roomId); + if (!isUserInRoom) { return; } + let chatNids = await db.getSortedSetScan({ + key: `uid:${caller.uid}:notifications:unread`, + match: `chat_*`, + }); + chatNids = chatNids.filter( + nid => nid && !nid.startsWith(`chat_${caller.uid}`) && nid.endsWith(`_${roomId}`) + ); - // Mark notification read - const nids = uidsInRoom.filter(uid => parseInt(uid, 10) !== caller.uid) - .map(uid => `chat_${uid}_${roomId}`); - - await notifications.markReadMultiple(nids, caller.uid); + await notifications.markReadMultiple(chatNids, caller.uid); await user.notifications.pushCount(caller.uid); } @@ -123,16 +163,18 @@ chatsAPI.mark = async (caller, data) => { }; chatsAPI.users = async (caller, data) => { + const start = data.hasOwnProperty('start') ? data.start : 0; + const stop = start + 39; const [isOwner, isUserInRoom, users] = await Promise.all([ messaging.isRoomOwner(caller.uid, data.roomId), messaging.isUserInRoom(caller.uid, data.roomId), - messaging.getUsersInRoom(data.roomId, 0, -1), + messaging.getUsersInRoom(data.roomId, start, stop), ]); if (!isUserInRoom) { throw new Error('[[error:no-privileges]]'); } users.forEach((user) => { - user.canKick = (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)) && isOwner; + user.canKick = isOwner && (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)); }); return { users }; }; @@ -145,10 +187,13 @@ chatsAPI.invite = async (caller, data) => { if (!data || !data.roomId) { throw new Error('[[error:invalid-data]]'); } - + const roomData = await messaging.getRoomData(data.roomId); + if (!roomData) { + throw new Error('[[error:invalid-data]]'); + } const userCount = await messaging.getUserCountInRoom(data.roomId); const maxUsers = meta.config.maximumUsersInChatRoom; - if (maxUsers && userCount >= maxUsers) { + if (!roomData.public && maxUsers && userCount >= maxUsers) { throw new Error('[[error:cant-add-more-users-to-chat-room]]'); } diff --git a/src/controllers/accounts/chats.js b/src/controllers/accounts/chats.js index 02c9b404cc..221e1f5fae 100644 --- a/src/controllers/accounts/chats.js +++ b/src/controllers/accounts/chats.js @@ -1,5 +1,6 @@ 'use strict'; +const db = require('../../database'); const messaging = require('../../messaging'); const meta = require('../../meta'); const user = require('../../user'); @@ -21,35 +22,45 @@ chatsController.get = async function (req, res, next) { if (!canChat) { return next(new Error('[[error:no-privileges]]')); } - const recentChats = await messaging.getRecentChats(req.uid, uid, 0, 29); - if (!recentChats) { - return next(); + + const payload = { + title: '[[pages:chats]]', + uid: uid, + userslug: req.params.userslug, + }; + const isSwitch = res.locals.isAPI && parseInt(req.query.switch, 10) === 1; + if (!isSwitch) { + const [recentChats, publicRooms, privateRoomCount] = await Promise.all([ + messaging.getRecentChats(req.uid, uid, 0, 29), + messaging.getPublicRooms(req.uid, uid), + db.sortedSetCard(`uid:${uid}:chat:rooms`), + ]); + if (!recentChats) { + return next(); + } + payload.rooms = recentChats.rooms; + payload.nextStart = recentChats.nextStart; + payload.publicRooms = publicRooms; + payload.privateRoomCount = privateRoomCount; } if (!req.params.roomid) { - return res.render('chats', { - rooms: recentChats.rooms, - uid: uid, - userslug: req.params.userslug, - nextStart: recentChats.nextStart, - allowed: true, - title: '[[pages:chats]]', - }); + return res.render('chats', payload); } + const room = await messaging.loadRoom(req.uid, { uid: uid, roomId: req.params.roomid }); if (!room) { return next(); } - room.rooms = recentChats.rooms; - room.nextStart = recentChats.nextStart; room.title = room.roomName || room.usernames || '[[pages:chats]]'; - room.uid = uid; - room.userslug = req.params.userslug; - + room.bodyClasses = ['chat-loaded']; room.canViewInfo = await privileges.global.can('view:users:info', uid); - res.render('chats', room); + res.render('chats', { + ...payload, + ...room, + }); }; chatsController.redirectToChat = async function (req, res, next) { diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index d2737ee314..1ef9756784 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -93,7 +93,7 @@ async function getPosts(callerUid, userData, setSuffix) { user.isModerator(callerUid, cids), privileges.categories.isUserAllowedTo('topics:schedule', cids, callerUid), ]); - const cidToIsMod = _.zipObject(cids, isModOfCids); + const isModOfCid = _.zipObject(cids, isModOfCids); const cidToCanSchedule = _.zipObject(cids, canSchedule); do { @@ -111,8 +111,12 @@ async function getPosts(callerUid, userData, setSuffix) { })); const p = await posts.getPostSummaryByPids(pids, callerUid, { stripTags: false }); postData.push(...p.filter( - p => p && p.topic && (isAdmin || cidToIsMod[p.topic.cid] || - (p.topic.scheduled && cidToCanSchedule[p.topic.cid]) || (!p.deleted && !p.topic.deleted)) + p => p && p.topic && ( + isAdmin || + isModOfCid[p.topic.cid] || + (p.topic.scheduled && cidToCanSchedule[p.topic.cid]) || + (!p.deleted && !p.topic.deleted) + ) )); } start += count; diff --git a/src/controllers/write/admin.js b/src/controllers/write/admin.js index b7ba39db10..84d25ac300 100644 --- a/src/controllers/write/admin.js +++ b/src/controllers/write/admin.js @@ -2,6 +2,8 @@ const api = require('../../api'); const helpers = require('../helpers'); +const messaging = require('../../messaging'); +const events = require('../../events'); const Admin = module.exports; @@ -29,6 +31,19 @@ Admin.getAnalyticsData = async (req, res) => { })); }; +Admin.chats = {}; + +Admin.chats.deleteRoom = async (req, res) => { + await messaging.deleteRooms([req.params.roomId]); + + events.log({ + type: 'chat-room-deleted', + uid: req.uid, + ip: req.ip, + }); + helpers.formatApiResponse(200, res); +}; + Admin.generateToken = async (req, res) => { const { uid, description } = req.body; const token = await api.utils.tokens.generate({ uid, description }); diff --git a/src/controllers/write/chats.js b/src/controllers/write/chats.js index fe7900a50a..e595ef1a44 100644 --- a/src/controllers/write/chats.js +++ b/src/controllers/write/chats.js @@ -39,6 +39,14 @@ Chats.post = async (req, res) => { helpers.formatApiResponse(200, res, messageObj); }; +Chats.update = async (req, res) => { + const payload = { ...req.body }; + payload.roomId = req.params.roomId; + const roomObj = await api.chats.update(req, payload); + + helpers.formatApiResponse(200, res, roomObj); +}; + Chats.rename = async (req, res) => { const roomObj = await api.chats.rename(req, { name: req.body.name, @@ -60,7 +68,8 @@ Chats.mark = async (req, res) => { Chats.users = async (req, res) => { const { roomId } = req.params; - const users = await api.chats.users(req, { roomId }); + const start = parseInt(req.query.start, 10) || 0; + const users = await api.chats.users(req, { roomId, start }); helpers.formatApiResponse(200, res, users); }; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index d5db6c3451..12859ed6a4 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -84,7 +84,9 @@ module.exports = function (module) { let result = []; async function doQuery(_key, fields, skip, limit) { - return await module.client.collection('objects').find({ ...query, ...{ _key: _key } }, { projection: fields }) + return await module.client.collection('objects').find({ + ...query, ...{ _key: _key }, + }, { projection: fields }) .sort({ score: sort }) .skip(skip) .limit(limit) diff --git a/src/events.js b/src/events.js index 637f53acf6..09c9062ae8 100644 --- a/src/events.js +++ b/src/events.js @@ -75,6 +75,7 @@ events.types = [ 'export:uploads', 'account-locked', 'getUsersCSV', + 'chat-room-deleted', // To add new types from plugins, just Array.push() to this array ]; diff --git a/src/groups/leave.js b/src/groups/leave.js index 14bfb2558c..32495232c9 100644 --- a/src/groups/leave.js +++ b/src/groups/leave.js @@ -1,9 +1,12 @@ 'use strict'; +const _ = require('lodash'); + const db = require('../database'); const user = require('../user'); const plugins = require('../plugins'); const cache = require('../cache'); +const messaging = require('../messaging'); module.exports = function (Groups) { Groups.leave = async function (groupNames, uid) { @@ -53,7 +56,10 @@ module.exports = function (Groups) { await Promise.all(promises); - await clearGroupTitleIfSet(groupsToLeave, uid); + await Promise.all([ + clearGroupTitleIfSet(groupsToLeave, uid), + leavePublicRooms(groupsToLeave, uid), + ]); plugins.hooks.fire('action:group.leave', { groupNames: groupsToLeave, @@ -61,6 +67,20 @@ module.exports = function (Groups) { }); }; + async function leavePublicRooms(groupNames, uid) { + const allRoomIds = await messaging.getPublicRoomIdsFromSet('chat:rooms:public:order'); + const allRoomData = await messaging.getRoomsData(allRoomIds); + const roomData = allRoomData.filter( + room => room && room.groups.some(group => groupNames.includes(group)) + ); + const isMemberOfAny = _.zipObject( + roomData.map(r => r.roomId), + await Promise.all(roomData.map(r => Groups.isMemberOfAny(uid, r.groups))) + ); + const roomIds = roomData.filter(r => isMemberOfAny[r.roomId]).map(r => r.roomId); + await messaging.leaveRooms(uid, roomIds); + } + async function clearGroupTitleIfSet(groupNames, uid) { groupNames = groupNames.filter(groupName => groupName !== 'registered-users' && !Groups.isPrivilegeGroup(groupName)); if (!groupNames.length) { diff --git a/src/groups/membership.js b/src/groups/membership.js index 66af1c1ed1..aa25719652 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -97,7 +97,7 @@ module.exports = function (Groups) { } Groups.isMemberOfAny = async function (uid, groups) { - if (!groups.length) { + if (!Array.isArray(groups) || !groups.length) { return false; } const isMembers = await Groups.isMemberOfGroups(uid, groups); diff --git a/src/groups/update.js b/src/groups/update.js index 56b541df27..ced53ef04e 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -189,6 +189,7 @@ module.exports = function (Groups) { await updateNavigationItems(oldName, newName); await updateWidgets(oldName, newName); await updateConfig(oldName, newName); + await updateChatRooms(oldName, newName); await db.setObject(`group:${oldName}`, { name: newName, slug: slugify(newName) }); await db.deleteObjectField('groupslug:groupname', group.slug); await db.setObjectField('groupslug:groupname', slugify(newName), newName); @@ -286,4 +287,18 @@ module.exports = function (Groups) { await meta.configs.set('groupsExemptFromMaintenanceMode', meta.config.groupsExemptFromMaintenanceMode); } } + + async function updateChatRooms(oldName, newName) { + const messaging = require('../messaging'); + const roomIds = await db.getSortedSetRange('chat:rooms:public', 0, -1); + const roomData = await messaging.getRoomsData(roomIds); + const bulkSet = []; + roomData.forEach((room) => { + if (room && room.public && Array.isArray(room.groups) && room.groups.includes(oldName)) { + room.groups.splice(room.groups.indexOf(oldName), 1, newName); + bulkSet.push([`chat:room:${room.roomId}`, { groups: JSON.stringify(room.groups) }]); + } + }); + await db.setObjectBulk(bulkSet); + } }; diff --git a/src/messaging/create.js b/src/messaging/create.js index d78a0afe4c..fa83a22c42 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -1,5 +1,7 @@ 'use strict'; +const _ = require('lodash'); + const meta = require('../meta'); const plugins = require('../plugins'); const db = require('../database'); @@ -34,13 +36,18 @@ module.exports = function (Messaging) { }; Messaging.addMessage = async (data) => { + const { uid, roomId } = data; + const roomData = await Messaging.getRoomData(roomId); + if (!roomData) { + throw new Error('[[error:no-room]]'); + } const mid = await db.incrObjectField('global', 'nextMid'); const timestamp = data.timestamp || Date.now(); let message = { content: String(data.content), timestamp: timestamp, - fromuid: data.uid, - roomId: data.roomId, + fromuid: uid, + roomId: roomId, deleted: 0, system: data.system || 0, }; @@ -51,24 +58,34 @@ module.exports = function (Messaging) { message = await plugins.hooks.fire('filter:messaging.save', message); await db.setObject(`message:${mid}`, message); - const isNewSet = await Messaging.isNewSet(data.uid, data.roomId, timestamp); - let uids = await db.getSortedSetRange(`chat:room:${data.roomId}:uids`, 0, -1); - uids = await user.blocks.filterUids(data.uid, uids); + const isNewSet = await Messaging.isNewSet(uid, roomId, timestamp); - await Promise.all([ - Messaging.addRoomToUsers(data.roomId, uids, timestamp), - Messaging.addMessageToUsers(data.roomId, uids, mid, timestamp), - Messaging.markUnread(uids.filter(uid => uid !== String(data.uid)), data.roomId), - ]); + const tasks = [ + Messaging.addMessageToRoom(roomId, mid, timestamp), + Messaging.markRead(uid, roomId), + ]; + if (roomData.public) { + tasks.push( + db.sortedSetAdd('chat:rooms:public:lastpost', timestamp, roomId) + ); + } else { + let uids = await Messaging.getUidsInRoom(roomId, 0, -1); + uids = await user.blocks.filterUids(uid, uids); + tasks.push( + Messaging.addRoomToUsers(roomId, uids, timestamp), + Messaging.markUnread(uids.filter(uid => uid !== String(data.uid)), roomId), + ); + } + await Promise.all(tasks); - const messages = await Messaging.getMessagesData([mid], data.uid, data.roomId, true); + const messages = await Messaging.getMessagesData([mid], uid, roomId, true); if (!messages || !messages[0]) { return null; } messages[0].newSet = isNewSet; - messages[0].mid = mid; - messages[0].roomId = data.roomId; + messages[0].mid = mid; // TODO: messageId is a duplicate + messages[0].roomId = roomId; plugins.hooks.fire('action:messaging.save', { message: messages[0], data: data }); return messages[0]; }; @@ -87,16 +104,11 @@ module.exports = function (Messaging) { if (!uids.length) { return; } - - const keys = uids.map(uid => `uid:${uid}:chat:rooms`); + const keys = _.uniq(uids).map(uid => `uid:${uid}:chat:rooms`); await db.sortedSetsAdd(keys, timestamp, roomId); }; - Messaging.addMessageToUsers = async (roomId, uids, mid, timestamp) => { - if (!uids.length) { - return; - } - const keys = uids.map(uid => `uid:${uid}:chat:room:${roomId}:mids`); - await db.sortedSetsAdd(keys, timestamp, mid); + Messaging.addMessageToRoom = async (roomId, mid, timestamp) => { + await db.sortedSetAdd(`chat:room:${roomId}:mids`, timestamp, mid); }; }; diff --git a/src/messaging/data.js b/src/messaging/data.js index 085081d8ec..b65f8737fb 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -78,13 +78,11 @@ module.exports = function (Messaging) { messages = await Promise.all(messages.map(async (message) => { if (message.system) { message.content = validator.escape(String(message.content)); - message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(message.content)); return message; } const result = await Messaging.parse(message.content, message.fromuid, uid, roomId, isNew); message.content = result; - message.cleanedContent = utils.stripHTMLTags(utils.decodeHTMLEntities(result)); return message; })); @@ -108,7 +106,7 @@ module.exports = function (Messaging) { }); } else if (messages.length === 1) { // For single messages, we don't know the context, so look up the previous message and compare - const key = `uid:${uid}:chat:room:${roomId}:mids`; + const key = `chat:room:${roomId}:mids`; const index = await db.sortedSetRank(key, messages[0].messageId); if (index > 0) { const mid = await db.getSortedSetRange(key, index - 1, index - 1); diff --git a/src/messaging/delete.js b/src/messaging/delete.js index 341bafda6b..c8070f7740 100644 --- a/src/messaging/delete.js +++ b/src/messaging/delete.js @@ -15,19 +15,12 @@ module.exports = function (Messaging) { await Messaging.setMessageField(mid, 'deleted', state); - const [uids, messages] = await Promise.all([ - Messaging.getUidsInRoom(roomId, 0, -1), - Messaging.getMessagesData([mid], uid, roomId, true), - ]); - - uids.forEach((_uid) => { - if (parseInt(_uid, 10) !== parseInt(uid, 10)) { - if (state === 1) { - sockets.in(`uid_${_uid}`).emit('event:chats.delete', mid); - } else if (state === 0) { - sockets.in(`uid_${_uid}`).emit('event:chats.restore', messages[0]); - } - } - }); + const messages = await Messaging.getMessagesData([mid], uid, roomId, true); + const ioRoom = sockets.in(`chat_room_${roomId}`); + if (state === 1 && ioRoom) { + ioRoom.emit('event:chats.delete', mid); + } else if (state === 0 && ioRoom) { + ioRoom.emit('event:chats.restore', messages[0]); + } } }; diff --git a/src/messaging/edit.js b/src/messaging/edit.js index 85cad068ab..d54b5dc587 100644 --- a/src/messaging/edit.js +++ b/src/messaging/edit.js @@ -27,15 +27,9 @@ module.exports = function (Messaging) { await Messaging.setMessageFields(mid, payload); // Propagate this change to users in the room - const [uids, messages] = await Promise.all([ - Messaging.getUidsInRoom(roomId, 0, -1), - Messaging.getMessagesData([mid], uid, roomId, true), - ]); - - uids.forEach((uid) => { - sockets.in(`uid_${uid}`).emit('event:chats.edit', { - messages: messages, - }); + const messages = await Messaging.getMessagesData([mid], uid, roomId, true); + sockets.in(`chat_room_${roomId}`).emit('event:chats.edit', { + messages: messages, }); }; diff --git a/src/messaging/index.js b/src/messaging/index.js index e532043a12..faede05c4e 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -1,15 +1,17 @@ 'use strict'; - +const _ = require('lodash'); const validator = require('validator'); const nconf = require('nconf'); const db = require('../database'); const user = require('../user'); +const groups = require('../groups'); const privileges = require('../privileges'); const plugins = require('../plugins'); const meta = require('../meta'); const utils = require('../utils'); const translator = require('../translator'); +const cache = require('../cache'); const relative_path = nconf.get('relative_path'); @@ -26,38 +28,50 @@ require('./notifications')(Messaging); Messaging.messageExists = async mid => db.exists(`message:${mid}`); Messaging.getMessages = async (params) => { + const { callerUid, uid, roomId } = params; const isNew = params.isNew || false; const start = params.hasOwnProperty('start') ? params.start : 0; const stop = parseInt(start, 10) + ((params.count || 50) - 1); - const indices = {}; - const ok = await canGet('filter:messaging.canGetMessages', params.callerUid, params.uid); + const ok = await canGet('filter:messaging.canGetMessages', callerUid, uid); if (!ok) { return; } - - const mids = await db.getSortedSetRevRange(`uid:${params.uid}:chat:room:${params.roomId}:mids`, start, stop); + const mids = await getMessageIds(roomId, uid, start, stop); if (!mids.length) { return []; } + const indices = {}; mids.forEach((mid, index) => { indices[mid] = start + index; }); mids.reverse(); - const messageData = await Messaging.getMessagesData(mids, params.uid, params.roomId, isNew); - messageData.forEach((messageData) => { - messageData.index = indices[messageData.messageId.toString()]; - messageData.isOwner = messageData.fromuid === parseInt(params.uid, 10); - if (messageData.deleted && !messageData.isOwner) { - messageData.content = '[[modules:chat.message-deleted]]'; - messageData.cleanedContent = messageData.content; + const messageData = await Messaging.getMessagesData(mids, uid, roomId, isNew); + messageData.forEach((msg) => { + msg.index = indices[msg.messageId.toString()]; + msg.isOwner = msg.fromuid === parseInt(uid, 10); + if (msg.deleted && !msg.isOwner) { + msg.content = `

        [[modules:chat.message-deleted]]

        `; } }); return messageData; }; +async function getMessageIds(roomId, uid, start, stop) { + const isPublic = await db.getObjectField(`chat:room:${roomId}`, 'public'); + if (parseInt(isPublic, 10) === 1) { + return await db.getSortedSetRevRange( + `chat:room:${roomId}:mids`, start, stop, + ); + } + const userjoinTimestamp = await db.sortedSetScore(`chat:room:${roomId}:uids`, uid); + return await db.getSortedSetRevRangeByScore( + `chat:room:${roomId}:mids`, start, stop - start + 1, '+inf', userjoinTimestamp + ); +} + async function canGet(hook, callerUid, uid) { const data = await plugins.hooks.fire(hook, { callerUid: callerUid, @@ -85,7 +99,7 @@ Messaging.parse = async (message, fromuid, uid, roomId, isNew) => { }; Messaging.isNewSet = async (uid, roomId, timestamp) => { - const setKey = `uid:${uid}:chat:room:${roomId}:mids`; + const setKey = `chat:room:${roomId}:mids`; const messages = await db.getSortedSetRevRangeWithScores(setKey, 0, 0); if (messages && messages.length) { return parseInt(timestamp, 10) > parseInt(messages[0].score, 10) + Messaging.newMessageCutoff; @@ -93,6 +107,53 @@ Messaging.isNewSet = async (uid, roomId, timestamp) => { return true; }; +Messaging.getPublicRoomIdsFromSet = async function (set) { + const cacheKey = `${set}:all`; + let allRoomIds = cache.get(cacheKey); + if (allRoomIds === undefined) { + allRoomIds = await db.getSortedSetRange(set, 0, -1); + cache.set(cacheKey, allRoomIds); + } + return allRoomIds.slice(); +}; + +Messaging.getPublicRooms = async (callerUid, uid) => { + const ok = await canGet('filter:messaging.canGetPublicChats', callerUid, uid); + if (!ok) { + return null; + } + + const allRoomIds = await Messaging.getPublicRoomIdsFromSet('chat:rooms:public:order'); + const allRoomData = await Messaging.getRoomsData(allRoomIds); + const checks = await Promise.all( + allRoomData.map(room => groups.isMemberOfAny(uid, room && room.groups)) + ); + const roomData = allRoomData.filter((room, idx) => room && checks[idx]); + const roomIds = roomData.map(r => r.roomId); + const userReadTimestamps = await db.getObjectFields( + `uid:${uid}:chat:rooms:read`, + roomIds, + ); + + const maxUnread = 50; + const unreadCounts = await Promise.all(roomIds.map(async (roomId) => { + const cutoff = userReadTimestamps[roomId] || '-inf'; + const unreadMids = await db.getSortedSetRangeByScore( + `chat:room:${roomId}:mids`, 0, maxUnread + 1, cutoff, '+inf' + ); + return unreadMids.length; + })); + + roomData.forEach((r, idx) => { + const count = unreadCounts[idx]; + r.unreadCountText = count > maxUnread ? `${maxUnread}+` : String(count); + r.unreadCount = count; + r.unread = count > 0; + }); + + return roomData; +}; + Messaging.getRecentChats = async (callerUid, uid, start, stop) => { const ok = await canGet('filter:messaging.canGetRecentChats', callerUid, uid); if (!ok) { @@ -100,15 +161,29 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { } const roomIds = await db.getSortedSetRevRange(`uid:${uid}:chat:rooms`, start, stop); + + async function getUsers(roomIds) { + const arrayOfUids = await Promise.all( + roomIds.map(roomId => Messaging.getUidsInRoom(roomId, 0, 9)) + ); + const uniqUids = _.uniq(_.flatten(arrayOfUids)).filter( + _uid => _uid && parseInt(_uid, 10) !== parseInt(uid, 10) + ); + const uidToUser = _.zipObject( + uniqUids, + await user.getUsersFields(uniqUids, [ + 'uid', 'username', 'userslug', 'picture', 'status', 'lastonline', + ]) + ); + return arrayOfUids.map(uids => uids.map(uid => uidToUser[uid])); + } + const results = await utils.promiseParallel({ roomData: Messaging.getRoomsData(roomIds), unread: db.isSortedSetMembers(`uid:${uid}:chat:rooms:unread`, roomIds), - users: Promise.all(roomIds.map(async (roomId) => { - let uids = await db.getSortedSetRevRange(`chat:room:${roomId}:uids`, 0, 9); - uids = uids.filter(_uid => _uid && parseInt(_uid, 10) !== parseInt(uid, 10)); - return await user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline']); - })), - teasers: Promise.all(roomIds.map(async roomId => Messaging.getTeaser(uid, roomId))), + users: getUsers(roomIds), + teasers: Messaging.getTeasers(uid, roomIds), + settings: user.getSettings(uid), }); await Promise.all(results.roomData.map(async (room, index) => { @@ -126,7 +201,7 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { room.users = room.users.filter(user => user && parseInt(user.uid, 10)); room.lastUser = room.users[0]; room.usernames = Messaging.generateUsernames(room.users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(room.users, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room.users, uid, results.settings.userLang); } })); @@ -153,8 +228,8 @@ Messaging.generateUsernames = function (users, excludeUid) { return usernames.join(', '); }; -Messaging.generateChatWithMessage = async function (users, excludeUid) { - users = users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); +Messaging.generateChatWithMessage = async function (users, callerUid, userLang) { + users = users.filter(u => u && parseInt(u.uid, 10) !== callerUid); const usernames = users.map(u => `${u.username}`); let compiled = ''; if (!users.length) { @@ -172,31 +247,48 @@ Messaging.generateChatWithMessage = async function (users, excludeUid) { usernames.join(', '), ); } - return utils.decodeHTMLEntities(await translator.translate(compiled)); + return utils.decodeHTMLEntities(await translator.translate(compiled, userLang)); }; Messaging.getTeaser = async (uid, roomId) => { - const mid = await Messaging.getLatestUndeletedMessage(uid, roomId); - if (!mid) { - return null; - } - const teaser = await Messaging.getMessageFields(mid, ['fromuid', 'content', 'timestamp']); - if (!teaser.fromuid) { - return null; - } - const blocked = await user.blocks.is(teaser.fromuid, uid); - if (blocked) { - return null; - } + const teasers = await Messaging.getTeasers(uid, [roomId]); + return teasers[0]; +}; - teaser.user = await user.getUserFields(teaser.fromuid, ['uid', 'username', 'userslug', 'picture', 'status', 'lastonline']); - if (teaser.content) { - teaser.content = utils.stripHTMLTags(utils.decodeHTMLEntities(teaser.content)); - teaser.content = validator.escape(String(teaser.content)); - } +Messaging.getTeasers = async (uid, roomIds) => { + const mids = await Promise.all( + roomIds.map(roomId => Messaging.getLatestUndeletedMessage(uid, roomId)) + ); + const [teasers, blockedUids] = await Promise.all([ + Messaging.getMessagesFields(mids, ['fromuid', 'content', 'timestamp']), + user.blocks.list(uid), + ]); + const uids = _.uniq( + teasers.map(t => t && t.fromuid).filter(uid => uid && !blockedUids.includes(uid)) + ); - const payload = await plugins.hooks.fire('filter:messaging.getTeaser', { teaser: teaser }); - return payload.teaser; + const userMap = _.zipObject( + uids, + await user.getUsersFields(uids, [ + 'uid', 'username', 'userslug', 'picture', 'status', 'lastonline', + ]) + ); + + return await Promise.all(roomIds.map(async (roomId, idx) => { + const teaser = teasers[idx]; + if (!teaser || !teaser.fromuid) { + return null; + } + if (userMap[teaser.fromuid]) { + teaser.user = userMap[teaser.fromuid]; + } + teaser.content = validator.escape( + String(utils.stripHTMLTags(utils.decodeHTMLEntities(teaser.content))) + ); + teaser.roomId = roomId; + const payload = await plugins.hooks.fire('filter:messaging.getTeaser', { teaser: teaser }); + return payload.teaser; + })); }; Messaging.getLatestUndeletedMessage = async (uid, roomId) => { @@ -207,7 +299,7 @@ Messaging.getLatestUndeletedMessage = async (uid, roomId) => { while (!done) { /* eslint-disable no-await-in-loop */ - mids = await db.getSortedSetRevRange(`uid:${uid}:chat:room:${roomId}:mids`, index, index); + mids = await getMessageIds(roomId, uid, index, index); if (mids.length) { const states = await Messaging.getMessageFields(mids[0], ['deleted', 'system']); done = !states.deleted && !states.system; @@ -337,8 +429,16 @@ Messaging.canViewMessage = async (mids, roomId, uid) => { mids = [mids]; single = true; } + const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; + const [midTimestamps, userTimestamp] = await Promise.all([ + db.sortedSetScores(`chat:room:${roomId}:mids`, mids), + db.sortedSetScore(`chat:room:${roomId}:uids`, uid), + ]); + + const canView = midTimestamps.map( + midTimestamp => !!(midTimestamp && userTimestamp && (isPublic || userTimestamp <= midTimestamp)) + ); - const canView = await db.isSortedSetMembers(`uid:${uid}:chat:room:${roomId}:mids`, mids); return single ? canView.pop() : canView; }; diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 6913c2d415..73cefdde92 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -2,39 +2,46 @@ const winston = require('winston'); -const user = require('../user'); +const batch = require('../batch'); +const db = require('../database'); const notifications = require('../notifications'); -const sockets = require('../socket.io'); +const io = require('../socket.io'); const plugins = require('../plugins'); const meta = require('../meta'); module.exports = function (Messaging) { - Messaging.notifyQueue = {}; // Only used to notify a user of a new chat message, see Messaging.notifyUser - + // Only used to notify a user of a new chat message + Messaging.notifyQueue = {}; Messaging.notifyUsersInRoom = async (fromUid, roomId, messageObj) => { - let uids = await Messaging.getUidsInRoom(roomId, 0, -1); - uids = await user.blocks.filterUids(fromUid, uids); + const isPublic = parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; let data = { roomId: roomId, fromUid: fromUid, message: messageObj, - uids: uids, + public: isPublic, }; data = await plugins.hooks.fire('filter:messaging.notify', data); - if (!data || !data.uids || !data.uids.length) { + if (!data) { return; } - uids = data.uids; - uids.forEach((uid) => { - data.self = parseInt(uid, 10) === parseInt(fromUid, 10) ? 1 : 0; - Messaging.pushUnreadCount(uid); - sockets.in(`uid_${uid}`).emit('event:chats.receive', data); - }); - if (messageObj.system) { + // delivers full message to all online users in roomId + io.in(`chat_room_${roomId}`).emit('event:chats.receive', data); + + const unreadData = { roomId, fromUid, public: isPublic }; + if (isPublic && !messageObj.system) { + // delivers unread public msg to all online users on the chats page + io.in(`chat_room_public_${roomId}`).emit('event:chats.public.unread', unreadData); + } + if (messageObj.system || isPublic) { return; } + + // push unread count only for private rooms + const uids = await Messaging.getAllUidsInRoom(roomId); + Messaging.pushUnreadCount(uids, unreadData); + // Delayed notifications let queueObj = Messaging.notifyQueue[`${fromUid}:${roomId}`]; if (queueObj) { @@ -49,35 +56,35 @@ module.exports = function (Messaging) { queueObj.timeout = setTimeout(async () => { try { - await sendNotifications(fromUid, uids, roomId, queueObj.message); + await sendNotification(fromUid, roomId, queueObj.message); + delete Messaging.notifyQueue[`${fromUid}:${roomId}`]; } catch (err) { winston.error(`[messaging/notifications] Unabled to send notification\n${err.stack}`); } }, meta.config.notificationSendDelay * 1000); }; - async function sendNotifications(fromuid, uids, roomId, messageObj) { - const hasRead = await Messaging.hasRead(uids, roomId); - uids = uids.filter((uid, index) => !hasRead[index] && parseInt(fromuid, 10) !== parseInt(uid, 10)); - if (!uids.length) { - delete Messaging.notifyQueue[`${fromuid}:${roomId}`]; - return; - } - + async function sendNotification(fromUid, roomId, messageObj) { const { displayname } = messageObj.fromUser; - const isGroupChat = await Messaging.isGroupChat(roomId); const notification = await notifications.create({ type: isGroupChat ? 'new-group-chat' : 'new-chat', subject: `[[email:notif.chat.subject, ${displayname}]]`, bodyShort: `[[notifications:new_message_from, ${displayname}]]`, bodyLong: messageObj.content, - nid: `chat_${fromuid}_${roomId}`, - from: fromuid, + nid: `chat_${fromUid}_${roomId}`, + from: fromUid, path: `/chats/${messageObj.roomId}`, }); - delete Messaging.notifyQueue[`${fromuid}:${roomId}`]; - notifications.push(notification, uids); + await batch.processSortedSet(`chat:room:${roomId}:uids`, async (uids) => { + const hasRead = await Messaging.hasRead(uids, roomId); + uids = uids.filter((uid, index) => !hasRead[index] && parseInt(fromUid, 10) !== parseInt(uid, 10)); + + notifications.push(notification, uids); + }, { + batch: 500, + interval: 1000, + }); } }; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 49646d394a..54edfe3150 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -1,68 +1,185 @@ 'use strict'; +const _ = require('lodash'); const validator = require('validator'); +const winston = require('winston'); const db = require('../database'); const user = require('../user'); +const groups = require('../groups'); const plugins = require('../plugins'); const privileges = require('../privileges'); const meta = require('../meta'); +const cacheCreate = require('../cacheCreate'); + +const cache = cacheCreate({ + name: 'chat:room:uids', + max: 500, + ttl: 0, +}); + +const intFields = [ + 'roomId', 'timestamp', 'userCount', +]; module.exports = function (Messaging) { - Messaging.getRoomData = async (roomId) => { - const data = await db.getObject(`chat:room:${roomId}`); + Messaging.getRoomData = async (roomId, fields = []) => { + const data = await db.getObject(`chat:room:${roomId}`, fields); if (!data) { throw new Error('[[error:no-chat-room]]'); } - modifyRoomData([data]); + modifyRoomData([data], fields); return data; }; - Messaging.getRoomsData = async (roomIds) => { - const roomData = await db.getObjects(roomIds.map(roomId => `chat:room:${roomId}`)); - modifyRoomData(roomData); + Messaging.getRoomsData = async (roomIds, fields = []) => { + const roomData = await db.getObjects( + roomIds.map(roomId => `chat:room:${roomId}`), + fields + ); + modifyRoomData(roomData, fields); return roomData; }; - function modifyRoomData(rooms) { + function modifyRoomData(rooms, fields) { rooms.forEach((data) => { if (data) { - data.roomName = data.roomName || ''; - data.roomName = validator.escape(String(data.roomName)); + db.parseIntFields(data, intFields, fields); + data.roomName = validator.escape(String(data.roomName || '')); + data.public = parseInt(data.public, 10) === 1; if (data.hasOwnProperty('groupChat')) { data.groupChat = parseInt(data.groupChat, 10) === 1; } + + if (data.hasOwnProperty('groups')) { + try { + data.groups = JSON.parse(data.groups); + } catch (err) { + winston.error(err.stack); + data.groups = []; + } + } } }); } - Messaging.newRoom = async (uid, toUids) => { + Messaging.newRoom = async (uid, data) => { + // backwards compat. remove in 4.x + if (Array.isArray(data)) { // old usage second param used to be toUids + data = { uids: data }; + } const now = Date.now(); const roomId = await db.incrObjectField('global', 'nextChatRoomId'); const room = { owner: uid, roomId: roomId, + timestamp: now, }; + if (data.hasOwnProperty('roomName') && data.roomName) { + room.roomName = String(data.roomName); + } + if (Array.isArray(data.groups) && data.groups.length) { + room.groups = JSON.stringify(data.groups); + } + const isPublic = data.type === 'public'; + if (isPublic) { + room.public = 1; + } + await Promise.all([ db.setObject(`chat:room:${roomId}`, room), + db.sortedSetAdd('chat:rooms', now, roomId), db.sortedSetAdd(`chat:room:${roomId}:uids`, now, uid), ]); + await Promise.all([ - Messaging.addUsersToRoom(uid, toUids, roomId), - Messaging.addRoomToUsers(roomId, [uid].concat(toUids), now), + Messaging.addUsersToRoom(uid, data.uids, roomId), + isPublic ? + db.sortedSetAddBulk([ + ['chat:rooms:public', now, roomId], + ['chat:rooms:public:order', roomId, roomId], + ]) : + Messaging.addRoomToUsers(roomId, [uid].concat(data.uids), now), ]); - // chat owner should also get the user-join system message - await Messaging.addSystemMessage('user-join', uid, roomId); + + if (!isPublic) { + // chat owner should also get the user-join system message + await Messaging.addSystemMessage('user-join', uid, roomId); + } return roomId; }; - Messaging.isUserInRoom = async (uid, roomId) => { - const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid); - const data = await plugins.hooks.fire('filter:messaging.isUserInRoom', { uid: uid, roomId: roomId, inRoom: inRoom }); - return data.inRoom; + Messaging.deleteRooms = async (roomIds) => { + if (!roomIds) { + throw new Error('[[error:invalid-data]]'); + } + + if (!Array.isArray(roomIds)) { + roomIds = [roomIds]; + } + + await Promise.all(roomIds.map(async (roomId) => { + const uids = await db.getSortedSetMembers(`chat:room:${roomId}:uids`); + const keys = uids + .map(uid => `uid:${uid}:chat:rooms`) + .concat(uids.map(uid => `uid:${uid}:chat:rooms:unread`)); + + await Promise.all([ + db.sortedSetRemove(`chat:room:${roomId}:uids`, uids), + db.sortedSetsRemove(keys, roomId), + ]); + })); + await Promise.all([ + db.deleteAll(roomIds.map(id => `chat:room:${id}`)), + db.sortedSetRemove('chat:rooms', roomIds), + db.sortedSetRemove('chat:rooms:public', roomIds), + ]); + }; + + Messaging.isUserInRoom = async (uid, roomIds) => { + let single = false; + if (!Array.isArray(roomIds)) { + roomIds = [roomIds]; + single = true; + } + const inRooms = await db.isMemberOfSortedSets( + roomIds.map(id => `chat:room:${id}:uids`), + uid + ); + + const data = await Promise.all(roomIds.map(async (roomId, idx) => { + const data = await plugins.hooks.fire('filter:messaging.isUserInRoom', { + uid: uid, + roomId: roomId, + inRoom: inRooms[idx], + }); + return data.inRoom; + })); + return single ? data.pop() : data; + }; + + Messaging.isUsersInRoom = async (uids, roomId) => { + let single = false; + if (!Array.isArray(uids)) { + uids = [uids]; + single = true; + } + + const inRooms = await db.isSortedSetMembers( + `chat:room:${roomId}:uids`, + uids, + ); + + const data = await plugins.hooks.fire('filter:messaging.isUsersInRoom', { + uids: uids, + roomId: roomId, + inRooms: inRooms, + }); + + return single ? data.inRooms.pop() : data.inRooms; }; Messaging.roomExists = async roomId => db.exists(`chat:room:${roomId}:uids`); @@ -84,7 +201,12 @@ module.exports = function (Messaging) { return isArray ? result : result[0]; }; + Messaging.isRoomPublic = async function (roomId) { + return parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; + }; + Messaging.addUsersToRoom = async function (uid, uids, roomId) { + uids = _.uniq(uids); const inRoom = await Messaging.isUserInRoom(uid, roomId); const payload = await plugins.hooks.fire('filter:messaging.addUsersToRoom', { uid, uids, roomId, inRoom }); @@ -92,13 +214,17 @@ module.exports = function (Messaging) { throw new Error('[[error:cant-add-users-to-chat-room]]'); } - const now = Date.now(); - const timestamps = payload.uids.map(() => now); - await db.sortedSetAdd(`chat:room:${payload.roomId}:uids`, timestamps, payload.uids); - await updateGroupChatField([payload.roomId]); - await Promise.all(payload.uids.map(uid => Messaging.addSystemMessage('user-join', uid, payload.roomId))); + await addUidsToRoom(payload.uids, roomId); }; + async function addUidsToRoom(uids, roomId) { + const now = Date.now(); + const timestamps = uids.map(() => now); + await db.sortedSetAdd(`chat:room:${roomId}:uids`, timestamps, uids); + await updateUserCount([roomId]); + await Promise.all(uids.map(uid => Messaging.addSystemMessage('user-join', uid, roomId))); + } + Messaging.removeUsersFromRoom = async (uid, uids, roomId) => { const [isOwner, userCount] = await Promise.all([ Messaging.isRoomOwner(uid, roomId), @@ -117,14 +243,16 @@ module.exports = function (Messaging) { return (await Messaging.getRoomData(roomId)).groupChat; }; - async function updateGroupChatField(roomIds) { + async function updateUserCount(roomIds) { const userCounts = await db.sortedSetsCard(roomIds.map(roomId => `chat:room:${roomId}:uids`)); + const countMap = _.zipObject(roomIds, userCounts); const groupChats = roomIds.filter((roomId, index) => userCounts[index] > 2); const privateChats = roomIds.filter((roomId, index) => userCounts[index] <= 2); await db.setObjectBulk([ - ...groupChats.map(id => [`chat:room:${id}`, { groupChat: 1 }]), - ...privateChats.map(id => [`chat:room:${id}`, { groupChat: 0 }]), + ...groupChats.map(id => [`chat:room:${id}`, { groupChat: 1, userCount: countMap[id] }]), + ...privateChats.map(id => [`chat:room:${id}`, { groupChat: 0, userCount: countMap[id] }]), ]); + cache.del(roomIds.map(id => `chat:room:${id}:users`)); } Messaging.leaveRoom = async (uids, roomId) => { @@ -142,7 +270,7 @@ module.exports = function (Messaging) { await Promise.all(uids.map(uid => Messaging.addSystemMessage('user-leave', uid, roomId))); await updateOwner(roomId); - await updateGroupChatField([roomId]); + await updateUserCount([roomId]); }; Messaging.leaveRooms = async (uid, roomIds) => { @@ -162,7 +290,7 @@ module.exports = function (Messaging) { roomIds.map(roomId => updateOwner(roomId)) .concat(roomIds.map(roomId => Messaging.addSystemMessage('user-leave', uid, roomId))) ); - await updateGroupChatField(roomIds); + await updateUserCount(roomIds); }; async function updateOwner(roomId) { @@ -171,7 +299,18 @@ module.exports = function (Messaging) { await db.setObjectField(`chat:room:${roomId}`, 'owner', newOwner); } - Messaging.getUidsInRoom = async (roomId, start, stop) => db.getSortedSetRevRange(`chat:room:${roomId}:uids`, start, stop); + Messaging.getAllUidsInRoom = async function (roomId) { + const cacheKey = `chat:room:${roomId}:users`; + let uids = cache.get(cacheKey); + if (uids !== undefined) { + return uids; + } + uids = await Messaging.getUidsInRoom(roomId, 0, -1); + cache.set(cacheKey, uids); + return uids; + }; + + Messaging.getUidsInRoom = async (roomId, start, stop) => db.getSortedSetRange(`chat:room:${roomId}:uids`, start, stop); Messaging.getUsersInRoom = async (roomId, start, stop) => { const uids = await Messaging.getUidsInRoom(roomId, start, stop); @@ -181,6 +320,7 @@ module.exports = function (Messaging) { ]); return users.map((user, index) => { + user.index = start + index; user.isOwner = isOwners[index]; return user; }); @@ -221,40 +361,55 @@ module.exports = function (Messaging) { }; Messaging.loadRoom = async (uid, data) => { - const canChat = await privileges.global.can('chat', uid); + const { roomId } = data; + const [room, inRoom, canChat] = await Promise.all([ + Messaging.getRoomData(roomId), + Messaging.isUserInRoom(uid, roomId), + privileges.global.can('chat', uid), + ]); + if (!canChat) { throw new Error('[[error:no-privileges]]'); } - const inRoom = await Messaging.isUserInRoom(uid, data.roomId); - if (!inRoom) { + if (!room || + (!room.public && !inRoom) || + (room.public && !(await groups.isMemberOfAny(uid, room.groups))) + ) { return null; } - const [room, canReply, users, messages, isAdminOrGlobalMod, isOwner] = await Promise.all([ - Messaging.getRoomData(data.roomId), - Messaging.canReply(data.roomId, uid), - Messaging.getUsersInRoom(data.roomId, 0, -1), + // add user to public room onload + if (room.public && !inRoom) { + await addUidsToRoom([uid], roomId); + } + + const [canReply, users, messages, isAdmin, isGlobalMod, settings, isOwner] = await Promise.all([ + Messaging.canReply(roomId, uid), + Messaging.getUsersInRoom(roomId, 0, 39), Messaging.getMessages({ callerUid: uid, uid: data.uid || uid, - roomId: data.roomId, + roomId: roomId, isNew: false, }), - user.isAdminOrGlobalMod(uid), - Messaging.isRoomOwner(uid, data.roomId), + user.isAdministrator(uid), + user.isGlobalModerator(uid), + user.getSettings(uid), + Messaging.isRoomOwner(uid, roomId), ]); room.messages = messages; room.isOwner = isOwner; - room.users = users.filter(user => user && parseInt(user.uid, 10) && parseInt(user.uid, 10) !== parseInt(uid, 10)); + room.users = users; room.canReply = canReply; room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : users.length > 2; room.usernames = Messaging.generateUsernames(users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(users, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(users, uid, settings.userLang); room.maximumUsersInChatRoom = meta.config.maximumUsersInChatRoom; room.maximumChatMessageLength = meta.config.maximumChatMessageLength; room.showUserInput = !room.maximumUsersInChatRoom || room.maximumUsersInChatRoom > 2; - room.isAdminOrGlobalMod = isAdminOrGlobalMod; + room.isAdminOrGlobalMod = isAdmin || isGlobalMod; + room.isAdmin = isAdmin; const payload = await plugins.hooks.fire('filter:messaging.loadRoom', { uid, data, room }); return payload.room; diff --git a/src/messaging/unread.js b/src/messaging/unread.js index 3a31595070..8b98ec279d 100644 --- a/src/messaging/unread.js +++ b/src/messaging/unread.js @@ -1,27 +1,35 @@ 'use strict'; const db = require('../database'); -const sockets = require('../socket.io'); +const io = require('../socket.io'); module.exports = function (Messaging) { Messaging.getUnreadCount = async (uid) => { - if (parseInt(uid, 10) <= 0) { + if (!(parseInt(uid, 10) > 0)) { return 0; } return await db.sortedSetCard(`uid:${uid}:chat:rooms:unread`); }; - Messaging.pushUnreadCount = async (uid) => { - if (parseInt(uid, 10) <= 0) { + Messaging.pushUnreadCount = async (uids, data = null) => { + if (!Array.isArray(uids)) { + uids = [uids]; + } + uids = uids.filter(uid => parseInt(uid, 10) > 0); + if (!uids.length) { return; } - const unreadCount = await Messaging.getUnreadCount(uid); - sockets.in(`uid_${uid}`).emit('event:unread.updateChatCount', unreadCount); + uids.forEach((uid) => { + io.in(`uid_${uid}`).emit('event:unread.updateChatCount', data); + }); }; Messaging.markRead = async (uid, roomId) => { - await db.sortedSetRemove(`uid:${uid}:chat:rooms:unread`, roomId); + await Promise.all([ + db.sortedSetRemove(`uid:${uid}:chat:rooms:unread`, roomId), + db.setObjectField(`uid:${uid}:chat:rooms:read`, roomId, Date.now()), + ]); }; Messaging.hasRead = async (uids, roomId) => { @@ -42,6 +50,6 @@ module.exports = function (Messaging) { return; } const keys = uids.map(uid => `uid:${uid}:chat:rooms:unread`); - return await db.sortedSetsAdd(keys, Date.now(), roomId); + await db.sortedSetsAdd(keys, Date.now(), roomId); }; }; diff --git a/src/middleware/assert.js b/src/middleware/assert.js index f91fde93f4..553114f870 100644 --- a/src/middleware/assert.js +++ b/src/middleware/assert.js @@ -113,8 +113,8 @@ Assert.room = helpers.try(async (req, res, next) => { } const [exists, inRoom] = await Promise.all([ - await messaging.roomExists(req.params.roomId), - await messaging.isUserInRoom(req.uid, req.params.roomId), + messaging.roomExists(req.params.roomId), + messaging.isUserInRoom(req.uid, req.params.roomId), ]); if (!exists) { diff --git a/src/middleware/render.js b/src/middleware/render.js index 71673b3052..ac7121d6f8 100644 --- a/src/middleware/render.js +++ b/src/middleware/render.js @@ -169,6 +169,7 @@ module.exports = function (middleware) { isGlobalMod: user.isGlobalModerator(req.uid), isModerator: user.isModeratorOfAnyCategory(req.uid), privileges: privileges.global.get(req.uid), + blocks: user.blocks.list(req.uid), user: user.getUserData(req.uid), isEmailConfirmSent: req.uid <= 0 ? false : await user.email.isValidationPending(req.uid), languageDirection: translator.translate('[[language:dir]]', res.locals.config.userLang), @@ -190,6 +191,7 @@ module.exports = function (middleware) { results.user.isGlobalMod = results.isGlobalMod; results.user.isMod = !!results.isModerator; results.user.privileges = results.privileges; + results.user.blocks = results.blocks; results.user.timeagoCode = results.timeagoCode; results.user[results.user.status] = true; results.user.lastRoomId = results.roomIds.length ? results.roomIds[0] : null; diff --git a/src/routes/write/admin.js b/src/routes/write/admin.js index 2571b8dd01..593e9ce123 100644 --- a/src/routes/write/admin.js +++ b/src/routes/write/admin.js @@ -15,6 +15,8 @@ module.exports = function () { setupApiRoute(router, 'get', '/analytics', [...middlewares], controllers.write.admin.getAnalyticsKeys); setupApiRoute(router, 'get', '/analytics/:set', [...middlewares], controllers.write.admin.getAnalyticsData); + setupApiRoute(router, 'delete', '/chats/:roomId', [...middlewares, middleware.assert.room], controllers.write.admin.chats.deleteRoom); + setupApiRoute(router, 'post', '/tokens', [...middlewares], controllers.write.admin.generateToken); setupApiRoute(router, 'get', '/tokens/:token', [...middlewares], controllers.write.admin.getToken); setupApiRoute(router, 'put', '/tokens/:token', [...middlewares], controllers.write.admin.updateToken); diff --git a/src/routes/write/chats.js b/src/routes/write/chats.js index a92db701f7..3334cb377f 100644 --- a/src/routes/write/chats.js +++ b/src/routes/write/chats.js @@ -16,8 +16,7 @@ module.exports = function () { setupApiRoute(router, 'head', '/:roomId', [...middlewares, middleware.assert.room], controllers.write.chats.exists); setupApiRoute(router, 'get', '/:roomId', [...middlewares, middleware.assert.room], controllers.write.chats.get); setupApiRoute(router, 'post', '/:roomId', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['message'])], controllers.write.chats.post); - setupApiRoute(router, 'put', '/:roomId', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['name'])], controllers.write.chats.rename); - // no route for room deletion, noted here just in case... + setupApiRoute(router, 'put', '/:roomId', [...middlewares, middleware.assert.room], controllers.write.chats.update); setupApiRoute(router, 'put', '/:roomId/state', [...middlewares, middleware.assert.room], controllers.write.chats.mark); setupApiRoute(router, 'delete', '/:roomId/state', [...middlewares, middleware.assert.room], controllers.write.chats.mark); diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index f34f9b2c13..c426d0c7d6 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -20,7 +20,6 @@ SocketRooms.getAll = async function () { totals.onlineGuestCount = 0; totals.onlineRegisteredCount = 0; totals.socketCount = sockets.length; - totals.topics = {}; totals.topTenTopics = []; totals.users = { categories: 0, diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 969a0c07e8..d34eec366e 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -65,6 +65,17 @@ SocketGroups.loadMoreMembers = async (socket, data) => { }; }; +SocketGroups.getChatGroups = async (socket) => { + const isAdmin = await user.isAdministrator(socket.uid); + if (!isAdmin) { + throw new Error('[[error:no-privileges]]'); + } + const allGroups = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1); + const groupsList = allGroups.filter(g => !groups.ephemeralGroups.includes(g.name)); + groupsList.sort((a, b) => b.system - a.system); + return groupsList.map(g => ({ name: g.name, displayName: g.displayName })); +}; + async function canSearchMembers(uid, groupName) { const [isHidden, isMember, hasAdminPrivilege, isGlobalMod, viewGroups] = await Promise.all([ groups.isHidden(groupName), diff --git a/src/socket.io/meta.js b/src/socket.io/meta.js index 68230bd6f0..e62ae0e356 100644 --- a/src/socket.io/meta.js +++ b/src/socket.io/meta.js @@ -4,9 +4,8 @@ const user = require('../user'); const topics = require('../topics'); -const SocketMeta = { - rooms: {}, -}; +const SocketMeta = module.exports; +SocketMeta.rooms = {}; SocketMeta.reconnected = function (socket, data, callback) { callback = callback || function () {}; @@ -19,13 +18,13 @@ SocketMeta.reconnected = function (socket, data, callback) { /* Rooms */ -SocketMeta.rooms.enter = function (socket, data, callback) { +SocketMeta.rooms.enter = async function (socket, data) { if (!socket.uid) { - return callback(); + return; } if (!data) { - return callback(new Error('[[error:invalid-data]]')); + throw new Error('[[error:invalid-data]]'); } if (data.enter) { @@ -33,7 +32,11 @@ SocketMeta.rooms.enter = function (socket, data, callback) { } if (data.enter && data.enter.startsWith('uid_') && data.enter !== `uid_${socket.uid}`) { - return callback(new Error('[[error:not-allowed]]')); + throw new Error('[[error:not-allowed]]'); + } + + if (data.enter && data.enter.startsWith('chat_')) { + throw new Error('[[error:not-allowed]]'); } leaveCurrentRoom(socket); @@ -42,15 +45,13 @@ SocketMeta.rooms.enter = function (socket, data, callback) { socket.join(data.enter); socket.currentRoom = data.enter; } - callback(); }; -SocketMeta.rooms.leaveCurrent = function (socket, data, callback) { +SocketMeta.rooms.leaveCurrent = async function (socket) { if (!socket.uid || !socket.currentRoom) { - return callback(); + return; } leaveCurrentRoom(socket); - callback(); }; function leaveCurrentRoom(socket) { @@ -60,4 +61,4 @@ function leaveCurrentRoom(socket) { } } -module.exports = SocketMeta; +require('../promisify')(SocketMeta); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 679a2516ec..f98b7052a8 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -1,5 +1,7 @@ 'use strict'; +const _ = require('lodash'); + const db = require('../database'); const Messaging = require('../messaging'); const utils = require('../utils'); @@ -18,13 +20,13 @@ SocketModules.chats.getRaw = async function (socket, data) { throw new Error('[[error:invalid-data]]'); } const roomId = await Messaging.getMessageField(data.mid, 'roomId'); - const [isAdmin, hasMessage, inRoom] = await Promise.all([ + const [isAdmin, canViewMessage, inRoom] = await Promise.all([ user.isAdministrator(socket.uid), - db.isSortedSetMember(`uid:${socket.uid}:chat:room:${roomId}:mids`, data.mid), + Messaging.canViewMessage(data.mid, roomId, socket.uid), Messaging.isUserInRoom(socket.uid, roomId), ]); - if (!isAdmin && (!inRoom || !hasMessage)) { + if (!isAdmin && (!inRoom || !canViewMessage)) { throw new Error('[[error:not-allowed]]'); } @@ -70,4 +72,107 @@ SocketModules.chats.getIP = async function (socket, mid) { return await Messaging.getMessageField(mid, 'ip'); }; +SocketModules.chats.getUnreadCount = async function (socket) { + return await Messaging.getUnreadCount(socket.uid); +}; + +SocketModules.chats.enter = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'join'); +}; + +SocketModules.chats.leave = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'leave'); +}; + +SocketModules.chats.enterPublic = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'join', 'chat_room_public'); +}; + +SocketModules.chats.leavePublic = async function (socket, roomIds) { + await joinLeave(socket, roomIds, 'leave', 'chat_room_public'); +}; + +async function joinLeave(socket, roomIds, method, prefix = 'chat_room') { + if (!(socket.uid > 0)) { + throw new Error('[[error:not-allowed]]'); + } + if (!Array.isArray(roomIds)) { + roomIds = [roomIds]; + } + if (roomIds.length) { + const [isAdmin, inRooms, roomData] = await Promise.all([ + user.isAdministrator(socket.uid), + Messaging.isUserInRoom(socket.uid, roomIds), + Messaging.getRoomsData(roomIds, ['public', 'groups']), + ]); + + await Promise.all(roomIds.map(async (roomId, idx) => { + const isPublic = roomData[idx] && roomData[idx].public; + const groups = roomData[idx] && roomData[idx].groups; + if (isAdmin || (inRooms[idx] && (!isPublic || await groups.isMemberOfAny(socket.uid, groups)))) { + socket[method](`${prefix}_${roomId}`); + } + })); + } +} + +SocketModules.chats.sortPublicRooms = async function (socket, data) { + if (!data || !Array.isArray(data.scores) || !Array.isArray(data.roomIds)) { + throw new Error('[[error:invalid-data]]'); + } + const isAdmin = await user.isAdministrator(socket.uid); + if (!isAdmin) { + throw new Error('[[error:no-privileges]]'); + } + await db.sortedSetAdd(`chat:rooms:public:order`, data.scores, data.roomIds); +}; + +SocketModules.chats.searchMembers = async function (socket, data) { + if (!data || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + const [isAdmin, inRoom, isRoomOwner] = await Promise.all([ + user.isAdministrator(socket.uid), + Messaging.isUserInRoom(socket.uid, data.roomId), + Messaging.isRoomOwner(socket.uid, data.roomId), + ]); + + if (!isAdmin && !inRoom) { + throw new Error('[[error:no-privileges]]'); + } + + const results = await user.search({ + query: data.username, + paginate: false, + hardCap: -1, + }); + + const { users } = results; + const foundUids = users.map(user => user && user.uid); + const isUidInRoom = _.zipObject( + foundUids, + await Messaging.isUsersInRoom(foundUids, data.roomId) + ); + + const roomUsers = users.filter(user => isUidInRoom[user.uid]); + const isOwners = await Messaging.isRoomOwner(roomUsers.map(u => u.uid), data.roomId); + + roomUsers.forEach((user, index) => { + if (user) { + user.isOwner = isOwners[index]; + user.canKick = isRoomOwner && (parseInt(user.uid, 10) !== parseInt(socket.uid, 10)); + } + }); + + roomUsers.sort((a, b) => { + if (a.isOwner && !b.isOwner) { + return -1; + } else if (!a.isOwner && b.isOwner) { + return 1; + } + return 0; + }); + return { users: roomUsers }; +}; + require('../promisify')(SocketModules); diff --git a/src/upgrades/3.3.0/chat_room_refactor.js b/src/upgrades/3.3.0/chat_room_refactor.js new file mode 100644 index 0000000000..9b3337fc3c --- /dev/null +++ b/src/upgrades/3.3.0/chat_room_refactor.js @@ -0,0 +1,64 @@ +'use strict'; + + +const _ = require('lodash'); + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Update chat messages to add roomId field', + timestamp: Date.UTC(2023, 6, 2), + method: async function () { + const { progress } = this; + + const nextChatRoomId = await db.getObjectField('global', 'nextChatRoomId'); + const allRoomIds = []; + for (let i = 1; i <= nextChatRoomId; i++) { + allRoomIds.push(i); + } + progress.total = allRoomIds.length; + await batch.processArray(allRoomIds, async (roomIds) => { + progress.incr(roomIds.length); + await Promise.all(roomIds.map(async (roomId) => { + const [uids, roomData] = await Promise.all([ + db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, -1), + db.getObject(`chat:room:${roomId}`), + ]); + + if (!uids.length && !roomData) { + return; + } + if (roomData && roomData.owner && !uids.includes(String(roomData.owner))) { + uids.push(roomData.owner); + } + const userKeys = uids.map(uid => `uid:${uid}:chat:room:${roomId}:mids`); + const mids = await db.getSortedSetsMembers(userKeys); + const uniqMids = _.uniq(_.flatten(mids)); + let messageData = await db.getObjects(uniqMids.map(mid => `message:${mid}`)); + messageData.forEach((m, idx) => { + if (m) { + m.mid = parseInt(uniqMids[idx], 10); + } + }); + messageData = messageData.filter(Boolean); + + const bulkSet = messageData.map( + msg => [`message:${msg.mid}`, { roomId: roomId }] + ); + + await db.setObjectBulk(bulkSet); + await db.setObjectField(`chat:room:${roomId}`, 'userCount', uids.length); + await db.sortedSetAdd( + `chat:room:${roomId}:mids`, + messageData.map(m => m.timestamp), + messageData.map(m => m.mid), + ); + await db.deleteAll(userKeys); + })); + }, { + batch: 500, + }); + }, +}; diff --git a/src/upgrades/3.3.0/save_rooms_zset.js b/src/upgrades/3.3.0/save_rooms_zset.js new file mode 100644 index 0000000000..9c75362a50 --- /dev/null +++ b/src/upgrades/3.3.0/save_rooms_zset.js @@ -0,0 +1,42 @@ +'use strict'; + +const db = require('../../database'); +const batch = require('../../batch'); + +module.exports = { + name: 'Store list of chat rooms', + timestamp: Date.UTC(2023, 6, 3), + method: async function () { + const { progress } = this; + const lastRoomId = await db.getObjectField('global', 'nextChatRoomId'); + const allRoomIds = []; + for (let x = 1; x <= lastRoomId; x++) { + allRoomIds.push(x); + } + const users = await db.getSortedSetRangeWithScores(`users:joindate`, 0, 0); + const timestamp = users.length ? users[0].score : Date.now(); + progress.total = allRoomIds.length; + + await batch.processArray(allRoomIds, async (roomIds) => { + progress.incr(roomIds.length); + const keys = roomIds.map(id => `chat:room:${id}`); + const exists = await db.exists(keys); + roomIds = roomIds.filter((_, idx) => exists[idx]); + // get timestamp from uids, if no users use the timestamp of first user + const arrayOfUids = await Promise.all( + roomIds.map(roomId => db.getSortedSetRangeWithScores(`chat:room:${roomId}:uids`, 0, 0)) + ); + + const timestamps = roomIds.map( + (id, idx) => (arrayOfUids[idx].length ? (arrayOfUids[idx][0].score || timestamp) : timestamp) + ); + + await db.sortedSetAdd('chat:rooms', timestamps, roomIds); + await db.setObjectBulk( + roomIds.map((id, idx) => ([`chat:room:${id}`, { timestamp: timestamps[idx] }])) + ); + }, { + batch: 500, + }); + }, +}; diff --git a/src/user/delete.js b/src/user/delete.js index 4cc574c4ff..1362df1621 100644 --- a/src/user/delete.js +++ b/src/user/delete.js @@ -116,7 +116,9 @@ module.exports = function (User) { `user:${uid}:emails`, `uid:${uid}:topics`, `uid:${uid}:posts`, `uid:${uid}:chats`, `uid:${uid}:chats:unread`, - `uid:${uid}:chat:rooms`, `uid:${uid}:chat:rooms:unread`, + `uid:${uid}:chat:rooms`, + `uid:${uid}:chat:rooms:unread`, + `uid:${uid}:chat:rooms:read`, `uid:${uid}:upvote`, `uid:${uid}:downvote`, `uid:${uid}:flag:pids`, `uid:${uid}:sessions`, `uid:${uid}:sessionUUID:sessionId`, @@ -168,13 +170,10 @@ module.exports = function (User) { } async function deleteChats(uid) { - const roomIds = await db.getSortedSetRange(`uid:${uid}:chat:rooms`, 0, -1); - const userKeys = roomIds.map(roomId => `uid:${uid}:chat:room:${roomId}:mids`); - - await Promise.all([ - messaging.leaveRooms(uid, roomIds), - db.deleteAll(userKeys), - ]); + const roomIds = await db.getSortedSetRange([ + `uid:${uid}:chat:rooms`, `chat:rooms:public`, + ], 0, -1); + await messaging.leaveRooms(uid, roomIds); } async function deleteUserIps(uid) { diff --git a/src/user/jobs/export-profile.js b/src/user/jobs/export-profile.js index 49c18550ca..27177d112d 100644 --- a/src/user/jobs/export-profile.js +++ b/src/user/jobs/export-profile.js @@ -89,7 +89,7 @@ process.on('message', async (msg) => { async function getRoomMessages(uid, roomId) { const batch = require('../../batch'); let data = []; - await batch.processSortedSet(`uid:${uid}:chat:room:${roomId}:mids`, async (mids) => { + await batch.processSortedSet(`chat:room:${roomId}:mids`, async (mids) => { const messageData = await db.getObjects(mids.map(mid => `message:${mid}`)); data = data.concat( messageData diff --git a/src/views/modals/create-room.tpl b/src/views/modals/create-room.tpl new file mode 100644 index 0000000000..dcb470cd6e --- /dev/null +++ b/src/views/modals/create-room.tpl @@ -0,0 +1,45 @@ +
        +
        + + +
        +
        + + +
        + + {{{ if user.isAdmin }}} + + + + {{{ end }}} +
        \ No newline at end of file diff --git a/src/views/modals/manage-room.tpl b/src/views/modals/manage-room.tpl index de9ac4f331..ccb46f1a7d 100644 --- a/src/views/modals/manage-room.tpl +++ b/src/views/modals/manage-room.tpl @@ -1,11 +1,27 @@
        - + +

        [[modules:chat.add-user-help]]


        -
          + + +
          • [[modules:chat.retrieving-users]]
          + + {{{ if (user.isAdmin && group.public ) }}} + + + +
          + +
          + {{{ end }}}
        \ No newline at end of file diff --git a/src/views/partials/chats/manage-room-users.tpl b/src/views/partials/chats/manage-room-users.tpl index f8808587bd..0c7a0c5c0f 100644 --- a/src/views/partials/chats/manage-room-users.tpl +++ b/src/views/partials/chats/manage-room-users.tpl @@ -1,7 +1,12 @@ {{{ each users }}} -
      • - {{{ if ./canKick }}}{{{ end }}} - {buildAvatar(users, "24px", true)} - {../username} {{{ if ./isOwner }}}{{{ end }}} +
      • +
        + {buildAvatar(users, "24px", true)} + {./username}{{{ if ./isOwner }}} {{{ end }}} +
        + + {{{ if ./canKick }}} + + {{{ end }}}
      • {{{ end }}} \ No newline at end of file diff --git a/test/api.js b/test/api.js index 6eddd17f52..6723cd3f5e 100644 --- a/test/api.js +++ b/test/api.js @@ -281,7 +281,7 @@ describe('API', async () => { await flags.create('post', 2, unprivUid, 'sample reasons', Date.now()); // for testing flag notes (since flag 1 deleted) // Create a new chat room - await messaging.newRoom(1, [2]); + await messaging.newRoom(1, { uids: [2] }); // Create an empty file to test DELETE /files and thumb deletion fs.closeSync(fs.openSync(path.resolve(nconf.get('upload_path'), 'files/test.txt'), 'w')); diff --git a/test/database/sorted.js b/test/database/sorted.js index e77314689b..36d4534a91 100644 --- a/test/database/sorted.js +++ b/test/database/sorted.js @@ -64,6 +64,7 @@ describe('Sorted Set methods', () => { match: '*b{', limit: 2, }); + assert.strictEqual(data.length, 2); assert(data.includes('aaab{')); assert(data.includes('bbcb{')); }); @@ -73,8 +74,8 @@ describe('Sorted Set methods', () => { const data = await db.getSortedSetScan({ key: 'scanzset4', match: 'b*', - limit: 2, }); + assert.strictEqual(data.length, 2); assert(data.includes('bbbb')); assert(data.includes('bbcb')); }); @@ -85,7 +86,7 @@ describe('Sorted Set methods', () => { key: 'scanzset5', match: '*db', }); - assert.equal(data.length, 2); + assert.strictEqual(data.length, 2); assert(data.includes('ddb')); assert(data.includes('adb')); }); diff --git a/test/messaging.js b/test/messaging.js index 45ed034bc3..24bbebfc19 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -345,7 +345,7 @@ describe('Messaging Library', () => { assert(messageData.fromUser); assert(messageData.roomId, roomId); const raw = - await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.foo.uid }, { mid: messageData.mid }); + await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.foo.uid }, { mid: messageData.messageId }); assert.equal(raw, 'first chat message'); }); @@ -378,7 +378,7 @@ describe('Messaging Library', () => { assert(myRoomId); try { - await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.baz.uid }, { mid: 200 }); + await socketModules.chats.getRaw({ uid: mocks.users.baz.uid }, { mid: 200 }); } catch (err) { assert(err); assert.equal(err.message, '[[error:not-allowed]]'); @@ -386,7 +386,7 @@ describe('Messaging Library', () => { ({ body } = await callv3API('post', `/chats/${myRoomId}`, { roomId: myRoomId, message: 'admin will see this' }, 'baz')); const message = body.response; - const raw = await util.promisify(socketModules.chats.getRaw)({ uid: mocks.users.foo.uid }, { mid: message.mid }); + const raw = await socketModules.chats.getRaw({ uid: mocks.users.foo.uid }, { mid: message.messageId }); assert.equal(raw, 'admin will see this'); }); @@ -455,11 +455,8 @@ describe('Messaging Library', () => { }); it('should fail to rename room with invalid data', async () => { - let { body } = await callv3API('put', `/chats/${roomId}`, { name: null }, 'foo'); + const { body } = await callv3API('put', `/chats/${roomId}`, { name: null }, 'foo'); assert.strictEqual(body.status.message, await translator.translate('[[error:invalid-data]]')); - - ({ body } = await callv3API('put', `/chats/${roomId}`, {}, 'foo')); - assert.strictEqual(body.status.message, await translator.translate('[[error:required-parameters-missing, name]]')); }); it('should rename room', async () => { @@ -563,9 +560,9 @@ describe('Messaging Library', () => { before(async () => { await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.baz.uid] }, 'foo'); let { body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'first chat message' }, 'foo'); - mid = body.response.mid; + mid = body.response.messageId; ({ body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'second chat message' }, 'baz')); - mid2 = body.response.mid; + mid2 = body.response.messageId; }); after(async () => { @@ -639,8 +636,7 @@ describe('Messaging Library', () => { const { body } = await callv3API('get', `/chats/${roomId}`, {}, 'herp'); const { messages } = body.response; messages.forEach((msg) => { - assert(!msg.deleted || msg.content === '[[modules:chat.message-deleted]]', msg.content); - assert(!msg.deleted || msg.cleanedContent, '[[modules:chat.message-deleted]]', msg.content); + assert(!msg.deleted || msg.content === '

        [[modules:chat.message-deleted]]

        ', msg.content); }); }); diff --git a/test/user.js b/test/user.js index 066f6f13ae..660d35b805 100644 --- a/test/user.js +++ b/test/user.js @@ -574,7 +574,7 @@ describe('User', () => { const socketModules = require('../src/socket.io/modules'); const uid1 = await User.create({ username: 'chatuserdelete1' }); const uid2 = await User.create({ username: 'chatuserdelete2' }); - const roomId = await messaging.newRoom(uid1, [uid2]); + const roomId = await messaging.newRoom(uid1, { uids: [uid2] }); await messaging.addMessage({ uid: uid1, content: 'hello', From 2710037cb13e362b9593298d508746d6bf6a3d12 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Wed, 12 Jul 2023 17:04:32 +0000 Subject: [PATCH 037/300] chore(i18n): fallback strings for new resources: nodebb.error, nodebb.modules --- public/language/ar/error.json | 1 + public/language/ar/modules.json | 16 +++++++++++++++- public/language/bg/error.json | 1 + public/language/bg/modules.json | 16 +++++++++++++++- public/language/bn/error.json | 1 + public/language/bn/modules.json | 16 +++++++++++++++- public/language/cs/error.json | 1 + public/language/cs/modules.json | 16 +++++++++++++++- public/language/da/error.json | 1 + public/language/da/modules.json | 16 +++++++++++++++- public/language/de/error.json | 1 + public/language/de/modules.json | 16 +++++++++++++++- public/language/el/error.json | 1 + public/language/el/modules.json | 16 +++++++++++++++- public/language/en-US/error.json | 1 + public/language/en-US/modules.json | 16 +++++++++++++++- public/language/en-x-pirate/error.json | 1 + public/language/en-x-pirate/modules.json | 16 +++++++++++++++- public/language/es/error.json | 1 + public/language/es/modules.json | 16 +++++++++++++++- public/language/et/error.json | 1 + public/language/et/modules.json | 16 +++++++++++++++- public/language/fa-IR/error.json | 1 + public/language/fa-IR/modules.json | 16 +++++++++++++++- public/language/fi/error.json | 1 + public/language/fi/modules.json | 16 +++++++++++++++- public/language/fr/error.json | 1 + public/language/fr/modules.json | 16 +++++++++++++++- public/language/gl/error.json | 1 + public/language/gl/modules.json | 16 +++++++++++++++- public/language/he/error.json | 1 + public/language/he/modules.json | 16 +++++++++++++++- public/language/hr/error.json | 1 + public/language/hr/modules.json | 16 +++++++++++++++- public/language/hu/error.json | 1 + public/language/hu/modules.json | 16 +++++++++++++++- public/language/hy/error.json | 1 + public/language/hy/modules.json | 16 +++++++++++++++- public/language/id/error.json | 1 + public/language/id/modules.json | 16 +++++++++++++++- public/language/it/error.json | 1 + public/language/it/modules.json | 16 +++++++++++++++- public/language/ja/error.json | 1 + public/language/ja/modules.json | 16 +++++++++++++++- public/language/ko/error.json | 1 + public/language/ko/modules.json | 16 +++++++++++++++- public/language/lt/error.json | 1 + public/language/lt/modules.json | 16 +++++++++++++++- public/language/lv/error.json | 1 + public/language/lv/modules.json | 16 +++++++++++++++- public/language/ms/error.json | 1 + public/language/ms/modules.json | 16 +++++++++++++++- public/language/nb/error.json | 1 + public/language/nb/modules.json | 16 +++++++++++++++- public/language/nl/error.json | 1 + public/language/nl/modules.json | 16 +++++++++++++++- public/language/pl/error.json | 1 + public/language/pl/modules.json | 16 +++++++++++++++- public/language/pt-BR/error.json | 1 + public/language/pt-BR/modules.json | 16 +++++++++++++++- public/language/pt-PT/error.json | 1 + public/language/pt-PT/modules.json | 16 +++++++++++++++- public/language/ro/error.json | 1 + public/language/ro/modules.json | 16 +++++++++++++++- public/language/ru/error.json | 1 + public/language/ru/modules.json | 16 +++++++++++++++- public/language/rw/error.json | 1 + public/language/rw/modules.json | 16 +++++++++++++++- public/language/sc/error.json | 1 + public/language/sc/modules.json | 16 +++++++++++++++- public/language/sk/error.json | 1 + public/language/sk/modules.json | 16 +++++++++++++++- public/language/sl/error.json | 1 + public/language/sl/modules.json | 16 +++++++++++++++- public/language/sq-AL/error.json | 1 + public/language/sq-AL/modules.json | 16 +++++++++++++++- public/language/sr/error.json | 1 + public/language/sr/modules.json | 16 +++++++++++++++- public/language/sv/error.json | 1 + public/language/sv/modules.json | 16 +++++++++++++++- public/language/th/error.json | 1 + public/language/th/modules.json | 16 +++++++++++++++- public/language/tr/error.json | 1 + public/language/tr/modules.json | 16 +++++++++++++++- public/language/uk/error.json | 1 + public/language/uk/modules.json | 16 +++++++++++++++- public/language/vi/error.json | 1 + public/language/vi/modules.json | 16 +++++++++++++++- public/language/zh-CN/error.json | 1 + public/language/zh-CN/modules.json | 16 +++++++++++++++- public/language/zh-TW/error.json | 1 + public/language/zh-TW/modules.json | 16 +++++++++++++++- 92 files changed, 736 insertions(+), 46 deletions(-) diff --git a/public/language/ar/error.json b/public/language/ar/error.json index 5006890609..bcb2b49bba 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -199,6 +199,7 @@ "not-in-room": "المستخدم غير موجود في الغرفة.", "cant-kick-self": "لا يمكنك طرد نفسك من المجموعة.", "no-users-selected": "لا يوجد مستخدم محدد.", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index 3a30828fbf..b056086291 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 أشهر", "chat.delete_message_confirm": "هل أنت متأكد من أنك تريد حذف هذه الرسالة؟", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index 779b067093..b1c1e84a67 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -199,6 +199,7 @@ "not-in-room": "Потребителят не е в стаята", "cant-kick-self": "Не можете да изритате себе си от групата", "no-users-selected": "Няма избран(и) потребител(и)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Грешен път към началната страница", "invalid-session": "Изтекла сесия", "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла. Моля, опреснете страницата.", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 83cd1dd6af..18d434156a 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 месеца", "chat.delete_message_confirm": "Наистина ли искате да изтриете това съобщение?", "chat.retrieving-users": "Получаване на потребителите…", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управление на стаята за разговори", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Тук можете да потърсите потребители. Когато някой потребител бъде избран, той ще бъде добавен в разговора. Новият потребител няма да може да вижда съобщенията, написани преди включването му в разговора. Само собствениците на стаята () могат да премахват потребители от нея.", "chat.confirm-chat-with-dnd-user": "Този потребител е в състояние „не ме безпокойте“. Наистина ли искате да разговаряте с него?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Преименуване на стаята", "chat.rename-placeholder": "Въведете името на стаята си тук", "chat.rename-help": "Зададеното тук име на стаята ще се вижда от всички участници в нея.", - "chat.leave": "Напускане на разговора", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Наистина ли искате да напуснете този разговор?", "chat.leave-help": "Ако напуснете този разговор, няма да виждате следващите съобщения в него. Ако бъдете добавен(а) отново, няма да виждате историята на разговора отпреди добавянето Ви.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "В тази стая", "chat.kick": "Изгонване", "chat.show-ip": "Показване на IP адреса", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index c7d852a2cb..d736f30796 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index 28331cd7da..d7d1a20825 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "৩ মাস", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index d310f4a236..8a6d36a75c 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -199,6 +199,7 @@ "not-in-room": "Uživatel není přítomen v místnosti", "cant-kick-self": "Nemůžete vyhodit sami sebe ze skupiny", "no-users-selected": "Žádný uživatel/é nebyl/y vybrán/i", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Neplatná cesta k domovské stránkce", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index 73de1bebd5..c6c377fb9c 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 měsíce", "chat.delete_message_confirm": "Jste si jist/a, že chcete odstranit tuto zprávu?", "chat.retrieving-users": "Získávání seznamu uživatelů...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Spravovat konverzační místnosti", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Zde můžete vyhledávat uživatele. Jakmile si ho vyberete, uživatel bude přidán do konverzace. Nový uživatel nebude mít zobrazeny zprávy konverzace napsané dříve, než byl do konverzace přidán. Jen majitelé místnosti () mohou odebrat uživatele z konverzační místnosti.", "chat.confirm-chat-with-dnd-user": "Tento uživatel nastavil svůj stav na NERUŠIT. Opravdu chcete začít s ním konverzaci.", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Přejmenovat místnost", "chat.rename-placeholder": "Zde zadejte název místnosti", "chat.rename-help": "Název místnosti zde nastavený bude viditelný pro všechny účastníky komunikace v místnosti", - "chat.leave": "Opustit konverzaci", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Jste si jist/a, že chcete ukončit tuto konverzaci?", "chat.leave-help": "Ukončením této konverzace budete vyjmuti z budoucí možné komunikace v této konverzaci. Následně budete-li znovu přidán/a, neuvidíte historii komunikace od Vašeho odchodu.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "V této místnosti", "chat.kick": "Vykopnout", "chat.show-ip": "Zobrazit IP", diff --git a/public/language/da/error.json b/public/language/da/error.json index 7331a1c8c3..00a121fd34 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -199,6 +199,7 @@ "not-in-room": "Bruger er ikke i rummet", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/da/modules.json b/public/language/da/modules.json index 66e1c623f5..b59998229f 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 måneder", "chat.delete_message_confirm": "Er du sikker på at du vil slette denne besked?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/de/error.json b/public/language/de/error.json index ca93bf67d8..2cd3070c88 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -199,6 +199,7 @@ "not-in-room": "Benutzer nicht im Raum", "cant-kick-self": "Du kannst dich nicht selber aus der Gruppe entfernen.", "no-users-selected": "Kein(e) Benutzer ausgewählt", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ungültiger Startseitenpfad", "invalid-session": "Ungültige Session", "invalid-session-text": "Es scheint als wäre deine Login-Sitzung nicht mehr aktiv. Bitte aktualisiere diese Seite.", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index 1ee0f6f56b..fdad54ed4b 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Monate", "chat.delete_message_confirm": "Bist du sicher, dass du diese Nachricht löschen möchtest?", "chat.retrieving-users": "Rufe Benutzer ab", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Chatroom managen", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Suche hier nach Usern. Auswählen fügt den User hinzu. Der neue User wird nicht in der Lage sein Chat Nachrichten zu lesen, die geschrieben wurden bevor er der Konversation hinzugefügt wurde. Ausschließlich Raumbesitzer () können User von Chat Rooms entfernen.", "chat.confirm-chat-with-dnd-user": "Dieser Benutzer hat seinen Status auf DnD (Bitte nicht stören) gesetzt. Möchtest du dennoch mit ihm chatten?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Raum umbenennen", "chat.rename-placeholder": "Gib deinen Chatraumnamen hier ein", "chat.rename-help": "Den Namen des Chatraums den du hier setzt, wird für alle Teilnehmer sichtbar sein.", - "chat.leave": "Chat verlassen", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Bist du sicher, dass du diesen Chat verlassen willst?", "chat.leave-help": "Den Chat zu verlassen wird dich von weiterem Schriftverkehr in diesem Chat entfernen. Solltest du in der Zukunft wieder hinzugefügt werden, würdest du keinen Chatverlauf sehen können, der in der Zwischenzeit geschrieben wurde.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In diesem Chat-Room", "chat.kick": "Rauswerfen", "chat.show-ip": "IP anzeigen", diff --git a/public/language/el/error.json b/public/language/el/error.json index cf0873a294..16d4909599 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index 5f6d4149f0..05f5807fa1 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/en-US/error.json b/public/language/en-US/error.json index b4b0db8f20..5b092ac626 100644 --- a/public/language/en-US/error.json +++ b/public/language/en-US/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/en-US/modules.json b/public/language/en-US/modules.json index 5f6d4149f0..05f5807fa1 100644 --- a/public/language/en-US/modules.json +++ b/public/language/en-US/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/en-x-pirate/error.json b/public/language/en-x-pirate/error.json index b4b0db8f20..5b092ac626 100644 --- a/public/language/en-x-pirate/error.json +++ b/public/language/en-x-pirate/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/en-x-pirate/modules.json b/public/language/en-x-pirate/modules.json index c7dfd3c200..2f6f7d0487 100644 --- a/public/language/en-x-pirate/modules.json +++ b/public/language/en-x-pirate/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/es/error.json b/public/language/es/error.json index c99fa1c0f7..d72412f7b7 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -199,6 +199,7 @@ "not-in-room": "El usuario no está en la sala", "cant-kick-self": "No te puedes expulsar a ti mismo del grupo", "no-users-selected": "Ningun usuario(s) seleccionado", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ruta de página de inicio invalida", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index b08bc94649..eef7863278 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 meses", "chat.delete_message_confirm": "¿Estás seguro de que deseas eliminar este mensaje?", "chat.retrieving-users": "Cargando usuarios...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Administrar Sala de Chat", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "Este usuario está en modo No molestar. ¿ Estás seguro de que quieres chatear con él ?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Renombrar Sala", "chat.rename-placeholder": "Introduzca el nombre de su sala aquí", "chat.rename-help": "El nombre de sala elegido será visible por todos los participantes en la sala", - "chat.leave": "Abandonar Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Está seguro/a de que desea abandonar este chat?", "chat.leave-help": "Abandonar este chat te excluirá de futuras interacciones en este chat. Si eres re-añadido en el futuro, no verás ningún historial de chat anterior a tu vuelta.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "En esta sala", "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", diff --git a/public/language/et/error.json b/public/language/et/error.json index a88bb0e0c7..1dc87cd514 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -199,6 +199,7 @@ "not-in-room": "Kasutaja pole ruumis", "cant-kick-self": "Sa ei saa ennast ära visata gruppist", "no-users-selected": "Ühtki kasutajat pole valitud", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Vigane avalehe suunamine", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index f01fed2a2c..7ae2cb934e 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Kuud", "chat.delete_message_confirm": "Oled kindel, et soovid selle sõnumi kustutada?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/fa-IR/error.json b/public/language/fa-IR/error.json index 5b3bf5543d..78d5bcfb61 100644 --- a/public/language/fa-IR/error.json +++ b/public/language/fa-IR/error.json @@ -199,6 +199,7 @@ "not-in-room": "هیچ کاربری در این گفتگو نیست", "cant-kick-self": "شما نمی توانید خودتان را از گروه کیک کنید", "no-users-selected": "هیچ کاربر(های) انتخاب نشده", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "مسیر صفحه اصلی نامعتبر است", "invalid-session": "seesion نامعتبر، دوباره وارد حساب کاربری خود شوید ", "invalid-session-text": "به نظر می رسد این جلسه برای ورود شما دیگر فعال نیست. لطفا این صفحه را رفرش کنید", diff --git a/public/language/fa-IR/modules.json b/public/language/fa-IR/modules.json index dc4a40d7b9..1bace70e5d 100644 --- a/public/language/fa-IR/modules.json +++ b/public/language/fa-IR/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 ماه", "chat.delete_message_confirm": "آیا مطمئن هستید که می خواهید این پیام را حذف کنید؟", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "مدیریت چت روم", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "کاربران را در اینجا جستجو کنید. پس از انتخاب، کاربر به چت اضافه می شود. کاربر جدید نمی‌تواند پیام‌های چت نوشته شده قبل از اضافه شدن به مکالمه را ببیند. فقط مالک اتاق () می توانند کاربران را از اتاق های گفتگو حذف کنند.", "chat.confirm-chat-with-dnd-user": "این کاربر وضعیت خود را روی حالت مزاحم نشوید قرار داده است. آیا همچنان می خواهید با او چت کنید؟", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "تعویض اسم چت روم", "chat.rename-placeholder": "اسم چت روم را اینجا وارد کنید", "chat.rename-help": "اسم چت روم برای همه کاربران چت روم قابل رویت خواهد بود.", - "chat.leave": "ترک چت روم", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "آیا شما مطمئن هستید که می خواهید چت روم را ترک کنید؟", "chat.leave-help": "ترک این چت روم باعث از دست دادن ارتباط شما می شود. اگر شما بعدا به چت روم اضافه بشوید، قادر به مشاهده تاریخچه پیام ها نخواهید بود.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "در این چت روم", "chat.kick": "اخراج", "chat.show-ip": "نشان دادن IP", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 39a4632623..bf0955e480 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -199,6 +199,7 @@ "not-in-room": "Käyttäjä ei ole huoneessa", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index 50e0207b75..1f98a56893 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 kuukautta", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index bb850baf7f..5de824bcf0 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -199,6 +199,7 @@ "not-in-room": "L'utilisateur n'est pas dans cette salle", "cant-kick-self": "Vous ne pouvez pas vous exclure vous-même du groupe", "no-users-selected": "Aucun utilisateur sélectionné", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Chemin vers la page d'accueil invalide", "invalid-session": "Session Invalide", "invalid-session-text": "Il semblerait que votre session de connexion ne soit plus active. Merci de rafraîchir cette page.", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 2a81ace788..3302006f5b 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Mois", "chat.delete_message_confirm": "Êtes-vous sûr de vouloir supprimer ce message ?", "chat.retrieving-users": "Ajouter des utilisateurs ...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gérer l'espace de discussion", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Rechercher des utilisateurs ici. Lorsque cette option est sélectionnée, l'utilisateur sera ajouté à l'espace de discussion. Le nouvel utilisateur ne pourra pas visualiser les échanges avant d'être ajoutés à la conversation. Seuls les propriétaires de l'espace de discussion () peuvent supprimer des utilisateurs.", "chat.confirm-chat-with-dnd-user": "Cet utilisateur a son statut en mode \"Ne pas déranger\". Voulez-vous quand même discuter avec lui ?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Renommer l'espace de discussion ", "chat.rename-placeholder": "Entrer le nom ici ", "chat.rename-help": "Le nom de l'espace de discussion défini ici sera visible par tous les participants à la discussion.", - "chat.leave": "Quitter la discussion", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Êtes-vous sûr de vouloir quitter la discussion ?", "chat.leave-help": "Si vous quittez vous ne pourrez plus suivre la discussion. Si vous êtes de nouveau ajouté, vous ne verrez aucun historique de la discussion avant votre réintégration.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Dans cet espace de discussion", "chat.kick": "Exclure", "chat.show-ip": "Voir IP", diff --git a/public/language/gl/error.json b/public/language/gl/error.json index effa37c1f2..0007c72f7f 100644 --- a/public/language/gl/error.json +++ b/public/language/gl/error.json @@ -199,6 +199,7 @@ "not-in-room": "O usuario non se atopa nesta sala", "cant-kick-self": "Non te podes expulsar a ti mesmo do grupo", "no-users-selected": "Ningún usuario seleccionado", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ruta de páxina de inicio inválida", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/gl/modules.json b/public/language/gl/modules.json index f35c6944b1..02bbb5a9c3 100644 --- a/public/language/gl/modules.json +++ b/public/language/gl/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Meses", "chat.delete_message_confirm": "Estás seguro de que desexas eliminar esta mensaxe?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/he/error.json b/public/language/he/error.json index 43ae9ccccc..394d88fc05 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -199,6 +199,7 @@ "not-in-room": "משתמש זה אינו בחדר הצ'אט", "cant-kick-self": "אינכם יכולים להסיר את עצמכם מהקבוצה", "no-users-selected": "לא נבחרו משתמשים", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "כתובת דף הבית שגויה", "invalid-session": "סשן לא תקין", "invalid-session-text": "נראה שסשן ההתחברות שלכם אינה פעילה יותר. אנא רעננו את הדף.", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 181be76630..d260609c25 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 חודשים", "chat.delete_message_confirm": "האם למחוק הודעה זו?", "chat.retrieving-users": "מאחזר משתמשים...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "ניהול חדר צ'אט", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "חפשו משתמשים כאן. כאשר משתמש נבחר, הוא יצורף לצ'אט. המשתמש החדש לא יוכל לראות הודעות שנכתבו לפני הצטרפותו. רק מנהלי החדר () יכולים להסיר משתמשים מהצ'אט.", "chat.confirm-chat-with-dnd-user": "משתמש זה שינה את הסטטוס שלו ל'לא להפריע'. אתם עדיין מעוניין לשוחח איתו?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "שינוי שם חדר", "chat.rename-placeholder": "הזינו את שם החדר שלכם כאן", "chat.rename-help": "שם החדר המוגדר כאן יהיה זמין לכל המשתתפים בחדר.", - "chat.leave": "עזיבת שיחה", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "האם לעזוב שיחה זו?", "chat.leave-help": "עזיבת שיחה, תסיר אתכם מהתכתבות עתידית בצ'אט זה. אם תצטרפו מחדש בעתיד, לא תראו את היסטוריית הצ'אט שלפני הצטרפותכם מחדש.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "בתוך חדר זה", "chat.kick": "הוצא", "chat.show-ip": "הצג IP", diff --git a/public/language/hr/error.json b/public/language/hr/error.json index 3e8466c908..d2cc837547 100644 --- a/public/language/hr/error.json +++ b/public/language/hr/error.json @@ -199,6 +199,7 @@ "not-in-room": "Korisnik nije u sobi", "cant-kick-self": "Ne možete sebe izbaciti iz grupe", "no-users-selected": "Korisnici nisu odabrani", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Netočna putanja naslovnice", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/hr/modules.json b/public/language/hr/modules.json index 2e1446011b..2bfef4fe7f 100644 --- a/public/language/hr/modules.json +++ b/public/language/hr/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Mjeseca", "chat.delete_message_confirm": "Sigurni ste da želite izbrisati ovu poruku?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "Korisnik ne želi biti ometan. Jeste li sigurno da mu želite poslati poruku?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index daa6e50508..3917c24146 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -199,6 +199,7 @@ "not-in-room": "A felhasználó nincs a szobában", "cant-kick-self": "Nem rúghatod ki magad a csoportból", "no-users-selected": "Nincs felhasználó kiválasztva", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Érvénytelen főoldal elérési útvonal", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index 2cdfeab55d..648d64d749 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 hónap", "chat.delete_message_confirm": "Biztos törölni akarod az üzenetet?", "chat.retrieving-users": "Felhasználók lekérése...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Csevegő szoba kezelése", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Itt keress felhasználókat. Kiválasztás után a felhasználó hozzá lesz adva a chathez. Az új felhasználó nem fogja látni az üzenet előzményeket az előttről, hogy hozzá lett adva a beszélgetéshez. Csak a szoba tulajdonosai () távolíthatnak el felhasználókat a beszélgetésből.", "chat.confirm-chat-with-dnd-user": "A felhasználó \"ne zavarj\"-ra állította az állapotukat. Még így is csevegni akarsz velük?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Szoba átnevezése", "chat.rename-placeholder": "Add meg a szoba nevét", "chat.rename-help": "A megadott szoba név az összes szobában tartózkodó által megtekinthező lesz.", - "chat.leave": "Csevegő elhagyása", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Biztosan el akarod hagyni a beszélgetést?", "chat.leave-help": "A szoba elhagyását követően nem fogod látni az oda érkező üzeneteket. Ha újra hozzá leszel adva a szobához akkor nem fogod látni a beszélgetés előzményeit a kilépésed előttről sem.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Ebben a szobában", "chat.kick": "Kirúgás", "chat.show-ip": "IP cím mutatása", diff --git a/public/language/hy/error.json b/public/language/hy/error.json index 3b93ebc43c..e4580b6efa 100644 --- a/public/language/hy/error.json +++ b/public/language/hy/error.json @@ -199,6 +199,7 @@ "not-in-room": "Օգտատերը սենյակում չէ", "cant-kick-self": "Դուք չեք կարող ձեզ հեռացնել խմբից", "no-users-selected": "Ընտրված օգտատեր(ներ) չկա", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Գլխավոր էջի անվավեր ուղեգիծ", "invalid-session": "Անվավեր սեսիա", "invalid-session-text": "Կարծես թե ձեր մուտքի սեսիան այլևս ակտիվ չէ: Խնդրում ենք թարմացնել այս էջը:", diff --git a/public/language/hy/modules.json b/public/language/hy/modules.json index 3223ffdd2e..1bd8032980 100644 --- a/public/language/hy/modules.json +++ b/public/language/hy/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 ամիս", "chat.delete_message_confirm": "Վստա՞հ եք, որ ցանկանում եք ջնջել այս հաղորդագրությունը:", "chat.retrieving-users": "Օգտատերերի վերականգնում ", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Կարգավորել Զրուցասենյակը", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Որոնել օգտերերին այստեղ: Ընտրվելուց հետո օգտատերը կավելացվի զրուցարանում: Նոր օգտատերը չի կարողանա տեսնել զրույցի հաղորդագրությունները, որոնք գրված են նախքան դրանք ավելացվելը խոսակցությանը: Միայն սենյակների սեփականատերերը կարող են օգտատերերին հեռացնել զրուցարաններից:", "chat.confirm-chat-with-dnd-user": "Այս օգտվողը դրել է իր կարգավիճակը DnD (Մի խանգարեք): Դեռ ցանկանու՞մ եք զրուցել նրանց հետ:", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Վերանվանել սենյակը", "chat.rename-placeholder": "Մուտքագրեք ձեր սենյակի անունը այստեղ", "chat.rename-help": "Այստեղ սահմանված սենյակի անունը տեսանելի կլինի սենյակի բոլոր մասնակիցների համար:", - "chat.leave": "Դուրս գալ զրույցից.", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Վստա՞հ եք, որ ցանկանում եք լքել այս զրույցը:", "chat.leave-help": "Այս զրույցից դուրս գալը ձեզ կհեռացնի այս զրույցի հետագա նամակագրությունից: Եթե ապագայում ձեզ նորից ավելացնեն, դուք չեք տեսնի զրույցի պատմություն, որը տեղի է ունեցել մինչ ձեր նորից միանալը:", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Այս սենյակում ", "chat.kick": "Kick", "chat.show-ip": "Ցույց տալ IP", diff --git a/public/language/id/error.json b/public/language/id/error.json index a5c4c74ff2..c3f20f6d80 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index 551ef4ac4f..b5dc60f0e7 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Bulan", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/it/error.json b/public/language/it/error.json index bca3af9820..9f5975d10f 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -199,6 +199,7 @@ "not-in-room": "L'utente non è in questa stanza", "cant-kick-self": "Non puoi espellerti dal gruppo", "no-users-selected": "Nessun utente selezionato", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Percorso della pagina iniziale non valido", "invalid-session": "Sessione non valida", "invalid-session-text": "Sembra che la tua sessione di accesso non sia più attiva. Si prega di aggiornare questa pagina.", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 417a5faf5d..c392de3990 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Mesi", "chat.delete_message_confirm": "Sei sicuro di voler eliminare questo messaggio?", "chat.retrieving-users": "Estrapolando gli utenti...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gestisci stanza chat", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Cerca qui gli utenti. Quando selezionato, l'utente sarà aggiunto alla chat.\nIl nuovo utente non sarà in grado di vedere i messaggi della chat scritti prima della sua partecipazione alla conversazione.\nSolo i proprietari della stanza () possono rimuovere gli utenti dalla stanza della chat.", "chat.confirm-chat-with-dnd-user": "Questo utente ha impostato il suo stato su Non Disturbare. Sei sicuro di voler iniziare una conversazione?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rinomina stanza", "chat.rename-placeholder": "Inserisci qui il nome della stanza", "chat.rename-help": "Il nome della stanza qui impostato sarà visibile da tutti i partecipanti nella stanza.", - "chat.leave": "Abbandona Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Sei sicuro di volere abbandonare questa chat?", "chat.leave-help": "Abbandonando questa chat perderai ogni sua traccia. Anche dopo un tuo eventuale rientro, non vedrai nessun messaggio precedente.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In questa stanza", "chat.kick": "Butta fuori", "chat.show-ip": "Mostra indirizzo IP", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index 6dd1b14526..a27e15966a 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -199,6 +199,7 @@ "not-in-room": "ユーザーが部屋にいません", "cant-kick-self": "あなたは、グループから自分自身をキックすることが出来ません", "no-users-selected": "ユーザー(s)が選択されていません", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "ホームページのルートが無効", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index b478224153..88798bb517 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3ヶ月", "chat.delete_message_confirm": "本当にこのメッセージを削除しますか?", "chat.retrieving-users": "ユーザーを所得しています…", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "チャット部屋を管理", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "このユーザーのステータスはDnD(Do not disturb:取り込み中)に設定されています。あなたはまだチャットしたいですか?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "部屋名を変更", "chat.rename-placeholder": "部屋名を入力", "chat.rename-help": "設定した部屋名は、この部屋のすべての参加者に表示されます", - "chat.leave": "チャットから退出", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "このチャットから退出しますか?", "chat.leave-help": "このチャットを終了すると、このチャットからあなたが削除されます。 再度参加しても、前のチャット履歴は表示されません。", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "この部屋内", "chat.kick": "キック", "chat.show-ip": "IP表示", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index c44e5f67bb..766ff9433e 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -199,6 +199,7 @@ "not-in-room": "채팅방에 사용자 없음", "cant-kick-self": "스스로 이 그룹을 탈퇴할 수 없습니다.", "no-users-selected": "선택된 사용자가 없습니다.", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "올바르지 않은 홈페이지 경로입니다.", "invalid-session": "세션 오류", "invalid-session-text": "로그인 세션이 종료됐습니다. 페이지를 새로고침 해주세요.", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index 9f80fdbacd..69f34746af 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3개월", "chat.delete_message_confirm": "이 메세지를 삭제하시겠습니까?", "chat.retrieving-users": "사용자 불러오는 중...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "채팅 관리", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "여기에서 사용자를 검색하세요. 선택한 사용자를 채팅에 초대합니다. 새로운 사용자는 이전에 주고받은 채팅을 확인할 수 없습니다. 채팅 관리자들()만 사용자를 채팅방에서 추방할 수 있습니다.", "chat.confirm-chat-with-dnd-user": "이 사용자는 자신의 상태를 방해 금지로 설정했습니다. 그래도 대화를 요청하시겠습니까?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "채팅방 이름 변경", "chat.rename-placeholder": "여기에 채팅방 이름을 입력하세요.", "chat.rename-help": "여기에서 설정된 채팅방 이름은 모든 참여자들에게 보여집니다.", - "chat.leave": "채팅방 나가기", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "정말로 이 채팅에서 나가시겠어요?", "chat.leave-help": "이 채팅방에서 퇴장하면 더 이상 이 채팅방의 메시지를 수신할 수 없습니다. 나중에 다시 입장하게 되더라도 퇴장한 동안의 메시지는 확인할 수 없습니다.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "채팅 참여자", "chat.kick": "추방", "chat.show-ip": "IP 보이기", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 1595d4a985..5fefbbb238 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -199,6 +199,7 @@ "not-in-room": "Vartotojas ne svetainėje", "cant-kick-self": "Negalite išmesti savęs iš grupės", "no-users-selected": "Nepasirinktas joks vartotojas", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Blogas kelias į pagrindinį puslapį", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index 221532a712..fe4a4bebc5 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 mėnesiai", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/lv/error.json b/public/language/lv/error.json index b6f24a4006..2712f0b3dc 100644 --- a/public/language/lv/error.json +++ b/public/language/lv/error.json @@ -199,6 +199,7 @@ "not-in-room": "Lietotājs nav tērzētavā", "cant-kick-self": "Nevar sevi izslēgt no grupas", "no-users-selected": "Nav atlasīts neviens lietotājs(-i)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Nederīgs sākumlapas ceļš", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/lv/modules.json b/public/language/lv/modules.json index 778e9f68cc..9a4e39bc1d 100644 --- a/public/language/lv/modules.json +++ b/public/language/lv/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 mēneši", "chat.delete_message_confirm": "Vai tiešām vēlies izdzēst šo sarunu?", "chat.retrieving-users": "Ielādē lietotājus...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Pārvaldīt tērzētavu", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Meklē lietotājus šeit. Izvēlētais lietotājs tiks pievienots sarunai. Jaunais lietotājs neredzēs sarunas, kas rakstītas pirms viņu pievienoja sarunai. Tikai tērzētavas īpašnieks(-i) var noņemt lietotājus no tērzētavām.", "chat.confirm-chat-with-dnd-user": "Lietotājs ir iestatījis savu statusu uz DnD (netraucējams). Vai Tu joprojām vēlies sarunāties ar viņu?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Pārdēvēt tērzētavu", "chat.rename-placeholder": "Ievadi savas tērzētavas nosaukumu šeit", "chat.rename-help": "Šeit norādītais tērzētavas nosaukums būs redzams visiem dalībniekiem.", - "chat.leave": "Pamest sarunu", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Vai tiešām vēlies pamest šo sarunu?", "chat.leave-help": "Atstājot šo sarunu, Tu tiksi noņemts no turpmākām sarunām. Ja Tu nākotnē atkārtoti pievienojies, Tu neredzēsi nevienu sarunu no pirms tā brīža.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Šajā tērzētavā", "chat.kick": "Izslēgt", "chat.show-ip": "Rādīt IP adresi", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 4d4e15f518..c046c2d6fd 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -199,6 +199,7 @@ "not-in-room": "Pengguna tiada dalam bilik", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index 5cedf4f72e..02cb0c4037 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Bulan", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index c33c8ba5a8..3e3ae4c821 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -199,6 +199,7 @@ "not-in-room": "Bruker ikke i rom", "cant-kick-self": "Du kan ikke utestenge deg selv fra gruppen", "no-users-selected": "Ingen bruker(e) valgt", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ugyldig hjemmesidelenke", "invalid-session": "Ugyldig økt", "invalid-session-text": "Det ser ut til at din innloggingssesjon ikke lenger er aktiv. Last inn denne siden på nytt.", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 5153061778..d0eae25530 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 måneder", "chat.delete_message_confirm": "Er du sikker på at du vil slette denne meldingen?", "chat.retrieving-users": "Henter brukere ...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Søk etter brukere her. Når dette er valgt, blir brukeren lagt til i chatten. Den nye brukeren vil ikke kunne se chatmeldinger skrevet før de ble lagt til i samtalen. Bare romeiere () kan fjerne brukere fra chatterom.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index d9bd55dc51..1fb5aa0cef 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -199,6 +199,7 @@ "not-in-room": "Gebruiker niet in de chat", "cant-kick-self": "Je kunt jezelf niet uit een groep schoppen", "no-users-selected": "Geen gebruiker(s) geselecteerd", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Onbekende homepage route", "invalid-session": "Ongeldige Sessie", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index 45b80e955c..8fee0946c5 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 maanden", "chat.delete_message_confirm": "Weet je zeker dat je dit bericht wilt verwijderen?", "chat.retrieving-users": "Gebruikers ophalen...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Chat Room beheren", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Zoek hier naar gebruikers. Indien geselecteerd word de gebruiker toegevoegd aan de chat. De nieuwe gebruiker kan geen chatberichten zien die geschreven zijn voordat de gebruiker was toegevoegd aan de conversatie. Alleen chatroom-eigenaren () kunnen gebruikers verwijderen uit een chatroom.", "chat.confirm-chat-with-dnd-user": "Deze gebruiker heeft de status op Niet Storen (DnD, Do not disturb) gezet. Wil je nog steeds een chat starten met deze persoon?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Hernoem chatroom", "chat.rename-placeholder": "Voer hier de naam van je chat room in", "chat.rename-help": "De naam van de chat room die je hier zet is zichtbaar voor alle deelnemers aan de chat.", - "chat.leave": "Verlaat Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Weet je zeker dat je deze chat wilt verlaten?", "chat.leave-help": "Als je de chat verlaat zul je toekomstige correspondentie in de chat niet meer zien. Als je later weer wordt toegevoegd, dan kun je de chat geschiedenis tot de hertoevoeging niet zien.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In deze chat room", "chat.kick": "Schop", "chat.show-ip": "Geef IP weer", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index 8f9444dec4..60a17c7524 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -199,6 +199,7 @@ "not-in-room": "Użytkownika nie ma w pokoju", "cant-kick-self": "Nie możesz wyrzucić samego siebie z grupy", "no-users-selected": "Nie wybrano żadnych użytkowników", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Niepoprawny odnośnik strony domowej", "invalid-session": "Nieprawidłowa sesja", "invalid-session-text": "Wygląda na to, że Twoja sesja wygasła. Proszę odśwież stronę.", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 320a089659..9d9021efb2 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 miesiące", "chat.delete_message_confirm": "Czy na pewno chcesz usunąć tę wiadomość?", "chat.retrieving-users": "Pobieram użytkowników...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Zarządzaj pokojami czatu", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Tu można wyszukiwać użytkowników. Wybrany użytkownik zostanie dodany do czatu. Nowy użytkownik nie zobaczy wiadomości sprzed dołączenia do konwersacji. Tylko właściciele pokoi () mogą usuwać użytkowników z pokoi czatu.", "chat.confirm-chat-with-dnd-user": "Ten użytkownik ustawił status „nie przeszkadzać”. Czy chcesz z nim rozmawiać mimo to?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Zmień nazwę pokoju", "chat.rename-placeholder": "Tu wpisz nazwę pokoju", "chat.rename-help": "Ustawiona tu nazwa pokoju będzie widoczna dla wszystkich obecnych w nim użytkowników.", - "chat.leave": "Opuść czat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Czy na pewno chcesz opuścić ten czat?", "chat.leave-help": "Opuszczając czat, tracisz dostęp do dalszej rozmowy na czacie. Jeśli w przyszłości zostaniesz znów dodany, nie zobaczysz historii czatu sprzed ponownego dołączenia.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "W tym pokoju", "chat.kick": "Wyrzuć", "chat.show-ip": "Pokaż IP", diff --git a/public/language/pt-BR/error.json b/public/language/pt-BR/error.json index 6c82763848..f9b988a853 100644 --- a/public/language/pt-BR/error.json +++ b/public/language/pt-BR/error.json @@ -199,6 +199,7 @@ "not-in-room": "O usuário não está na sala", "cant-kick-self": "Você não pode kickar a si mesmo do grupo", "no-users-selected": "Nenhuma escolha de usuário(s) foi feita", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Rota de página inicial inválida", "invalid-session": "Sessão Inválida", "invalid-session-text": "Parece que a sua sessão de login não está mais ativa. Por favor, atualize esta página.", diff --git a/public/language/pt-BR/modules.json b/public/language/pt-BR/modules.json index 21dc86820d..06d16e8752 100644 --- a/public/language/pt-BR/modules.json +++ b/public/language/pt-BR/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Meses", "chat.delete_message_confirm": "Tem certeza que deseja excluir esta mensagem?", "chat.retrieving-users": "Carregando usuários", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Administrar Salas de Conversa", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Pesquise usuários aqui. Quando selecionado, o usuário será adicionado ao chat. O novo usuário não poderá ver as mensagens de chat que foram enviadas antes de ele ser adicionado à conversa. Somente os donos de salas () podem remover usuários de salas de conversa.", "chat.confirm-chat-with-dnd-user": "Este usuário definiu seu estado como DnD(Do not disturb - Não perturbe). Você ainda assim quer conversar com ele?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Renomear sala", "chat.rename-placeholder": "Digite o nome da sala aqui", "chat.rename-help": "O nome informado será visto por todos os participantes desta sala", - "chat.leave": "Sair da conversa", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Tem certeza que deseja sair da conversa?", "chat.leave-help": "Ao sair desta conversa você não receberá mais informações à respeito desta. Se você for adicionado novamente no futuro, você não poderá visualizar o histórico da conversa antes de sua re-entrada.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Nesta sala", "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", diff --git a/public/language/pt-PT/error.json b/public/language/pt-PT/error.json index cd9fb18d08..4e0a5163d6 100644 --- a/public/language/pt-PT/error.json +++ b/public/language/pt-PT/error.json @@ -199,6 +199,7 @@ "not-in-room": "Utilizador não se encontra na sala", "cant-kick-self": "Não te podes expulsar a ti próprio do grupo", "no-users-selected": "Não existe(m) utilizador(es) selecionado(s)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Rota para a página principal inválida", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index 415bfbb6bc..96f3bcbcff 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 meses", "chat.delete_message_confirm": "Tens a certeza que desejas apagar esta mensagem?", "chat.retrieving-users": "A recuperar utilizadores...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gerir sala de conversa", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Encontra utilizadores aqui. Quando selecionado, o utilizador vai ser adicionado à conversa. O novo utilizador não conseguirá ver mensagens que foram enviadas antes de ele entrar na sala. Apenas os donos das salas () poderão remover participantes das salas de conversa", "chat.confirm-chat-with-dnd-user": "Este utilizador definiu o seu estado como \"não perturbar\". Pretendes mesmo assim conversar com ele?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Renomear esta sala", "chat.rename-placeholder": "Insere o nome da conversa aqui", "chat.rename-help": "O nome desta conversa vai ser visualizada por todos os participantes desta sala.", - "chat.leave": "Sair da conversa", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Tens a certeza que pretendes sair desta conversa?", "chat.leave-help": "Deixar esta sala vai te remover de receber futuras mensagens importantes nesta conversa. Se fores novamente adicionado no futuro, não conseguirás ver nenhum histórico das conversas de antes da tua re-adesão.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Participantes nesta sala", "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index 3d5c6e2890..a6c0e9b920 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index 2ee45933fc..fcf29f083b 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Luni", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index 632118b8c5..24d296fc7f 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -199,6 +199,7 @@ "not-in-room": "Пользователь отсутствует в этой комнате", "cant-kick-self": "Удалить себя из группы невозможно.", "no-users-selected": "Выберите одного или нескольких пользователей", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Неверная ссылка на домашнюю страницу", "invalid-session": "Недействительная сессия", "invalid-session-text": "Похоже, что ваша сессия входа больше не активна. Пожалуйста, обновите эту страницу.", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 11f8cacca4..f1ca046db6 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 месяца", "chat.delete_message_confirm": "Вы уверены, что хотите удалить это сообщение?", "chat.retrieving-users": "Получение списка пользователей...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управлять комнатой чата", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Поиск пользователей здесь. Когда выбрали пользователя, он будет добавлен в чат. Новый пользователь не сможет видеть сообщения чата, написанные до его добавления в беседу. Только владельцы комнат () могут удалить пользователей из чатов.", "chat.confirm-chat-with-dnd-user": "Этот пользователь установил статус \"Не беспокоить\". Вы всё еще хотите написать ему?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Переименовать комнату", "chat.rename-placeholder": "Введите название комнаты здесь", "chat.rename-help": "Название комнаты, установленное здесь, будет доступно для просмотра всеми участниками комнаты.", - "chat.leave": "Покинуть чат", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Вы действительно хотите покинуть чат?", "chat.leave-help": "Оставив этот чат, вы удалите себя из будущей переписки в этом чате. Если вы будете повторно добавлены в будущем, вы не увидите истории чата до вашего повторного присоединения.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "В этой комнате", "chat.kick": "Исключить", "chat.show-ip": "Показать IP", diff --git a/public/language/rw/error.json b/public/language/rw/error.json index 404e69bb7f..865c083d6d 100644 --- a/public/language/rw/error.json +++ b/public/language/rw/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/rw/modules.json b/public/language/rw/modules.json index d47842ab0f..0b4a2cb3ac 100644 --- a/public/language/rw/modules.json +++ b/public/language/rw/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "Amezi 3", "chat.delete_message_confirm": "Wiringiye neza ko ushaka gusiba ubu butumwa?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index b4b0db8f20..5b092ac626 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -199,6 +199,7 @@ "not-in-room": "User not in room", "cant-kick-self": "You can't kick yourself from the group", "no-users-selected": "No user(s) selected", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Invalid home page route", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index 24a6c6a64f..d7afcd8310 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Months", "chat.delete_message_confirm": "Are you sure you wish to delete this message?", "chat.retrieving-users": "Retrieving users...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Manage Chat Room", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Leave Chat", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Are you sure you wish to leave this chat?", "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 8132e52263..8244d24118 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -199,6 +199,7 @@ "not-in-room": "Užívateľ nie je v miestnosti", "cant-kick-self": "Nemôžete vykopnúť samého seba zo skupiny", "no-users-selected": "Žiadny užívateľ(ia) neboli vybratý", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Neplatná cesta pre domovskú stránku", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index abb7e3e49c..1ebff8e966 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 mesiace", "chat.delete_message_confirm": "Ste si istý, že chcete odstrániť túto správu?", "chat.retrieving-users": "Získavanie zoznamu používateľov...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Spravovať konverzačné miestnosti", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Tu môžete vyhľadávať používateľov. Akonáhle si ho vyberiete, užívateľ bude pridaný do konverzácie. Nový používateľ nebude mať možnosť čítať správy, ktoré boli napísané skôr, ako bol pridaný do konverzácie. Iba majitelia miestnosti () môžu odobrať používateľov z konverzačných miestností.", "chat.confirm-chat-with-dnd-user": "Tento používateľ nastavil svoj stav na NERUŠIŤ. Naozaj chcete s ním začať konverzáciu?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Premenovať miestnosť", "chat.rename-placeholder": "Sem zadajte názov miestnosti", "chat.rename-help": "Názov miestnosti zadaný sem, bude viditeľný pre všetkých účastníkov komunikácie v miestnosti", - "chat.leave": "Opustiť konverzáciu", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Ste si istý, že chcete ukončiť túto konverzáciu?", "chat.leave-help": "Ukončením tejto konverzácie budete odstránený z budúcej komunikácie v tejto konverzácií. Ak budete následne znovu pridaný, neuvidíte históriu komunikácie od Vášho odchodu.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "V tejto miestnosti", "chat.kick": "Vykopnúť", "chat.show-ip": "Zobraziť IP adresu", diff --git a/public/language/sl/error.json b/public/language/sl/error.json index 3a9cb5ea47..c496364ed7 100644 --- a/public/language/sl/error.json +++ b/public/language/sl/error.json @@ -199,6 +199,7 @@ "not-in-room": "Uporabnika ni v sobi.", "cant-kick-self": "Sebe ne morete umakniti iz skupine.", "no-users-selected": "Ni izbranih uporabnikov.", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Napačna pot do domače strani.", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sl/modules.json b/public/language/sl/modules.json index 213f3f373c..d575d00a0a 100644 --- a/public/language/sl/modules.json +++ b/public/language/sl/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 meseci", "chat.delete_message_confirm": "Ali ste prepričani, da želite izbrisati to sporočilo?", "chat.retrieving-users": "Pridobivanje uporabnikov...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Upravljaj sobo klepeta", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "This user has set their status to DnD(Do not disturb). Do you still want to chat with them?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "Enter your room name here", "chat.rename-help": "The room name set here will be viewable by all participants in the room.", - "chat.leave": "Zapusti klepet", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Ste prepričani, da želite zapustiti ta klepet?", "chat.leave-help": "Če zapustite ta klepet boste izključeni iz prihodnje korespondence v tem klepetu. Če boste v prihodnosti v klepet znova dodani, ne boste videli zgodovine klepeta pred ponovno pridružitvijo.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "In this room", "chat.kick": "Kick", "chat.show-ip": "Pokaži IP", diff --git a/public/language/sq-AL/error.json b/public/language/sq-AL/error.json index 88b27422ba..e59893cd5b 100644 --- a/public/language/sq-AL/error.json +++ b/public/language/sq-AL/error.json @@ -199,6 +199,7 @@ "not-in-room": "Përdoruesi nuk është në dhomën e bisedës", "cant-kick-self": "Nuk mund ta largosh veten nga grupi", "no-users-selected": "Nuk është zgjedhur asnjë përdorues()", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Link i pavlefshëm", "invalid-session": "Sesion i pavlefshëm", "invalid-session-text": "Duket sikur sesioni juaj i hyrjes nuk është më aktiv. Ju lutemi rifreskojeni këtë faqe.", diff --git a/public/language/sq-AL/modules.json b/public/language/sq-AL/modules.json index 4a9f23adbd..1ce34f9498 100644 --- a/public/language/sq-AL/modules.json +++ b/public/language/sq-AL/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Muaj", "chat.delete_message_confirm": "A je i sigurt që dëshiron ta fshihni këtë mesazh?", "chat.retrieving-users": "Duke marrë përdoruesit...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Menaxho hapësirën e bisedave", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Kërkoni për përdoruesit këtu. Kur zgjidhet, përdoruesi do të shtohet në bisedë. Përdoruesi i ri nuk do të jetë në gjendje të shohë mesazhet e bisedës të shkruara përpara se të shtoheshin në bisedë. Vetëm krijuesit e bisedes () mund të heqin përdoruesit nga hapesirat e bisedës.", "chat.confirm-chat-with-dnd-user": "Ky përdorues ka vendosur statusin e tij në (Mos shqetëso). Dëshiron ende të bisedosh me ta?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Riemërto dhomën", "chat.rename-placeholder": "Shkruani emrin e dhomës tuaj këtu", "chat.rename-help": "Emri i dhomës i vendosur këtu do të jetë i dukshëm nga të gjithë pjesëmarrësit në dhomë.", - "chat.leave": "Largohu nga biseda", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Jeni i sigurt që dëshironi të largoheni nga kjo bisedë?", "chat.leave-help": "Largimi nga kjo bisedë do t'ju heqë nga korrespondenca e ardhshme në këtë bisedë. Nëse do të rishtoheni në të ardhmen, nuk do të shihni asnjë histori bisede nga para ribashkimit.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Në këtë dhomë", "chat.kick": "Largo", "chat.show-ip": "Shfaq IP", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index 26b4580399..e6dcd287dd 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -199,6 +199,7 @@ "not-in-room": "Корисник није у соби", "cant-kick-self": "Не можете избацити себе из групе", "no-users-selected": "Није одабран корисник", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Неважећа путања матичне странице", "invalid-session": "Неважећа сесија", "invalid-session-text": "Изгледа да ваша сесија пријављивања није више активна. Поново учитајте ову страницу.", diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index d8f3f8f7ed..078377f0a0 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 месеца", "chat.delete_message_confirm": "Да ли сте сигурни да желите да избришете ову поруку?", "chat.retrieving-users": "Преузимање корисника...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управљај собом за ћаскање", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Потражите кориснике овде. Када буде изабран, корисник ће бити додан у ћаскање. Нови корисник неће бити у могућности да види поруке написане пре него што је додан у преписку. Само власници соба () могу уклонити кориснике из соба за ћаскање.", "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на \"Не узнемиравај\". Да ли и даље желите да ћаскате са њим?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Преименуј собу", "chat.rename-placeholder": "Унесите назив собе овде", "chat.rename-help": "Име собе постављено овде биће видљиво свим учесницима у соби.", - "chat.leave": "Напусти ћаскање", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Да ли сте сигурни да желите да напустите ово ћаскање?", "chat.leave-help": "Напуштање овог ћаскања ће вас уклонити из будућих преписки у овом ћаскању. Ако будете поново додани у будућности, нећете видети историју ћаскања од пре вашег поновног придруживања.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "У овој соби", "chat.kick": "Избаци", "chat.show-ip": "Прикажи IP", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index ec3f18f974..576f209ac2 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -199,6 +199,7 @@ "not-in-room": "Användaren finns inte i rummet", "cant-kick-self": "Du kan inte sparka ut dig själv från gruppen", "no-users-selected": "Ingen användare vald(a)", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Ogiltig sidsökväg", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 957403eb60..3ec3cd1eae 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 månader", "chat.delete_message_confirm": "Är du säker på att du vill radera det här meddelandet?", "chat.retrieving-users": "Hämtar användare...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Hantera chattrum", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Sök efter användare här. Vid markering läggs användaren till i chatten. Den nya användaren kommer inte kunna se chattmeddelanden som skrevs innan de lades till i konversationen. Endast chattrumsägare () kan avlägsna användare från chattrum.", "chat.confirm-chat-with-dnd-user": "Denna användare har satt sin status till Stör Ej. Vill du fortfarande chatta med dem?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Byt namn på rum", "chat.rename-placeholder": "Skriv in rummets namn här", "chat.rename-help": "Rummets namn som skrivs in här kommer vara synligt för alla deltagare i rummet.", - "chat.leave": "Lämna chatt", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Är du säker att du vill lämna denna chatt?", "chat.leave-help": "Om du lämnar denna chatt kommer du inte vara med i framtida korrespondens i denna chatt. Om du läggs till igen i framtiden, kommer du inte se någon chatthistorik från innan du lades till.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "I detta rum", "chat.kick": "Sparka ut", "chat.show-ip": "Visa IP", diff --git a/public/language/th/error.json b/public/language/th/error.json index 99dabfb1c9..7ea59a5945 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -199,6 +199,7 @@ "not-in-room": "ผู้ใช้ไม่อยู่ในห้อง", "cant-kick-self": "คุณไม่สามารถเตะตัวเองออกจากกลุ่มได้", "no-users-selected": "ไม่มีผู้ใช้ที่เลือก", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "เส้นทางไปหน้าแรกผิดพลาด", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index f4326cac7c..9d287d729f 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 เดือน", "chat.delete_message_confirm": "คุณแน่ใจแล้วใช่ไหมว่าต้องการจะลบข้อความนี้?", "chat.retrieving-users": "กำลังเรียกข้อมูลผู้ใช้", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "จัดการห้องแชท", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Search for users here. When selected, the user will be added to the chat. The new user will not be able to see chat messages written before they were added to the conversation. Only room owners () may remove users from chat rooms.", "chat.confirm-chat-with-dnd-user": "ผู้ใช้นี้ได้ตั้งค่าสถานะเป็น (ห้ามรบกวน) คุณยังอยากจะคุยกับเขาอยู่ไหม?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Rename Room", "chat.rename-placeholder": "ใส่ชื่อห้องของคุณที่นี่", "chat.rename-help": "ชื่อห้องจะสามารถดูได้โดยผู้เข้าร่วมทั้งหมดในห้อง", - "chat.leave": "ออกแชท", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "คุณแน่ใจหรือไม่ว่าต้องการออกจากการแชทนี้", "chat.leave-help": "การออกจากการแชทนี้จะเป็นการลบคุณออกจากการติดต่อในอนาคตในการแชทนี้ หากคุณถูกเพิ่มเข้ามาใหม่ในอนาคตคุณจะไม่เห็นประวัติการแชทก่อนที่จะเข้าร่วมใหม่", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "ในห้องนี้", "chat.kick": "Kick", "chat.show-ip": "Show IP", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index 9d5360fc09..23cc21976a 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -199,6 +199,7 @@ "not-in-room": "Odada kullanıcı yok", "cant-kick-self": "Kendinizi gruptan atamazsınız.", "no-users-selected": "Seçili kullanıcı(lar) bulunamadı", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Geçersiz anasayfa yolu", "invalid-session": "Geçersiz Oturum", "invalid-session-text": "Giriş oturumunuz aktif görünmüyor. Lütfen sayfayı yenileyiniz.", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 72e0181ebe..51ef7af90e 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 Ay", "chat.delete_message_confirm": "Bu mesajı silmek istediğinizden emin misiniz?", "chat.retrieving-users": "Kullanıcılar alınıyor ...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Sohbet Odasını Yönet", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Burada kullanıcılar için arama yapın. Kullanıcı seçildiğinde sohbete eklenecektir. Yeni kullanıcı sohbete eklenmeden önce yazılmış olan sohbet mesajlarını göremeyecektir. Yalnızca oda sahipleri () kullanıcıları sohbet odalarından kaldırabilir.", "chat.confirm-chat-with-dnd-user": "Bu kullanıcı durumunu rahatsız etmeyin olarak ayarladı. Hala onunla sohbet etmek istiyor musunuz?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Odanın ismini değiştir", "chat.rename-placeholder": "Oda isminizi buraya girin", "chat.rename-help": "Buradaki oda ismi odadaki tüm katılımcılar tarafından görülebilir.", - "chat.leave": "Sohbetten Ayrıl", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Sohbetten ayrılmak istediğinizden emin misiniz?", "chat.leave-help": "Bu sohbetten ayrılmak, bu sohbetteki gelecekteki yazışmalardan sizi silecektir. Gelecekte tekrar eklendiyseniz, yeniden katılmadan önce herhangi bir sohbet geçmişi görmezsiniz.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Bu odada", "chat.kick": "Dışarı At", "chat.show-ip": "IP Göster", diff --git a/public/language/uk/error.json b/public/language/uk/error.json index 87ad050254..28850b7b44 100644 --- a/public/language/uk/error.json +++ b/public/language/uk/error.json @@ -199,6 +199,7 @@ "not-in-room": "Користувача немає в кімнаті", "cant-kick-self": "Ви не можете вигнати самі себе з групи", "no-users-selected": "Не вибрано жодного користувача", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Невірний шлях на головну", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/uk/modules.json b/public/language/uk/modules.json index 3af610d79a..15732c3e12 100644 --- a/public/language/uk/modules.json +++ b/public/language/uk/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 місяці", "chat.delete_message_confirm": "Ви впевнені, що хочете видалити це повідомлення?", "chat.retrieving-users": "Отримання користувачів...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Управління чат кімнатами", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Шукайте користувачів тут. Користувача можна додати до чату, обравши його. Нові користувачі не можуть бачити повідомлення, написані до того, як їх додали до розмови. Тільки власники кімнат можуть видаляти користувачів з кімнат.", "chat.confirm-chat-with-dnd-user": "Користувач змінив свій статус на DnD (Не турбувати). Ви дійсно бажаєте надіслати йому повідомлення в чат?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Перейменувати Кімнату", "chat.rename-placeholder": "Введіть назву своєї кімнати тут", "chat.rename-help": "Назва кімнати, яку буде встановлено тут, буде доступна для перегляду всіма учасниками в кімнаті.", - "chat.leave": "Залишити чат", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Ви впевнені, що хочете залишити цей чат?", "chat.leave-help": "Залишивши цей чат, ви видалите вас із майбутньої кореспонденції у цьому чаті. Якщо ви знову будете додані в майбутньому, ви не побачите жодної історії чату перед тим, як знову приєднатися.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "У цій кімнаті", "chat.kick": "Штурхнути", "chat.show-ip": "Показати IP", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index db16e2ffa8..9174a7c3a3 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -199,6 +199,7 @@ "not-in-room": "Thành viên không có trong phòng", "cant-kick-self": "Bạn không thể loại mình khỏi nhóm", "no-users-selected": "Chưa có người dùng(s) nào", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "Đường dẫn trang chủ không hợp lệ", "invalid-session": "Phiên Không Hợp Lệ", "invalid-session-text": "Có vẻ như phiên đăng nhập của bạn không còn hoạt động. Vui lòng làm mới trang này.", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 5c5b1812bc..3eefa5fd2d 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3 tháng", "chat.delete_message_confirm": "Bạn có chắc muốn xoá tin nhắn này không?", "chat.retrieving-users": "Đang truy xuất người dùng...", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Quản Lý Phòng Trò Chuyện", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "Tìm người dùng ở đây. Người dùng được chọn sẽ được thêm vào trò chuyện. Người dùng mới sẽ không thấy tin nhắn trò chuyện được đăng trước khi họ được thêm vào. Chỉ chủ phòng () được xóa người dùng khỏi phòng trò chuyện.", "chat.confirm-chat-with-dnd-user": "Người dùng này đã đặt trạng thái của họ thành DnD (Không làm phiền). Bạn vẫn muốn trò chuyện với họ?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "Đổi Tên Phòng", "chat.rename-placeholder": "Nhập tên phòng của bạn ở đây", "chat.rename-help": "Đẳt tên phòng ở đây, tất cả những người tham gia phòng này có thể xem.", - "chat.leave": "Rời Khỏi Trò Chuyện", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "Bạn có chắc chắn muốn rời khỏi cuộc trò chuyện này không?", "chat.leave-help": "Rời khỏi cuộc trò chuyện này sẽ xóa các tin nhắn của bạn trong cuộc trò chuyện này. Nếu bạn được thêm lại trong tương lai, bạn sẽ không thấy bất kỳ lịch sử trò chuyện nào từ trước khi bạn tham gia lại.", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "Trong phòng này", "chat.kick": "Loại ra", "chat.show-ip": "Hiện IP", diff --git a/public/language/zh-CN/error.json b/public/language/zh-CN/error.json index a1df0db9e5..0e839521c0 100644 --- a/public/language/zh-CN/error.json +++ b/public/language/zh-CN/error.json @@ -199,6 +199,7 @@ "not-in-room": "用户已不在聊天室中", "cant-kick-self": "您不能把自己踢出群组", "no-users-selected": "尚未选择用户", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "无效的首页路径", "invalid-session": "无效的会话", "invalid-session-text": "您的登录会话似乎不再处于活动状态。请刷新此页面。", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index c7ce0d5e37..b1f6f7ad8c 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3个月", "chat.delete_message_confirm": "您确定您要删除此消息吗?", "chat.retrieving-users": "查找用户", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "管理聊天室", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "在这里查找更多用户。被选中的用户会被添加到聊天中。新用户不能他们被加入对话前的聊天消息。只有聊天室所有者()可以从聊天室中移除用户。", "chat.confirm-chat-with-dnd-user": "该用户已将其状态设置为 DnD(请勿打扰)。 您仍希望与其聊天吗?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "重命名房间", "chat.rename-placeholder": "在这里输入房间名字", "chat.rename-help": "这里设置的房间名字能够被房间内所有人都看到。", - "chat.leave": "离开聊天室", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "您确定您要离开聊天室?", "chat.leave-help": "离开此聊天会切断您和此聊天以后的联系。如果您未来重新加入了,您将不能看到您重新加入之前的聊天记录。", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "在此房间", "chat.kick": "踢出", "chat.show-ip": "显示 IP", diff --git a/public/language/zh-TW/error.json b/public/language/zh-TW/error.json index a7f3a3fb44..a13bcec151 100644 --- a/public/language/zh-TW/error.json +++ b/public/language/zh-TW/error.json @@ -199,6 +199,7 @@ "not-in-room": "使用者已不在聊天室中", "cant-kick-self": "您不能把自己踢出群組", "no-users-selected": "尚未選擇使用者", + "no-groups-selected": "No group(s) selected", "invalid-home-page-route": "無效的首頁路徑", "invalid-session": "Invalid Session", "invalid-session-text": "It looks like your login session is no longer active. Please refresh this page.", diff --git a/public/language/zh-TW/modules.json b/public/language/zh-TW/modules.json index f20afdb943..37e0d91642 100644 --- a/public/language/zh-TW/modules.json +++ b/public/language/zh-TW/modules.json @@ -27,15 +27,29 @@ "chat.three_months": "3個月", "chat.delete_message_confirm": "您確定刪除此訊息嗎?", "chat.retrieving-users": "搜尋使用者", + "chat.view-users-list": "View users list", + "chat.public-rooms": "Public Rooms (%1)", + "chat.private-rooms": "Private Rooms (%1)", + "chat.create-room": "Create Chat Room", + "chat.private.option": "Private (Only visible to users added to room)", + "chat.public.option": "Public (Visible to every user in selected groups)", + "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "管理聊天室", + "chat.add-user": "Add User", + "chat.select-groups": "Select Groups", "chat.add-user-help": "在這裡搜尋更多使用者。選中之後加入到聊天中,新使用者在加入聊天之前看不到聊天訊息。只有聊天室所有者()可以從聊天室中移除使用者。", "chat.confirm-chat-with-dnd-user": "該使用者已將其狀態設置為 DnD(請勿打擾)。 您仍希望與其聊天嗎?", + "chat.room-name-optional": "Room Name (Optional)", "chat.rename-room": "重新命名房間", "chat.rename-placeholder": "在這裡輸入房間名字", "chat.rename-help": "這裡設定的房間名字能夠被房間內所有人都看到。", - "chat.leave": "離開聊天室", + "chat.leave": "Leave", + "chat.leave-room": "Leave Room", "chat.leave-prompt": "您確定要離開聊天室?", "chat.leave-help": "離開此聊天會將您在聊天中的未接收的訊息移除。您在重新加入之後不會看到任何聊天記錄", + "chat.delete": "Delete", + "chat.delete-room": "Delete Room", + "chat.delete-prompt": "Are you sure you wish to delete this chat room?", "chat.in-room": "在此房間", "chat.kick": "踢出", "chat.show-ip": "顯示 IP", From b2cabd431e36bca8d1910adc454179515ea1d745 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:08:17 -0400 Subject: [PATCH 038/300] fix(deps): update dependency ace-builds to v1.23.4 (#11782) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a6c3bba32c..be3b53c852 100644 --- a/install/package.json +++ b/install/package.json @@ -33,7 +33,7 @@ "@fontsource/poppins": "5.0.4", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", - "ace-builds": "1.23.1", + "ace-builds": "1.23.4", "archiver": "5.3.1", "async": "3.2.4", "autoprefixer": "10.4.14", From bb89a12a5e49c477ad79ef90883a659105e55931 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:08:29 -0400 Subject: [PATCH 039/300] fix(deps): update dependency jsonwebtoken to v9.0.1 (#11778) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index be3b53c852..5edad10bb5 100644 --- a/install/package.json +++ b/install/package.json @@ -79,7 +79,7 @@ "jquery-ui": "1.13.2", "jsesc": "3.0.2", "json2csv": "5.0.7", - "jsonwebtoken": "9.0.0", + "jsonwebtoken": "9.0.1", "less": "4.1.3", "lodash": "4.17.21", "logrotate-stream": "0.2.9", From 7fb8e414051792953f1dfd9d231b6da029f2aca8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:08:39 -0400 Subject: [PATCH 040/300] fix(deps): update dependency postcss to v8.4.25 (#11780) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 5edad10bb5..f024f1fe88 100644 --- a/install/package.json +++ b/install/package.json @@ -113,7 +113,7 @@ "passport-local": "1.0.0", "pg": "8.11.1", "pg-cursor": "2.10.1", - "postcss": "8.4.24", + "postcss": "8.4.25", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0", From 833a1ba7d6df748baf29e32c181c4e1c81538844 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:08:54 -0400 Subject: [PATCH 041/300] fix(deps): update dependency mongodb to v5.7.0 (#11781) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f024f1fe88..68fdf60fb1 100644 --- a/install/package.json +++ b/install/package.json @@ -86,7 +86,7 @@ "lru-cache": "10.0.0", "mime": "3.0.0", "mkdirp": "3.0.1", - "mongodb": "5.6.0", + "mongodb": "5.7.0", "morgan": "1.10.0", "mousetrap": "1.6.5", "multiparty": "4.2.3", From 3bf10941c1f933c34bbe6834eb26eddaf5f3256a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:09:05 -0400 Subject: [PATCH 042/300] fix(deps): update dependency semver to v7.5.4 (#11783) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 68fdf60fb1..50a92e56be 100644 --- a/install/package.json +++ b/install/package.json @@ -125,7 +125,7 @@ "rtlcss": "4.1.0", "sanitize-html": "2.11.0", "sass": "1.63.6", - "semver": "7.5.3", + "semver": "7.5.4", "serve-favicon": "2.5.0", "sharp": "0.32.1", "sitemap": "7.1.1", From 50fd242b694d620f80ccddbb8fd29857df3b0238 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:09:30 -0400 Subject: [PATCH 043/300] fix(deps): update dependency compare-versions to v6 (#11784) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 50a92e56be..826e75ce34 100644 --- a/install/package.json +++ b/install/package.json @@ -49,7 +49,7 @@ "clipboard": "2.0.11", "colors": "1.4.0", "commander": "11.0.0", - "compare-versions": "5.0.3", + "compare-versions": "6.0.0", "compression": "1.7.4", "connect-flash": "0.1.1", "connect-mongo": "5.0.0", From efd784fa5fb521fb6d487905fbdd9b6021eb2db0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:09:46 -0400 Subject: [PATCH 044/300] fix(deps): update fontsource monorepo to v5.0.5 (#11785) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 826e75ce34..6201cd2558 100644 --- a/install/package.json +++ b/install/package.json @@ -29,8 +29,8 @@ }, "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", - "@fontsource/inter": "5.0.4", - "@fontsource/poppins": "5.0.4", + "@fontsource/inter": "5.0.5", + "@fontsource/poppins": "5.0.5", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", "ace-builds": "1.23.4", From 40477c85d54693088b2ef4f3fddecf0670c7a8d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:19:19 -0400 Subject: [PATCH 045/300] chore(deps): update redis docker tag to v7.0.12 (#11789) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3e7d8120be..f68e3b98cd 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -65,7 +65,7 @@ jobs: - 5432:5432 redis: - image: 'redis:7.0.11' + image: 'redis:7.0.12' # Set health checks to wait until redis has started options: >- --health-cmd "redis-cli ping" From 3c5e5d3ed7c58254ceb665d99f0fb87788b7ffb5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:19:37 -0400 Subject: [PATCH 046/300] fix(deps): update dependency nodebb-plugin-ntfy to v1.0.16 (#11790) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 6201cd2558..ab9dd3b988 100644 --- a/install/package.json +++ b/install/package.json @@ -98,7 +98,7 @@ "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.5", "nodebb-plugin-mentions": "4.2.0", - "nodebb-plugin-ntfy": "1.0.15", + "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.0.66", From d156e67e9a506285f47fc1241abdb7af1683d79d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:21:06 -0400 Subject: [PATCH 047/300] fix(deps): update dependency sharp to v0.32.2 (#11791) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ab9dd3b988..1ee4c2085c 100644 --- a/install/package.json +++ b/install/package.json @@ -127,7 +127,7 @@ "sass": "1.63.6", "semver": "7.5.4", "serve-favicon": "2.5.0", - "sharp": "0.32.1", + "sharp": "0.32.2", "sitemap": "7.1.1", "slideout": "1.0.1", "socket.io": "4.7.1", From 786fff6f5c3e1337b8180048f80762f02f5ecc47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:12:41 -0400 Subject: [PATCH 048/300] fix(deps): update dependency winston to v3.10.0 (#11792) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 1ee4c2085c..db554352b6 100644 --- a/install/package.json +++ b/install/package.json @@ -145,7 +145,7 @@ "validator": "13.9.0", "webpack": "5.88.1", "webpack-merge": "5.9.0", - "winston": "3.9.0", + "winston": "3.10.0", "xml": "1.0.1", "xregexp": "5.1.1", "yargs": "17.7.2", From 9fda8dcec493a7fdbe4fe4c3813c8f59ffc5e195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 15:35:40 -0400 Subject: [PATCH 049/300] chore: up themes --- install/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/package.json b/install/package.json index a6c3bba32c..6a3c798e3b 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.0.15", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.0.66", + "nodebb-theme-harmony": "1.1.0", "nodebb-theme-lavender": "7.1.1", - "nodebb-theme-peace": "2.0.32", - "nodebb-theme-persona": "13.1.8", + "nodebb-theme-peace": "2.1.0", + "nodebb-theme-persona": "13.2.0", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From 547bde893905877faf938909a3edbe847d8f066b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 16:35:46 -0400 Subject: [PATCH 050/300] cache fixes on newRoom and deleteRooms clear cache add some checks for empty groups list --- public/src/client/chats/create.js | 25 +++++++++++++------------ src/api/chats.js | 3 +++ src/messaging/index.js | 9 ++++++++- src/messaging/rooms.js | 23 ++++++++++++++++++----- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/public/src/client/chats/create.js b/public/src/client/chats/create.js index 9f532f020d..4c76248a16 100644 --- a/public/src/client/chats/create.js +++ b/public/src/client/chats/create.js @@ -26,7 +26,7 @@ define('forum/chats/create', [ save: { label: '[[global:create]]', className: 'btn-primary', - callback: async function () { + callback: function () { const roomName = modal.find('[component="chat/room/name"]').val(); const uids = modal.find('[component="chat/room/users"] [component="chat/user"]').find('[data-uid]').map( (i, el) => $(el).attr('data-uid') @@ -38,16 +38,25 @@ define('forum/chats/create', [ alerts.error('[[error:no-users-selected]]'); return false; } - if (type === 'public' && !groups) { + if (type === 'public' && !groups.length) { alerts.error('[[error:no-groups-selected]]'); return false; } - await createRoom({ + if (!app.user.uid) { + alerts.error('[[error:not-logged-in]]'); + return false; + } + + api.post(`/chats`, { roomName: roomName, uids: uids, type: type, groups: groups, - }); + }).then(({ roomId }) => { + ajaxify.go('chats/' + roomId); + modal.modal('hide'); + }).catch(alerts.error); + return false; }, }, }, @@ -73,13 +82,5 @@ define('forum/chats/create', [ }); } - async function createRoom(params) { - if (!app.user.uid) { - return alerts.error('[[error:not-logged-in]]'); - } - const { roomId } = await api.post(`/chats`, params); - ajaxify.go('chats/' + roomId); - } - return create; }); diff --git a/src/api/chats.js b/src/api/chats.js index 835117e235..a2d2e3467f 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -52,6 +52,9 @@ chatsAPI.create = async function (caller, data) { if (!isPublic && !data.uids.length) { throw new Error('[[error:no-users-selected]]'); } + if (isPublic && (!Array.isArray(data.groups) || !data.groups.length)) { + throw new Error('[[error:no-groups-selected]]'); + } await Promise.all(data.uids.map(async uid => messaging.canMessageUser(caller.uid, uid))); const roomId = await messaging.newRoom(caller.uid, data); diff --git a/src/messaging/index.js b/src/messaging/index.js index faede05c4e..fb87dd07a8 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -125,8 +125,15 @@ Messaging.getPublicRooms = async (callerUid, uid) => { const allRoomIds = await Messaging.getPublicRoomIdsFromSet('chat:rooms:public:order'); const allRoomData = await Messaging.getRoomsData(allRoomIds); + console.log(allRoomIds, allRoomData); const checks = await Promise.all( - allRoomData.map(room => groups.isMemberOfAny(uid, room && room.groups)) + allRoomData.map( + room => room && ( + !Array.isArray(room.groups) || + !room.groups.length || + groups.isMemberOfAny(uid, room && room.groups) + ) + ) ); const roomData = allRoomData.filter((room, idx) => room && checks[idx]); const roomIds = roomData.map(r => r.roomId); diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 54edfe3150..93f1635f25 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -10,9 +10,10 @@ const groups = require('../groups'); const plugins = require('../plugins'); const privileges = require('../privileges'); const meta = require('../meta'); +const cache = require('../cache'); const cacheCreate = require('../cacheCreate'); -const cache = cacheCreate({ +const roomUidCache = cacheCreate({ name: 'chat:room:uids', max: 500, ttl: 0, @@ -104,6 +105,11 @@ module.exports = function (Messaging) { Messaging.addRoomToUsers(roomId, [uid].concat(data.uids), now), ]); + cache.del([ + 'chat:rooms:public:all', + 'chat:rooms:public:order:all', + ]); + if (!isPublic) { // chat owner should also get the user-join system message await Messaging.addSystemMessage('user-join', uid, roomId); @@ -136,6 +142,11 @@ module.exports = function (Messaging) { db.deleteAll(roomIds.map(id => `chat:room:${id}`)), db.sortedSetRemove('chat:rooms', roomIds), db.sortedSetRemove('chat:rooms:public', roomIds), + db.sortedSetRemove('chat:rooms:public:order', roomIds), + ]); + cache.del([ + 'chat:rooms:public:all', + 'chat:rooms:public:order:all', ]); }; @@ -252,7 +263,7 @@ module.exports = function (Messaging) { ...groupChats.map(id => [`chat:room:${id}`, { groupChat: 1, userCount: countMap[id] }]), ...privateChats.map(id => [`chat:room:${id}`, { groupChat: 0, userCount: countMap[id] }]), ]); - cache.del(roomIds.map(id => `chat:room:${id}:users`)); + roomUidCache.del(roomIds.map(id => `chat:room:${id}:users`)); } Messaging.leaveRoom = async (uids, roomId) => { @@ -301,12 +312,12 @@ module.exports = function (Messaging) { Messaging.getAllUidsInRoom = async function (roomId) { const cacheKey = `chat:room:${roomId}:users`; - let uids = cache.get(cacheKey); + let uids = roomUidCache.get(cacheKey); if (uids !== undefined) { return uids; } uids = await Messaging.getUidsInRoom(roomId, 0, -1); - cache.set(cacheKey, uids); + roomUidCache.set(cacheKey, uids); return uids; }; @@ -373,7 +384,9 @@ module.exports = function (Messaging) { } if (!room || (!room.public && !inRoom) || - (room.public && !(await groups.isMemberOfAny(uid, room.groups))) + (room.public && ( + Array.isArray(room.groups) && room.groups.length && !(await groups.isMemberOfAny(uid, room.groups))) + ) ) { return null; } From e03fdcd6fc1a2dbd6cb4b307f8748fd522163d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 16:49:55 -0400 Subject: [PATCH 051/300] fix: clear cache on sort --- src/socket.io/modules.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index f98b7052a8..809fe8fafa 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -125,6 +125,7 @@ SocketModules.chats.sortPublicRooms = async function (socket, data) { throw new Error('[[error:no-privileges]]'); } await db.sortedSetAdd(`chat:rooms:public:order`, data.scores, data.roomIds); + require('../cache').del(`chat:rooms:public:order:all`); }; SocketModules.chats.searchMembers = async function (socket, data) { From 954db1ee1936c515a19ae4e307f59098e7e49833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 17:07:58 -0400 Subject: [PATCH 052/300] chore: remove log --- src/messaging/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/messaging/index.js b/src/messaging/index.js index fb87dd07a8..7df98c0afc 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -125,7 +125,6 @@ Messaging.getPublicRooms = async (callerUid, uid) => { const allRoomIds = await Messaging.getPublicRoomIdsFromSet('chat:rooms:public:order'); const allRoomData = await Messaging.getRoomsData(allRoomIds); - console.log(allRoomIds, allRoomData); const checks = await Promise.all( allRoomData.map( room => room && ( From 9149a9a2cbc0fff3ed48330848cae428548b82ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 17:13:07 -0400 Subject: [PATCH 053/300] fix: mobile back button --- public/src/client/chats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index c19773ecbb..d812e81cb0 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -462,7 +462,7 @@ define('forum/chats', [ mainWrapper.html(html); chatNavWrapper = $('[component="chat/nav-wrapper"]'); html.find('.timeago').timeago(); - ajaxify.data = { ...ajaxify.data, ...payload }; + ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomid }; $('body').addClass(ajaxify.data.bodyClass); mainWrapper.find('[data-bs-toggle="tooltip"]').tooltip(); Chats.setActive(); From 4782764aeead5174734461ef9c05201f03ccbb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 19:36:30 -0400 Subject: [PATCH 054/300] fix mobile mobile bar fix user count if user just joined --- public/src/client/chats.js | 32 ++++++++++++++++---------------- src/messaging/rooms.js | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index d812e81cb0..f570c7cf8d 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -50,7 +50,7 @@ define('forum/chats', [ recentChats.init(); Chats.addEventListeners(); - Chats.setActive(); + Chats.setActive(ajaxify.data.roomId); if (env === 'md' || env === 'lg' || env === 'xl' || env === 'xxl') { Chats.addHotkeys(); @@ -437,20 +437,20 @@ define('forum/chats', [ }).catch(alerts.error); }; - Chats.switchChat = function (roomid) { + Chats.switchChat = function (roomId) { // Allow empty arg for return to chat list/close chat - if (!roomid) { - roomid = ''; + if (!roomId) { + roomId = ''; } Chats.destroyAutoComplete(ajaxify.data.roomId); socket.emit('modules.chats.leave', ajaxify.data.roomId); - const url = 'user/' + ajaxify.data.userslug + '/chats/' + roomid + window.location.search; + const url = 'user/' + ajaxify.data.userslug + '/chats/' + roomId + window.location.search; if (!self.fetch) { return ajaxify.go(url); } const params = new URL(document.location).searchParams; params.set('switch', 1); - const dataUrl = `${config.relative_path}/api/user/${ajaxify.data.userslug}/chats/${roomid}?${params.toString()}`; + const dataUrl = `${config.relative_path}/api/user/${ajaxify.data.userslug}/chats/${roomId}?${params.toString()}`; fetch(dataUrl, { credentials: 'include' }) .then(async function (response) { if (!response.ok) { @@ -462,10 +462,10 @@ define('forum/chats', [ mainWrapper.html(html); chatNavWrapper = $('[component="chat/nav-wrapper"]'); html.find('.timeago').timeago(); - ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomid }; - $('body').addClass(ajaxify.data.bodyClass); + ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomId }; + $('body').toggleClass('chat-loaded', !!roomId); mainWrapper.find('[data-bs-toggle="tooltip"]').tooltip(); - Chats.setActive(); + Chats.setActive(roomId); Chats.addEventListeners(); hooks.fire('action:chat.loaded', $('.chats-full')); messages.scrollToBottom(mainWrapper.find('.expanded-chat ul.chat-content')); @@ -566,24 +566,24 @@ define('forum/chats', [ unreadCountEl.toggleClass('hidden', count <= 0).text(countText).attr('data-count', count); }; - Chats.setActive = function () { + Chats.setActive = function (roomId) { chatNavWrapper.find('[data-roomid]').removeClass('active'); - if (ajaxify.data.roomId) { - socket.emit('modules.chats.enter', ajaxify.data.roomId); - const chatEl = chatNavWrapper.find(`[data-roomid="${ajaxify.data.roomId}"]`); + if (roomId) { + socket.emit('modules.chats.enter', roomId); + const chatEl = chatNavWrapper.find(`[data-roomid="${roomId}"]`); chatEl.addClass('active'); if (chatEl.hasClass('unread')) { - api.del(`/chats/${ajaxify.data.roomId}/state`, {}); + api.del(`/chats/${roomId}/state`, {}); chatEl.removeClass('unread'); } if (!utils.isMobile()) { $('.expanded-chat [component="chat/input"]').focus(); } - messages.updateTextAreaHeight($(`[component="chat/messages"][data-roomid="${ajaxify.data.roomId}"]`)); + messages.updateTextAreaHeight($(`[component="chat/messages"][data-roomid="${roomId}"]`)); } - chatNavWrapper.attr('data-loaded', ajaxify.data.roomId ? '1' : '0'); + chatNavWrapper.attr('data-loaded', roomId ? '1' : '0'); }; return Chats; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 93f1635f25..f189b39401 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -394,6 +394,7 @@ module.exports = function (Messaging) { // add user to public room onload if (room.public && !inRoom) { await addUidsToRoom([uid], roomId); + room.userCount += 1; } const [canReply, users, messages, isAdmin, isGlobalMod, settings, isOwner] = await Promise.all([ From 43060f3cde45aa98d426cc0311efc958ba23e537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 19:54:46 -0400 Subject: [PATCH 055/300] perf: faster upgrade script --- src/upgrades/3.3.0/chat_room_refactor.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/upgrades/3.3.0/chat_room_refactor.js b/src/upgrades/3.3.0/chat_room_refactor.js index 9b3337fc3c..7c008a9764 100644 --- a/src/upgrades/3.3.0/chat_room_refactor.js +++ b/src/upgrades/3.3.0/chat_room_refactor.js @@ -21,12 +21,14 @@ module.exports = { progress.total = allRoomIds.length; await batch.processArray(allRoomIds, async (roomIds) => { progress.incr(roomIds.length); - await Promise.all(roomIds.map(async (roomId) => { - const [uids, roomData] = await Promise.all([ - db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, -1), - db.getObject(`chat:room:${roomId}`), - ]); + const [arrayOfUids, arrayOfRoomData] = await Promise.all([ + db.getSortedSetsMembers(roomIds.map(roomId => `chat:room:${roomId}:uids`)), + db.getObjects(roomIds.map(roomId => `chat:room:${roomId}`)), + ]); + await Promise.all(roomIds.map(async (roomId, index) => { + const uids = arrayOfUids[index]; + const roomData = arrayOfRoomData[index]; if (!uids.length && !roomData) { return; } From 2f8c301abaf5b0c4c80785723dab5ddb4727cfb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 20:43:53 -0400 Subject: [PATCH 056/300] fix groups reference --- src/socket.io/modules.js | 5 +++-- src/topics/sorted.js | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 809fe8fafa..559bbdd5be 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -7,6 +7,7 @@ const Messaging = require('../messaging'); const utils = require('../utils'); const user = require('../user'); const privileges = require('../privileges'); +const groups = require('../groups'); const SocketModules = module.exports; @@ -108,8 +109,8 @@ async function joinLeave(socket, roomIds, method, prefix = 'chat_room') { await Promise.all(roomIds.map(async (roomId, idx) => { const isPublic = roomData[idx] && roomData[idx].public; - const groups = roomData[idx] && roomData[idx].groups; - if (isAdmin || (inRooms[idx] && (!isPublic || await groups.isMemberOfAny(socket.uid, groups)))) { + const roomGroups = roomData[idx] && roomData[idx].groups; + if (isAdmin || (inRooms[idx] && (!isPublic || await groups.isMemberOfAny(socket.uid, roomGroups)))) { socket[method](`${prefix}_${roomId}`); } })); diff --git a/src/topics/sorted.js b/src/topics/sorted.js index 7899a2f8d0..a1d809fb48 100644 --- a/src/topics/sorted.js +++ b/src/topics/sorted.js @@ -112,7 +112,9 @@ module.exports = function (Topics) { if (params.term === 'alltime' && !params.cids && !params.tags.length && params.filter !== 'watched' && !params.floatPinned) { return tids; } - const topicData = await Topics.getTopicsFields(tids, ['tid', 'lastposttime', 'upvotes', 'downvotes', 'postcount', 'pinned']); + const topicData = await Topics.getTopicsFields(tids, [ + 'tid', 'lastposttime', 'upvotes', 'downvotes', 'postcount', 'pinned', + ]); const sortMap = { recent: sortRecent, old: sortOld, From f8e30c6d52cbef9f8a8fad2505844661820d4f47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 21:13:11 -0400 Subject: [PATCH 057/300] add icon to rooms based on visibility --- src/messaging/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/messaging/index.js b/src/messaging/index.js index 7df98c0afc..4c6d280aaf 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -134,6 +134,7 @@ Messaging.getPublicRooms = async (callerUid, uid) => { ) ) ); + const roomData = allRoomData.filter((room, idx) => room && checks[idx]); const roomIds = roomData.map(r => r.roomId); const userReadTimestamps = await db.getObjectFields( @@ -149,12 +150,16 @@ Messaging.getPublicRooms = async (callerUid, uid) => { ); return unreadMids.length; })); - + const globalUserGroups = [ + 'registered-users', 'verified-users', 'unverified-users', 'banned-users', + ]; roomData.forEach((r, idx) => { const count = unreadCounts[idx]; r.unreadCountText = count > maxUnread ? `${maxUnread}+` : String(count); r.unreadCount = count; r.unread = count > 0; + const hasGroups = Array.isArray(r.groups) && r.groups.length; + r.icon = !hasGroups || r.groups.some(group => globalUserGroups.includes(group)) ? 'fa-hashtag' : 'fa-lock'; }); return roomData; From 624292524f4d055136c253a7bc02d01837a92c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 21:15:01 -0400 Subject: [PATCH 058/300] chore: up themes --- install/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/package.json b/install/package.json index ac081a4cf0..ce8f4268a1 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.0", + "nodebb-theme-harmony": "1.1.1", "nodebb-theme-lavender": "7.1.1", - "nodebb-theme-peace": "2.1.0", - "nodebb-theme-persona": "13.2.0", + "nodebb-theme-peace": "2.1.1", + "nodebb-theme-persona": "13.2.1", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From 857fe16878a5e754531fb2eed8c622c9cf750206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 21:20:30 -0400 Subject: [PATCH 059/300] use same code in load room --- src/messaging/index.js | 7 ++----- src/messaging/rooms.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/messaging/index.js b/src/messaging/index.js index 4c6d280aaf..ec41f84cae 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -150,16 +150,13 @@ Messaging.getPublicRooms = async (callerUid, uid) => { ); return unreadMids.length; })); - const globalUserGroups = [ - 'registered-users', 'verified-users', 'unverified-users', 'banned-users', - ]; + roomData.forEach((r, idx) => { const count = unreadCounts[idx]; r.unreadCountText = count > maxUnread ? `${maxUnread}+` : String(count); r.unreadCount = count; r.unread = count > 0; - const hasGroups = Array.isArray(r.groups) && r.groups.length; - r.icon = !hasGroups || r.groups.some(group => globalUserGroups.includes(group)) ? 'fa-hashtag' : 'fa-lock'; + r.icon = Messaging.getRoomIcon(r); }); return roomData; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index f189b39401..c38ba02e5f 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -417,6 +417,7 @@ module.exports = function (Messaging) { room.users = users; room.canReply = canReply; room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : users.length > 2; + room.icon = Messaging.getRoomIcon(room); room.usernames = Messaging.generateUsernames(users, uid); room.chatWithMessage = await Messaging.generateChatWithMessage(users, uid, settings.userLang); room.maximumUsersInChatRoom = meta.config.maximumUsersInChatRoom; @@ -428,4 +429,13 @@ module.exports = function (Messaging) { const payload = await plugins.hooks.fire('filter:messaging.loadRoom', { uid, data, room }); return payload.room; }; + + const globalUserGroups = [ + 'registered-users', 'verified-users', 'unverified-users', 'banned-users', + ]; + + Messaging.getRoomIcon = function (roomData) { + const hasGroups = Array.isArray(roomData.groups) && roomData.groups.length; + return !hasGroups || roomData.groups.some(group => globalUserGroups.includes(group)) ? 'fa-hashtag' : 'fa-lock'; + }; }; From f287e1323d49333fa82076d8ed21719bb026ad8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 21:23:17 -0400 Subject: [PATCH 060/300] spec --- public/openapi/read/user/userslug/chats/roomid.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index 4f8b26e6a4..278f20edbf 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -34,6 +34,8 @@ get: type: boolean userCount: type: number + icon: + type: string timestamp: type: number description: Timestamp of when room was created From b36bec95e4842e7dc1fec467120732505ee97fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 12 Jul 2023 21:24:22 -0400 Subject: [PATCH 061/300] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index ce8f4268a1..4a7407728b 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.1", + "nodebb-theme-harmony": "1.1.2", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.1.1", - "nodebb-theme-persona": "13.2.1", + "nodebb-theme-persona": "13.2.2", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From c1f062ebd94f9cce4e3807eb296c7f1f273e630f Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Thu, 13 Jul 2023 09:19:13 +0000 Subject: [PATCH 062/300] Latest translations and fallbacks --- public/language/bg/error.json | 2 +- public/language/bg/modules.json | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/public/language/bg/error.json b/public/language/bg/error.json index b1c1e84a67..db3ff05838 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -199,7 +199,7 @@ "not-in-room": "Потребителят не е в стаята", "cant-kick-self": "Не можете да изритате себе си от групата", "no-users-selected": "Няма избран(и) потребител(и)", - "no-groups-selected": "No group(s) selected", + "no-groups-selected": "Няма избрана/и група/и", "invalid-home-page-route": "Грешен път към началната страница", "invalid-session": "Изтекла сесия", "invalid-session-text": "Изглежда сесията Ви на вписване вече е изтекла. Моля, опреснете страницата.", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 18d434156a..da07e9a1b4 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -27,29 +27,29 @@ "chat.three_months": "3 месеца", "chat.delete_message_confirm": "Наистина ли искате да изтриете това съобщение?", "chat.retrieving-users": "Получаване на потребителите…", - "chat.view-users-list": "View users list", - "chat.public-rooms": "Public Rooms (%1)", - "chat.private-rooms": "Private Rooms (%1)", - "chat.create-room": "Create Chat Room", - "chat.private.option": "Private (Only visible to users added to room)", - "chat.public.option": "Public (Visible to every user in selected groups)", - "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", + "chat.view-users-list": "Преглед на списъка с потребители", + "chat.public-rooms": "Публични стаи (%1)", + "chat.private-rooms": "Частни стаи (%1)", + "chat.create-room": "Създаване на стая за разговор", + "chat.private.option": "Частна (видима само за потребителите добавени в стаята)", + "chat.public.option": "Публична (видима за всички в избраните групи)", + "chat.public.groups-help": "За да създадете стая за разговор видима за всички потребители изберете групата с регистрирани потребители от списъка.", "chat.manage-room": "Управление на стаята за разговори", - "chat.add-user": "Add User", - "chat.select-groups": "Select Groups", + "chat.add-user": "Добавяне на потребител", + "chat.select-groups": "Избиране на групи", "chat.add-user-help": "Тук можете да потърсите потребители. Когато някой потребител бъде избран, той ще бъде добавен в разговора. Новият потребител няма да може да вижда съобщенията, написани преди включването му в разговора. Само собствениците на стаята () могат да премахват потребители от нея.", "chat.confirm-chat-with-dnd-user": "Този потребител е в състояние „не ме безпокойте“. Наистина ли искате да разговаряте с него?", - "chat.room-name-optional": "Room Name (Optional)", + "chat.room-name-optional": "Име на стаята (незадължително)", "chat.rename-room": "Преименуване на стаята", "chat.rename-placeholder": "Въведете името на стаята си тук", "chat.rename-help": "Зададеното тук име на стаята ще се вижда от всички участници в нея.", - "chat.leave": "Leave", - "chat.leave-room": "Leave Room", + "chat.leave": "Напускане", + "chat.leave-room": "Напускане на стаята", "chat.leave-prompt": "Наистина ли искате да напуснете този разговор?", "chat.leave-help": "Ако напуснете този разговор, няма да виждате следващите съобщения в него. Ако бъдете добавен(а) отново, няма да виждате историята на разговора отпреди добавянето Ви.", - "chat.delete": "Delete", - "chat.delete-room": "Delete Room", - "chat.delete-prompt": "Are you sure you wish to delete this chat room?", + "chat.delete": "Изтриване", + "chat.delete-room": "Изтриване на стаята", + "chat.delete-prompt": "Наистина ли искате да изтриете тази стая за разговор?", "chat.in-room": "В тази стая", "chat.kick": "Изгонване", "chat.show-ip": "Показване на IP адреса", From 5c2086107efc65a863d1774c7b8d9ab2a053c644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 11:31:56 -0400 Subject: [PATCH 063/300] fix: always return empty array if its not set --- src/messaging/rooms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index c38ba02e5f..300f928e86 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -53,9 +53,9 @@ module.exports = function (Messaging) { data.groupChat = parseInt(data.groupChat, 10) === 1; } - if (data.hasOwnProperty('groups')) { + if (data.hasOwnProperty('groups') || !fields.length || fields.includes('groups')) { try { - data.groups = JSON.parse(data.groups); + data.groups = JSON.parse(data.groups || '[]'); } catch (err) { winston.error(err.stack); data.groups = []; From d545c1432fe6555b446ff62cd61dddc0e4b8363a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 11:35:14 -0400 Subject: [PATCH 064/300] chore: up mentions --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 4a7407728b..6565c5e73c 100644 --- a/install/package.json +++ b/install/package.json @@ -97,7 +97,7 @@ "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.5", - "nodebb-plugin-mentions": "4.2.0", + "nodebb-plugin-mentions": "4.3.0", "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", From f15265ffbcd76bcd2bae4b0229ca99624df0dac5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:36:07 -0400 Subject: [PATCH 065/300] fix(deps): update dependency esbuild to v0.18.12 (#11794) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 6565c5e73c..8d03797c9b 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.11", + "esbuild": "0.18.12", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From adfde1d4e100b7aa823007659d4df81dd5a10432 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:36:16 -0400 Subject: [PATCH 066/300] chore(deps): update coverallsapp/github-action action to v2.2.1 (#11795) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f68e3b98cd..f5064f709d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -194,7 +194,7 @@ jobs: run: npm run coverage - name: Test coverage - uses: coverallsapp/github-action@v2.2.0 + uses: coverallsapp/github-action@v2.2.1 if: matrix.coverage with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -208,7 +208,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Coveralls Finished - uses: coverallsapp/github-action@v2.2.0 + uses: coverallsapp/github-action@v2.2.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true From b63cd548124dfe3fa2a240cd70aa8135e55442d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 11:41:20 -0400 Subject: [PATCH 067/300] test: fix spec --- public/openapi/components/schemas/Chats.yaml | 3 +++ public/openapi/read/user/userslug/chats/roomid.yaml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 7f8f1b8b85..1d21c26343 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -19,6 +19,9 @@ RoomObject: userCount: type: number description: number of users in this chat room + groups: + type: array + description: list of groups that can access the room timestamp: type: number description: Timestamp of when room was created diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index 278f20edbf..d776512925 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -36,6 +36,8 @@ get: type: number icon: type: string + groups: + type: array timestamp: type: number description: Timestamp of when room was created @@ -181,6 +183,8 @@ get: type: boolean userCount: type: number + groups: + type: array timestamp: type: number description: Timestamp of when room was created From 265d8846c254b9ae0c47cad0ce1688d98b05c8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 12:37:28 -0400 Subject: [PATCH 068/300] only sort rooms inside room list --- public/src/client/chats.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index f570c7cf8d..41aaf3d93c 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -102,6 +102,7 @@ define('forum/chats', [ const publicRoomList = $('[component="chat/public"]'); publicRoomList.sortable({ handle: '[component="chat/public/room/sort/handle"]', + items: '[component="chat/public/room"]', axis: 'y', update: async function () { const data = { roomIds: [], scores: [] }; From ac063fe58af22f9376af988c12ca6d73d3c44c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 12:38:02 -0400 Subject: [PATCH 069/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 8d03797c9b..eb3dbfbbe6 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.2", + "nodebb-theme-harmony": "1.1.3", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.1.1", "nodebb-theme-persona": "13.2.2", From 840792ae35c9531edbb3aa828786c8f1c8c9e99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 19:35:23 -0400 Subject: [PATCH 070/300] fix: #11797, update title on chat switch --- public/src/ajaxify.js | 1 + public/src/client/chats.js | 1 + 2 files changed, 2 insertions(+) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 8111f0ef09..0971896727 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -229,6 +229,7 @@ ajaxify.widgets = { render: render }; }); }); } + ajaxify.updateTitle = updateTitle; function updateTags() { const metaWhitelist = ['title', 'description', /og:.+/, /article:.+/, 'robots'].map(function (val) { diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 41aaf3d93c..ad9147cb3c 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -464,6 +464,7 @@ define('forum/chats', [ chatNavWrapper = $('[component="chat/nav-wrapper"]'); html.find('.timeago').timeago(); ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomId }; + ajaxify.updateTitle(ajaxify.data.title); $('body').toggleClass('chat-loaded', !!roomId); mainWrapper.find('[data-bs-toggle="tooltip"]').tooltip(); Chats.setActive(roomId); From 5f43605e4ddbb185814bfee59f07e737eb5c1e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 19:53:26 -0400 Subject: [PATCH 071/300] move imports to top --- public/src/ajaxify.js | 116 ++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 0971896727..be16af3e91 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -1,5 +1,8 @@ 'use strict'; +const benchpress = require('benchpressjs'); +const translator = require('./modules/translator'); +const alerts = require('./modules/alerts'); const hooks = require('./modules/hooks'); const { render } = require('./widgets'); @@ -160,9 +163,7 @@ ajaxify.widgets = { render: render }; $('#footer, #content').removeClass('hide').addClass('ajaxifying'); return renderTemplate(url, status.toString(), data.responseJSON || {}, callback); } else if (status === 401) { - require(['alerts'], function (alerts) { - alerts.error('[[global:please_log_in]]'); - }); + alerts.error('[[global:please_log_in]]'); app.previousUrl = url; window.location.href = config.relative_path + '/login'; } else if (status === 302 || status === 308) { @@ -180,53 +181,48 @@ ajaxify.widgets = { render: render }; } } } else if (textStatus !== 'abort') { - require(['alerts'], function (alerts) { - alerts.error(data.responseJSON.error); - }); + alerts.error(data.responseJSON.error); } } function renderTemplate(url, tpl_url, data, callback) { hooks.fire('action:ajaxify.loadingTemplates', {}); - require(['translator', 'benchpress'], function (translator, Benchpress) { - Benchpress.render(tpl_url, data) - .then(rendered => translator.translate(rendered)) - .then(function (translated) { - translated = translator.unescape(translated); - $('body').removeClass(previousBodyClass).addClass(data.bodyClass); - $('#content').html(translated); + benchpress.render(tpl_url, data) + .then(rendered => translator.translate(rendered)) + .then(function (translated) { + translated = translator.unescape(translated); + $('body').removeClass(previousBodyClass).addClass(data.bodyClass); + $('#content').html(translated); - ajaxify.end(url, tpl_url); + ajaxify.end(url, tpl_url); - if (typeof callback === 'function') { - callback(); - } + if (typeof callback === 'function') { + callback(); + } - $('#content, #footer').removeClass('ajaxifying'); + $('#content, #footer').removeClass('ajaxifying'); - // Only executed on ajaxify. Otherwise these'd be in ajaxify.end() - updateTitle(data.title); - updateTags(); - }); - }); + // Only executed on ajaxify. Otherwise these'd be in ajaxify.end() + updateTitle(data.title); + updateTags(); + }); } function updateTitle(title) { if (!title) { return; } - require(['translator'], function (translator) { - title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}') - .replace('{pageTitle}', function () { return title; }) - .replace('{browserTitle}', function () { return config.browserTitle; }); - // Allow translation strings in title on ajaxify (#5927) - title = translator.unescape(title); - const data = { title: title }; - hooks.fire('action:ajaxify.updateTitle', data); - translator.translate(data.title, function (translated) { - window.document.title = $('
        ').html(translated).text(); - }); + title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}') + .replace('{pageTitle}', function () { return title; }) + .replace('{browserTitle}', function () { return config.browserTitle; }); + + // Allow translation strings in title on ajaxify (#5927) + title = translator.unescape(title); + const data = { title: title }; + hooks.fire('action:ajaxify.updateTitle', data); + translator.translate(data.title, function (translated) { + window.document.title = $('
        ').html(translated).text(); }); } ajaxify.updateTitle = updateTitle; @@ -249,25 +245,25 @@ ajaxify.widgets = { render: render }; .forEach(function (el) { document.head.removeChild(el); }); - require(['translator'], function (translator) { - // Add new meta tags - ajaxify.data._header.tags.meta - .filter(function (tagObj) { - const name = tagObj.name || tagObj.property; - return metaWhitelist.some(function (exp) { - return !!exp.test(name); - }); - }).forEach(async function (tagObj) { - if (tagObj.content) { - tagObj.content = await translator.translate(tagObj.content); - } - const metaEl = document.createElement('meta'); - Object.keys(tagObj).forEach(function (prop) { - metaEl.setAttribute(prop, tagObj[prop]); - }); - document.head.appendChild(metaEl); + + // Add new meta tags + ajaxify.data._header.tags.meta + .filter(function (tagObj) { + const name = tagObj.name || tagObj.property; + return metaWhitelist.some(function (exp) { + return !!exp.test(name); }); - }); + }).forEach(async function (tagObj) { + if (tagObj.content) { + tagObj.content = await translator.translate(tagObj.content); + } + const metaEl = document.createElement('meta'); + Object.keys(tagObj).forEach(function (prop) { + metaEl.setAttribute(prop, tagObj[prop]); + }); + document.head.appendChild(metaEl); + }); + // Delete the old link tags Array.prototype.slice @@ -472,15 +468,13 @@ ajaxify.widgets = { render: render }; hooks.fire('action:ajaxify.cleanup', { url, tpl_url }); }; - require(['translator', 'benchpress', 'navigator'], function (translator, Benchpress) { - translator.translate('[[error:no-connection]]'); - translator.translate('[[error:socket-reconnect-failed]]'); - translator.translate(`[[global:reconnecting-message, ${config.siteTitle}]]`); - Benchpress.registerLoader(ajaxify.loadTemplate); - Benchpress.setGlobal('config', config); - Benchpress.render('500', {}); // loads and caches 500.tpl - Benchpress.render('partials/toast'); // loads and caches partials/toast - }); + translator.translate('[[error:no-connection]]'); + translator.translate('[[error:socket-reconnect-failed]]'); + translator.translate(`[[global:reconnecting-message, ${config.siteTitle}]]`); + benchpress.registerLoader(ajaxify.loadTemplate); + benchpress.setGlobal('config', config); + benchpress.render('500', {}); // loads and caches 500.tpl + benchpress.render('partials/toast'); // loads and caches partials/toast }()); $(document).ready(function () { From bc8dbc20847d6337c18e57f51aa1b7b3f17e6b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 20:01:39 -0400 Subject: [PATCH 072/300] add roomId class to body --- src/middleware/helpers.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/middleware/helpers.js b/src/middleware/helpers.js index dde0c3b749..de2669bd84 100644 --- a/src/middleware/helpers.js +++ b/src/middleware/helpers.js @@ -41,16 +41,20 @@ helpers.buildBodyClass = function (req, res, templateData = {}) { p = validator.escape(String(p)); parts[index] = index ? `${parts[0]}-${p}` : `page-${p || 'home'}`; }); - - if (templateData.template) { - parts.push(`template-${templateData.template.name.split('/').join('-')}`); + const { template } = templateData; + if (template) { + parts.push(`template-${template.name.split('/').join('-')}`); } - if (templateData.template && templateData.template.topic) { + if (template && template.topic) { parts.push(`page-topic-category-${templateData.category.cid}`); parts.push(`page-topic-category-${slugify(templateData.category.name)}`); } + if (template && template.chats && templateData.roomId) { + parts.push(`page-user-chats-${templateData.roomId}`); + } + if (Array.isArray(templateData.breadcrumbs)) { templateData.breadcrumbs.forEach((crumb) => { if (crumb && crumb.hasOwnProperty('cid')) { From 3bf16f1c7515874be6542a5da52b01e3dbc66d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 21:25:32 -0400 Subject: [PATCH 073/300] no need to store 0 for all messages for deleted and system, if its missing it defaults to 0 --- src/messaging/create.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/messaging/create.js b/src/messaging/create.js index fa83a22c42..ed6b0b6a33 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -48,10 +48,12 @@ module.exports = function (Messaging) { timestamp: timestamp, fromuid: uid, roomId: roomId, - deleted: 0, - system: data.system || 0, }; + if (data.system) { + message.system = data.system; + } + if (data.ip) { message.ip = data.ip; } From adb3a5e64e7ec7157a103bfac857b26d4704bbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 21:40:33 -0400 Subject: [PATCH 074/300] fix: client side js crash --- public/src/client/chats.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index ad9147cb3c..f1548dd282 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -32,8 +32,14 @@ define('forum/chats', [ $(window).on('action:ajaxify.start', function () { Chats.destroyAutoComplete(ajaxify.data.roomId); - socket.emit('modules.chats.leave', ajaxify.data.roomId); - socket.emit('modules.chats.leavePublic', ajaxify.data.publicRooms.map(r => r.roomId)); + if (ajaxify.data.template.chats) { + if (ajaxify.data.roomId) { + socket.emit('modules.chats.leave', ajaxify.data.roomId); + } + if (ajaxify.data.publicRooms) { + socket.emit('modules.chats.leavePublic', ajaxify.data.publicRooms.map(r => r.roomId)); + } + } }); Chats.init = function () { From 887333478a36e1917fe6a6e05263f63a76295954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 13 Jul 2023 21:47:07 -0400 Subject: [PATCH 075/300] move load on restore --- src/messaging/delete.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/messaging/delete.js b/src/messaging/delete.js index c8070f7740..0363481e42 100644 --- a/src/messaging/delete.js +++ b/src/messaging/delete.js @@ -14,12 +14,11 @@ module.exports = function (Messaging) { } await Messaging.setMessageField(mid, 'deleted', state); - - const messages = await Messaging.getMessagesData([mid], uid, roomId, true); const ioRoom = sockets.in(`chat_room_${roomId}`); if (state === 1 && ioRoom) { ioRoom.emit('event:chats.delete', mid); } else if (state === 0 && ioRoom) { + const messages = await Messaging.getMessagesData([mid], uid, roomId, true); ioRoom.emit('event:chats.restore', messages[0]); } } From 911ef0581c54a9911035168bef0b87ca4490cb6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 14 Jul 2023 11:19:57 -0400 Subject: [PATCH 076/300] feat: show online users at the top of userlist and update when they enter/leave --- .../read/user/userslug/chats/roomid.yaml | 2 + public/src/client/chats.js | 8 +- src/api/chats.js | 4 +- src/messaging/notifications.js | 4 +- src/messaging/rooms.js | 78 ++++++++++++++----- src/socket.io/index.js | 20 +++++ src/socket.io/modules.js | 8 +- src/upgrades/3.3.0/chat_room_online_zset.js | 34 ++++++++ 8 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 src/upgrades/3.3.0/chat_room_online_zset.js diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index d776512925..e8b0876eaf 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -135,6 +135,8 @@ get: nullable: true status: type: string + online: + type: boolean icon:text: type: string description: A single-letter representation of a username. This is used in the diff --git a/public/src/client/chats.js b/public/src/client/chats.js index f1548dd282..100d24dab3 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -29,6 +29,7 @@ define('forum/chats', [ let newMessage = false; let chatNavWrapper = null; + let userListEl = null; $(window).on('action:ajaxify.start', function () { Chats.destroyAutoComplete(ajaxify.data.roomId); @@ -47,7 +48,7 @@ define('forum/chats', [ socket.emit('modules.chats.enterPublic', ajaxify.data.publicRooms.map(r => r.roomId)); const env = utils.findBootstrapEnvironment(); chatNavWrapper = $('[component="chat/nav-wrapper"]'); - + userListEl = $('[component="chat/user/list"]'); if (!Chats.initialised) { Chats.addSocketListeners(); Chats.addGlobalEventListeners(); @@ -468,6 +469,7 @@ define('forum/chats', [ const mainWrapper = components.get('chat/main-wrapper'); mainWrapper.html(html); chatNavWrapper = $('[component="chat/nav-wrapper"]'); + userListEl = $('[component="chat/user/list"]'); html.find('.timeago').timeago(); ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomId }; ajaxify.updateTitle(ajaxify.data.title); @@ -526,6 +528,10 @@ define('forum/chats', [ Chats.increasePublicRoomUnreadCount(chatNavWrapper.find('[data-roomid=' + data.roomId + ']')); }); + socket.on('event:chats.user-online', function (data) { + userListEl.find(`[data-uid="${data.uid}"]`).toggleClass('online', !!data.state); + }); + socket.on('event:user_status_change', function (data) { app.updateUserStatus($('.chats-list [data-uid="' + data.uid + '"] [component="user/status"]'), data.status); }); diff --git a/src/api/chats.js b/src/api/chats.js index a2d2e3467f..0fd0092bec 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -171,7 +171,9 @@ chatsAPI.users = async (caller, data) => { const [isOwner, isUserInRoom, users] = await Promise.all([ messaging.isRoomOwner(caller.uid, data.roomId), messaging.isUserInRoom(caller.uid, data.roomId), - messaging.getUsersInRoom(data.roomId, start, stop), + messaging.getUsersInRoomFromSet( + `chat:room:${data.roomId}:uids:online`, data.roomId, start, stop, true + ), ]); if (!isUserInRoom) { throw new Error('[[error:no-privileges]]'); diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 73cefdde92..0ef05c5acd 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -39,7 +39,7 @@ module.exports = function (Messaging) { } // push unread count only for private rooms - const uids = await Messaging.getAllUidsInRoom(roomId); + const uids = await Messaging.getAllUidsInRoomFromSet(`chat:room:${roomId}:uids:online`); Messaging.pushUnreadCount(uids, unreadData); // Delayed notifications @@ -77,7 +77,7 @@ module.exports = function (Messaging) { path: `/chats/${messageObj.roomId}`, }); - await batch.processSortedSet(`chat:room:${roomId}:uids`, async (uids) => { + await batch.processSortedSet(`chat:room:${roomId}:uids:online`, async (uids) => { const hasRead = await Messaging.hasRead(uids, roomId); uids = uids.filter((uid, index) => !hasRead[index] && parseInt(fromUid, 10) !== parseInt(uid, 10)); diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 300f928e86..9ab00ed7b6 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -10,6 +10,7 @@ const groups = require('../groups'); const plugins = require('../plugins'); const privileges = require('../privileges'); const meta = require('../meta'); +const io = require('../socket.io'); const cache = require('../cache'); const cacheCreate = require('../cacheCreate'); @@ -92,7 +93,10 @@ module.exports = function (Messaging) { await Promise.all([ db.setObject(`chat:room:${roomId}`, room), db.sortedSetAdd('chat:rooms', now, roomId), - db.sortedSetAdd(`chat:room:${roomId}:uids`, now, uid), + db.sortedSetsAdd([ + `chat:room:${roomId}:uids`, + `chat:room:${roomId}:uids:online`, + ], now, uid), ]); await Promise.all([ @@ -133,13 +137,14 @@ module.exports = function (Messaging) { .map(uid => `uid:${uid}:chat:rooms`) .concat(uids.map(uid => `uid:${uid}:chat:rooms:unread`)); - await Promise.all([ - db.sortedSetRemove(`chat:room:${roomId}:uids`, uids), - db.sortedSetsRemove(keys, roomId), - ]); + await db.sortedSetsRemove(keys, roomId); })); await Promise.all([ - db.deleteAll(roomIds.map(id => `chat:room:${id}`)), + db.deleteAll([ + ...roomIds.map(id => `chat:room:${id}`), + ...roomIds.map(id => `chat:room:${id}:uids`), + ...roomIds.map(id => `chat:room:${id}:uids:online`), + ]), db.sortedSetRemove('chat:rooms', roomIds), db.sortedSetRemove('chat:rooms:public', roomIds), db.sortedSetRemove('chat:rooms:public:order', roomIds), @@ -193,7 +198,7 @@ module.exports = function (Messaging) { return single ? data.inRooms.pop() : data.inRooms; }; - Messaging.roomExists = async roomId => db.exists(`chat:room:${roomId}:uids`); + Messaging.roomExists = async roomId => db.exists(`chat:room:${roomId}`); Messaging.getUserCountInRoom = async roomId => db.sortedSetCard(`chat:room:${roomId}:uids`); @@ -231,7 +236,10 @@ module.exports = function (Messaging) { async function addUidsToRoom(uids, roomId) { const now = Date.now(); const timestamps = uids.map(() => now); - await db.sortedSetAdd(`chat:room:${roomId}:uids`, timestamps, uids); + await Promise.all([ + db.sortedSetAdd(`chat:room:${roomId}:uids`, timestamps, uids), + db.sortedSetAdd(`chat:room:${roomId}:uids:online`, timestamps, uids), + ]); await updateUserCount([roomId]); await Promise.all(uids.map(uid => Messaging.addSystemMessage('user-join', uid, roomId))); } @@ -275,7 +283,10 @@ module.exports = function (Messaging) { .concat(uids.map(uid => `uid:${uid}:chat:rooms:unread`)); await Promise.all([ - db.sortedSetRemove(`chat:room:${roomId}:uids`, uids), + db.sortedSetRemove([ + `chat:room:${roomId}:uids`, + `chat:room:${roomId}:uids:online`, + ], uids), db.sortedSetsRemove(keys, roomId), ]); @@ -288,7 +299,10 @@ module.exports = function (Messaging) { const isInRoom = await Promise.all(roomIds.map(roomId => Messaging.isUserInRoom(uid, roomId))); roomIds = roomIds.filter((roomId, index) => isInRoom[index]); - const roomKeys = roomIds.map(roomId => `chat:room:${roomId}:uids`); + const roomKeys = [ + ...roomIds.map(roomId => `chat:room:${roomId}:uids`), + ...roomIds.map(roomId => `chat:room:${roomId}:uids:online`), + ]; await Promise.all([ db.sortedSetsRemove(roomKeys, uid), db.sortedSetRemove([ @@ -310,21 +324,34 @@ module.exports = function (Messaging) { await db.setObjectField(`chat:room:${roomId}`, 'owner', newOwner); } - Messaging.getAllUidsInRoom = async function (roomId) { - const cacheKey = `chat:room:${roomId}:users`; + Messaging.getAllUidsInRoomFromSet = async function (set) { + const cacheKey = `${set}:all`; let uids = roomUidCache.get(cacheKey); if (uids !== undefined) { return uids; } - uids = await Messaging.getUidsInRoom(roomId, 0, -1); + uids = await Messaging.getUidsInRoomFromSet(set, 0, -1); roomUidCache.set(cacheKey, uids); return uids; }; - Messaging.getUidsInRoom = async (roomId, start, stop) => db.getSortedSetRange(`chat:room:${roomId}:uids`, start, stop); + Messaging.getUidsInRoomFromSet = async (set, start, stop, reverse = false) => db[ + reverse ? 'getSortedSetRevRange' : 'getSortedSetRange' + ](set, start, stop); - Messaging.getUsersInRoom = async (roomId, start, stop) => { - const uids = await Messaging.getUidsInRoom(roomId, start, stop); + Messaging.getUidsInRoom = async (roomId, start, stop, reverse = false) => db[ + reverse ? 'getSortedSetRevRange' : 'getSortedSetRange' + ](`chat:room:${roomId}:uids`, start, stop); + + Messaging.getUsersInRoom = async (roomId, start, stop, reverse = false) => { + const users = await Messaging.getUsersInRoomFromSet( + `chat:room:${roomId}:uids`, roomId, start, stop, reverse + ); + return users; + }; + + Messaging.getUsersInRoomFromSet = async (set, roomId, start, stop, reverse = false) => { + const uids = await Messaging.getUidsInRoomFromSet(set, start, stop, reverse); const [users, isOwners] = await Promise.all([ user.getUsersFields(uids, ['uid', 'username', 'picture', 'status']), Messaging.isRoomOwner(uids, roomId), @@ -373,10 +400,12 @@ module.exports = function (Messaging) { Messaging.loadRoom = async (uid, data) => { const { roomId } = data; - const [room, inRoom, canChat] = await Promise.all([ + const [room, inRoom, canChat, isAdmin, isGlobalMod] = await Promise.all([ Messaging.getRoomData(roomId), Messaging.isUserInRoom(uid, roomId), privileges.global.can('chat', uid), + user.isAdministrator(uid), + user.isGlobalModerator(uid), ]); if (!canChat) { @@ -395,23 +424,30 @@ module.exports = function (Messaging) { if (room.public && !inRoom) { await addUidsToRoom([uid], roomId); room.userCount += 1; + } else if (inRoom) { + await db.sortedSetAdd(`chat:room:${roomId}:uids:online`, Date.now(), uid); } - const [canReply, users, messages, isAdmin, isGlobalMod, settings, isOwner] = await Promise.all([ + const [canReply, users, messages, settings, isOwner, onlineUids] = await Promise.all([ Messaging.canReply(roomId, uid), - Messaging.getUsersInRoom(roomId, 0, 39), + Messaging.getUsersInRoomFromSet(`chat:room:${roomId}:uids:online`, roomId, 0, 39, true), Messaging.getMessages({ callerUid: uid, uid: data.uid || uid, roomId: roomId, isNew: false, }), - user.isAdministrator(uid), - user.isGlobalModerator(uid), user.getSettings(uid), Messaging.isRoomOwner(uid, roomId), + io.getUidsInRoom(`chat_room_${roomId}`), ]); + users.forEach((user) => { + if (user) { + user.online = parseInt(user.uid, 10) === parseInt(uid, 10) || onlineUids.includes(String(user.uid)); + } + }); + room.messages = messages; room.isOwner = isOwner; room.users = users; diff --git a/src/socket.io/index.js b/src/socket.io/index.js index b540cbc15f..858223f07d 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -292,6 +292,26 @@ Sockets.getCountInRoom = function (room) { return roomMap ? roomMap.size : 0; }; +// works across multiple nodes +Sockets.getUidsInRoom = async function (room) { + if (!Sockets.server) { + return []; + } + const ioRoom = Sockets.server.in(room); + const uids = {}; + if (ioRoom) { + const sockets = await ioRoom.fetchSockets(); + for (const s of sockets) { + for (const r of s.rooms) { + if (r.startsWith('uid_')) { + uids[r.split('_').pop()] = 1; + } + } + } + } + return Object.keys(uids); +}; + Sockets.warnDeprecated = (socket, replacement) => { if (socket.previousEvents && socket.emit) { socket.emit('event:deprecated_call', { diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 559bbdd5be..f0a71eb2fa 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -106,12 +106,18 @@ async function joinLeave(socket, roomIds, method, prefix = 'chat_room') { Messaging.isUserInRoom(socket.uid, roomIds), Messaging.getRoomsData(roomIds, ['public', 'groups']), ]); - + const io = require('./index'); await Promise.all(roomIds.map(async (roomId, idx) => { const isPublic = roomData[idx] && roomData[idx].public; const roomGroups = roomData[idx] && roomData[idx].groups; if (isAdmin || (inRooms[idx] && (!isPublic || await groups.isMemberOfAny(socket.uid, roomGroups)))) { socket[method](`${prefix}_${roomId}`); + if (prefix === 'chat_room') { + io.in(`chat_room_${roomId}`).emit('event:chats.user-online', { + uid: socket.uid, + state: method === 'join' ? 1 : 0, + }); + } } })); } diff --git a/src/upgrades/3.3.0/chat_room_online_zset.js b/src/upgrades/3.3.0/chat_room_online_zset.js new file mode 100644 index 0000000000..683730662a --- /dev/null +++ b/src/upgrades/3.3.0/chat_room_online_zset.js @@ -0,0 +1,34 @@ +'use strict'; + + +const _ = require('lodash'); + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Create chat:room:uids:online zset', + timestamp: Date.UTC(2023, 6, 14), + method: async function () { + const { progress } = this; + + progress.total = await db.sortedSetCard('chat:rooms'); + + await batch.processSortedSet('chat:rooms', async (roomIds) => { + progress.incr(roomIds.length); + const arrayOfUids = await db.getSortedSetsMembersWithScores(roomIds.map(roomId => `chat:room:${roomId}:uids`)); + + const bulkAdd = []; + arrayOfUids.forEach((uids, idx) => { + const roomId = roomIds[idx]; + uids.forEach((uid) => { + bulkAdd.push([`chat:room:${roomId}:uids:online`, uid.score, uid.value]); + }); + }); + await db.sortedSetAddBulk(bulkAdd); + }, { + batch: 500, + }); + }, +}; From 98e0d141bdbc43a2f59a591bffb499476d35d248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 14 Jul 2023 11:21:10 -0400 Subject: [PATCH 077/300] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index eb3dbfbbe6..d9040e08c3 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.3", + "nodebb-theme-harmony": "1.1.4", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.1.1", - "nodebb-theme-persona": "13.2.2", + "nodebb-theme-persona": "13.2.3", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From 1e38a16bdb33b9dd95e2de3f302c677943139ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 14 Jul 2023 11:36:02 -0400 Subject: [PATCH 078/300] fix: lint --- src/upgrades/3.3.0/chat_room_online_zset.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/upgrades/3.3.0/chat_room_online_zset.js b/src/upgrades/3.3.0/chat_room_online_zset.js index 683730662a..0a57076fa0 100644 --- a/src/upgrades/3.3.0/chat_room_online_zset.js +++ b/src/upgrades/3.3.0/chat_room_online_zset.js @@ -1,8 +1,6 @@ 'use strict'; -const _ = require('lodash'); - const db = require('../../database'); const batch = require('../../batch'); From cfa00ece35e6d64c7b6b056a0ea140f474579463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 14 Jul 2023 12:19:33 -0400 Subject: [PATCH 079/300] on disconnect update chat rooms --- src/socket.io/index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 858223f07d..50ae9b25f6 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -97,6 +97,10 @@ function onConnection(socket) { socket.on('disconnect', () => { onDisconnect(socket); }); + + socket.on('disconnecting', () => { + onDisconnecting(socket); + }); } function onDisconnect(socket) { @@ -104,6 +108,19 @@ function onDisconnect(socket) { plugins.hooks.fire('action:sockets.disconnect', { socket: socket }); } +async function onDisconnecting(socket) { + if (socket.uid > 0) { + for (const roomName of socket.rooms) { + if (roomName.startsWith('chat_room') && !roomName.includes('public')) { + Sockets.server.in(roomName).emit('event:chats.user-online', { + uid: socket.uid, + state: 0, + }); + } + } + } +} + async function onConnect(socket) { try { await validateSession(socket, '[[error:invalid-session]]'); From f0775651b96cbdfddb579ff27ee59c9245ef427e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 14 Jul 2023 13:01:41 -0400 Subject: [PATCH 080/300] only update user list if its open --- public/src/client/chats.js | 7 ------- public/src/client/chats/user-list.js | 30 ++++++++++++++++++++++++++++ src/api/chats.js | 5 ++++- src/socket.io/index.js | 17 ---------------- src/socket.io/modules.js | 8 +------- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 100d24dab3..8593d501a5 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -29,7 +29,6 @@ define('forum/chats', [ let newMessage = false; let chatNavWrapper = null; - let userListEl = null; $(window).on('action:ajaxify.start', function () { Chats.destroyAutoComplete(ajaxify.data.roomId); @@ -48,7 +47,6 @@ define('forum/chats', [ socket.emit('modules.chats.enterPublic', ajaxify.data.publicRooms.map(r => r.roomId)); const env = utils.findBootstrapEnvironment(); chatNavWrapper = $('[component="chat/nav-wrapper"]'); - userListEl = $('[component="chat/user/list"]'); if (!Chats.initialised) { Chats.addSocketListeners(); Chats.addGlobalEventListeners(); @@ -469,7 +467,6 @@ define('forum/chats', [ const mainWrapper = components.get('chat/main-wrapper'); mainWrapper.html(html); chatNavWrapper = $('[component="chat/nav-wrapper"]'); - userListEl = $('[component="chat/user/list"]'); html.find('.timeago').timeago(); ajaxify.data = { ...ajaxify.data, ...payload, roomId: roomId }; ajaxify.updateTitle(ajaxify.data.title); @@ -528,10 +525,6 @@ define('forum/chats', [ Chats.increasePublicRoomUnreadCount(chatNavWrapper.find('[data-roomid=' + data.roomId + ']')); }); - socket.on('event:chats.user-online', function (data) { - userListEl.find(`[data-uid="${data.uid}"]`).toggleClass('online', !!data.state); - }); - socket.on('event:user_status_change', function (data) { app.updateUserStatus($('.chats-list [data-uid="' + data.uid + '"] [component="user/status"]'), data.status); }); diff --git a/public/src/client/chats/user-list.js b/public/src/client/chats/user-list.js index cd4b5a8f50..419e699032 100644 --- a/public/src/client/chats/user-list.js +++ b/public/src/client/chats/user-list.js @@ -4,6 +4,8 @@ define('forum/chats/user-list', ['api'], function (api) { const userList = {}; + let updateInterval = 0; + userList.init = function (roomId, container) { const userListEl = container.find('[component="chat/user/list"]'); if (!userListEl.length) { @@ -11,13 +13,41 @@ define('forum/chats/user-list', ['api'], function (api) { } container.find('[component="chat/user/list/btn"]').on('click', () => { userListEl.toggleClass('hidden'); + if (userListEl.hasClass('hidden')) { + stopUpdating(); + } else { + startUpdating(roomId, userListEl); + } }); + $(window).off('action:ajaxify.start', stopUpdating) + .one('action:ajaxify.start', stopUpdating); + userList.addInfiniteScrollHandler(roomId, userListEl, async (listEl, data) => { listEl.append(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); }); }; + function startUpdating(roomId, userListEl) { + updateInterval = setInterval(() => { + updateUserList(roomId, userListEl); + }, 5000); + } + + function stopUpdating() { + if (updateInterval) { + clearInterval(updateInterval); + updateInterval = 0; + } + } + + async function updateUserList(roomId, userListEl) { + if (ajaxify.data.template.chats && app.isFocused && userListEl.scrollTop() === 0 && !userListEl.hasClass('hidden')) { + const data = await api.get(`/chats/${roomId}/users`, { start: 0 }); + userListEl.html(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); + } + } + userList.addInfiniteScrollHandler = function (roomId, listEl, callback) { listEl.on('scroll', utils.debounce(async () => { const bottom = (listEl[0].scrollHeight - listEl.height()) * 0.85; diff --git a/src/api/chats.js b/src/api/chats.js index 0fd0092bec..2d9c31a1fe 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -168,18 +168,21 @@ chatsAPI.mark = async (caller, data) => { chatsAPI.users = async (caller, data) => { const start = data.hasOwnProperty('start') ? data.start : 0; const stop = start + 39; - const [isOwner, isUserInRoom, users] = await Promise.all([ + const io = require('../socket.io'); + const [isOwner, isUserInRoom, users, onlineUids] = await Promise.all([ messaging.isRoomOwner(caller.uid, data.roomId), messaging.isUserInRoom(caller.uid, data.roomId), messaging.getUsersInRoomFromSet( `chat:room:${data.roomId}:uids:online`, data.roomId, start, stop, true ), + io.getUidsInRoom(`chat_room_${data.roomId}`), ]); if (!isUserInRoom) { throw new Error('[[error:no-privileges]]'); } users.forEach((user) => { user.canKick = isOwner && (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)); + user.online = parseInt(user.uid, 10) === parseInt(caller.uid, 10) || onlineUids.includes(String(user.uid)); }); return { users }; }; diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 50ae9b25f6..858223f07d 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -97,10 +97,6 @@ function onConnection(socket) { socket.on('disconnect', () => { onDisconnect(socket); }); - - socket.on('disconnecting', () => { - onDisconnecting(socket); - }); } function onDisconnect(socket) { @@ -108,19 +104,6 @@ function onDisconnect(socket) { plugins.hooks.fire('action:sockets.disconnect', { socket: socket }); } -async function onDisconnecting(socket) { - if (socket.uid > 0) { - for (const roomName of socket.rooms) { - if (roomName.startsWith('chat_room') && !roomName.includes('public')) { - Sockets.server.in(roomName).emit('event:chats.user-online', { - uid: socket.uid, - state: 0, - }); - } - } - } -} - async function onConnect(socket) { try { await validateSession(socket, '[[error:invalid-session]]'); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index f0a71eb2fa..559bbdd5be 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -106,18 +106,12 @@ async function joinLeave(socket, roomIds, method, prefix = 'chat_room') { Messaging.isUserInRoom(socket.uid, roomIds), Messaging.getRoomsData(roomIds, ['public', 'groups']), ]); - const io = require('./index'); + await Promise.all(roomIds.map(async (roomId, idx) => { const isPublic = roomData[idx] && roomData[idx].public; const roomGroups = roomData[idx] && roomData[idx].groups; if (isAdmin || (inRooms[idx] && (!isPublic || await groups.isMemberOfAny(socket.uid, roomGroups)))) { socket[method](`${prefix}_${roomId}`); - if (prefix === 'chat_room') { - io.in(`chat_room_${roomId}`).emit('event:chats.user-online', { - uid: socket.uid, - state: method === 'join' ? 1 : 0, - }); - } } })); } From 79fae26d8ebe3ff2963e472c9d48dbc23f66afb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 14 Jul 2023 13:20:10 -0400 Subject: [PATCH 081/300] fix: spec --- public/openapi/components/schemas/Chats.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 1d21c26343..7451c93542 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -145,6 +145,8 @@ RoomUserList: type: boolean index: type: number + online: + type: boolean RoomObjectFull: # Messaging.loadRoom allOf: From 8e295464d1f53605ea59fbceb579c216a725fd89 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 21:14:26 -0400 Subject: [PATCH 082/300] fix(deps): update dependency postcss to v8.4.26 (#11798) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index d9040e08c3..716b85f96d 100644 --- a/install/package.json +++ b/install/package.json @@ -113,7 +113,7 @@ "passport-local": "1.0.0", "pg": "8.11.1", "pg-cursor": "2.10.1", - "postcss": "8.4.25", + "postcss": "8.4.26", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0", From b53da68800a3bac685f19642749763e2495f738e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 21:14:43 -0400 Subject: [PATCH 083/300] chore(deps): update dependency eslint to v8.45.0 (#11800) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 716b85f96d..041d32cd72 100644 --- a/install/package.json +++ b/install/package.json @@ -156,7 +156,7 @@ "@commitlint/cli": "17.6.6", "@commitlint/config-angular": "17.6.6", "coveralls": "3.1.1", - "eslint": "8.44.0", + "eslint": "8.45.0", "eslint-config-nodebb": "0.2.1", "eslint-plugin-import": "2.27.5", "grunt": "1.6.1", From 406ced79801e35ec2bf318e01c93bd1c674fe9ab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 21:14:51 -0400 Subject: [PATCH 084/300] fix(deps): update dependency sharp to v0.32.3 (#11799) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 041d32cd72..521665a95a 100644 --- a/install/package.json +++ b/install/package.json @@ -127,7 +127,7 @@ "sass": "1.63.6", "semver": "7.5.4", "serve-favicon": "2.5.0", - "sharp": "0.32.2", + "sharp": "0.32.3", "sitemap": "7.1.1", "slideout": "1.0.1", "socket.io": "4.7.1", From fd90de1ec0c78d9db5a46bb951d233236f30276d Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sat, 15 Jul 2023 09:18:34 +0000 Subject: [PATCH 085/300] Latest translations and fallbacks --- public/language/fr/modules.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 3302006f5b..f120d4fd83 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -2,7 +2,7 @@ "chat.chatting_with": "Discuter avec", "chat.placeholder": "Écrivez vos message ici, faites glisser / déposez les images, validez sur entrée pour envoyer", "chat.placeholder.mobile": "Tapez le message ici", - "chat.scroll-up-alert": "Go to most recent message", + "chat.scroll-up-alert": "Aller au message le plus récent", "chat.usernames-and-x-others": "%1 & %2 autres", "chat.chat-with-usernames": "Discuter avec %1", "chat.chat-with-usernames-and-x-others": "Discuter avec %1 & %2 autres", @@ -35,21 +35,21 @@ "chat.public.option": "Public (Visible to every user in selected groups)", "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", "chat.manage-room": "Gérer l'espace de discussion", - "chat.add-user": "Add User", - "chat.select-groups": "Select Groups", + "chat.add-user": "Ajouter un utilisateur", + "chat.select-groups": "Sélectionner des groupes", "chat.add-user-help": "Rechercher des utilisateurs ici. Lorsque cette option est sélectionnée, l'utilisateur sera ajouté à l'espace de discussion. Le nouvel utilisateur ne pourra pas visualiser les échanges avant d'être ajoutés à la conversation. Seuls les propriétaires de l'espace de discussion () peuvent supprimer des utilisateurs.", "chat.confirm-chat-with-dnd-user": "Cet utilisateur a son statut en mode \"Ne pas déranger\". Voulez-vous quand même discuter avec lui ?", - "chat.room-name-optional": "Room Name (Optional)", + "chat.room-name-optional": "Renommer l'espace de discussion (optionnel)", "chat.rename-room": "Renommer l'espace de discussion ", "chat.rename-placeholder": "Entrer le nom ici ", "chat.rename-help": "Le nom de l'espace de discussion défini ici sera visible par tous les participants à la discussion.", - "chat.leave": "Leave", - "chat.leave-room": "Leave Room", + "chat.leave": "Partir", + "chat.leave-room": "Quitter l'espace de discussion", "chat.leave-prompt": "Êtes-vous sûr de vouloir quitter la discussion ?", "chat.leave-help": "Si vous quittez vous ne pourrez plus suivre la discussion. Si vous êtes de nouveau ajouté, vous ne verrez aucun historique de la discussion avant votre réintégration.", - "chat.delete": "Delete", - "chat.delete-room": "Delete Room", - "chat.delete-prompt": "Are you sure you wish to delete this chat room?", + "chat.delete": "Supprimer", + "chat.delete-room": "Supprimer l'espace de discussion ", + "chat.delete-prompt": "Êtes-vous sûr de vouloir supprimer cet espace de discussion ?", "chat.in-room": "Dans cet espace de discussion", "chat.kick": "Exclure", "chat.show-ip": "Voir IP", From 212f90bb9c73d339ba6b554bb4985694dc3bd7a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 15 Jul 2023 15:41:11 -0400 Subject: [PATCH 086/300] fix(deps): update dependency esbuild to v0.18.13 (#11801) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 521665a95a..c81f0cea38 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.12", + "esbuild": "0.18.13", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From f27159794176a125336d356bcd504b4cf9fa8a59 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 15 Jul 2023 15:41:58 -0400 Subject: [PATCH 087/300] chore(deps): update mongo docker tag to v6 (#10889) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f5064f709d..d2dd13fe4d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -77,7 +77,7 @@ jobs: - 6379:6379 mongo: - image: 'mongo:3.7' + image: 'mongo:6.0' ports: # Maps port 27017 on service container to the host - 27017:27017 From c838782816815ef687474ce0bd00975fe1502ee0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 15 Jul 2023 15:42:43 -0400 Subject: [PATCH 088/300] chore(deps): update actions/setup-node action to v3 (#10347) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d2dd13fe4d..c97b7fb8da 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -88,7 +88,7 @@ jobs: - run: cp install/package.json package.json - name: Install Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} From 640e32d49c2c51f1519b8334a8907a2dfe293959 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sat, 15 Jul 2023 20:23:27 +0000 Subject: [PATCH 089/300] chore(i18n): fallback strings for new resources: nodebb.admin-settings-guest --- public/language/ar/admin/settings/guest.json | 2 +- public/language/bg/admin/settings/guest.json | 2 +- public/language/bn/admin/settings/guest.json | 2 +- public/language/cs/admin/settings/guest.json | 2 +- public/language/da/admin/settings/guest.json | 2 +- public/language/de/admin/settings/guest.json | 2 +- public/language/el/admin/settings/guest.json | 2 +- public/language/en-US/admin/settings/guest.json | 2 +- public/language/en-x-pirate/admin/settings/guest.json | 2 +- public/language/es/admin/settings/guest.json | 2 +- public/language/et/admin/settings/guest.json | 2 +- public/language/fa-IR/admin/settings/guest.json | 2 +- public/language/fi/admin/settings/guest.json | 2 +- public/language/fr/admin/settings/guest.json | 2 +- public/language/gl/admin/settings/guest.json | 2 +- public/language/he/admin/settings/guest.json | 2 +- public/language/hr/admin/settings/guest.json | 2 +- public/language/hu/admin/settings/guest.json | 2 +- public/language/hy/admin/settings/guest.json | 2 +- public/language/id/admin/settings/guest.json | 2 +- public/language/it/admin/settings/guest.json | 2 +- public/language/ja/admin/settings/guest.json | 2 +- public/language/ko/admin/settings/guest.json | 2 +- public/language/lt/admin/settings/guest.json | 2 +- public/language/lv/admin/settings/guest.json | 2 +- public/language/ms/admin/settings/guest.json | 2 +- public/language/nb/admin/settings/guest.json | 2 +- public/language/nl/admin/settings/guest.json | 2 +- public/language/pl/admin/settings/guest.json | 2 +- public/language/pt-BR/admin/settings/guest.json | 2 +- public/language/pt-PT/admin/settings/guest.json | 2 +- public/language/ro/admin/settings/guest.json | 2 +- public/language/ru/admin/settings/guest.json | 2 +- public/language/rw/admin/settings/guest.json | 2 +- public/language/sc/admin/settings/guest.json | 2 +- public/language/sk/admin/settings/guest.json | 2 +- public/language/sl/admin/settings/guest.json | 2 +- public/language/sq-AL/admin/settings/guest.json | 2 +- public/language/sr/admin/settings/guest.json | 2 +- public/language/sv/admin/settings/guest.json | 2 +- public/language/th/admin/settings/guest.json | 2 +- public/language/tr/admin/settings/guest.json | 2 +- public/language/uk/admin/settings/guest.json | 2 +- public/language/vi/admin/settings/guest.json | 2 +- public/language/zh-CN/admin/settings/guest.json | 2 +- public/language/zh-TW/admin/settings/guest.json | 2 +- 46 files changed, 46 insertions(+), 46 deletions(-) diff --git a/public/language/ar/admin/settings/guest.json b/public/language/ar/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/ar/admin/settings/guest.json +++ b/public/language/ar/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/bg/admin/settings/guest.json b/public/language/bg/admin/settings/guest.json index 32436ebbd7..7a9cf58dda 100644 --- a/public/language/bg/admin/settings/guest.json +++ b/public/language/bg/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Настройки", - "guest-settings": "Настройки за гостите", + "guest-settings": "Guest Settings", "handles.enabled": "Позволяване на имената за гостите", "handles.enabled-help": "Тази възможност предоставя ново поле, което позволява на гостите да си изберат име, което да се използва за всяка публикация, която правят. Ако е изключено, всички те просто ще имат името „Гост“.", "topic-views.enabled": "Гостите да допринасят за броя на преглеждания на темите", diff --git a/public/language/bn/admin/settings/guest.json b/public/language/bn/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/bn/admin/settings/guest.json +++ b/public/language/bn/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/cs/admin/settings/guest.json b/public/language/cs/admin/settings/guest.json index 27d0bfef44..7f818a9774 100644 --- a/public/language/cs/admin/settings/guest.json +++ b/public/language/cs/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Povolit upravení zacházení s hosty", "handles.enabled-help": "Tato možnost odkryje nové pole, které umožňuje hostům vybrat jméno, které se připojí ke každému příspěvku, který vytvoří. Bude-li zakázáno, budou jednoduše nazýváni „Host”", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/da/admin/settings/guest.json b/public/language/da/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/da/admin/settings/guest.json +++ b/public/language/da/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/de/admin/settings/guest.json b/public/language/de/admin/settings/guest.json index 0007092f0b..e8e26b311b 100644 --- a/public/language/de/admin/settings/guest.json +++ b/public/language/de/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Einstellungen", - "guest-settings": "Gasteinstellungen", + "guest-settings": "Guest Settings", "handles.enabled": "Gastzugänge erlauben", "handles.enabled-help": "Diese Option zeigt ein neues Feld an, in dem Gäste einen Namen auswählen können, der jedem von ihnen erstellten Beitrag zugeordnet werden soll. Wenn sie deaktiviert sind, werden sie einfach „Gast“ genannt.", "topic-views.enabled": "Gästen erlauben, die gezählte Anzahl der Themenaufrufe zu erhöhen", diff --git a/public/language/el/admin/settings/guest.json b/public/language/el/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/el/admin/settings/guest.json +++ b/public/language/el/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/en-US/admin/settings/guest.json b/public/language/en-US/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/en-US/admin/settings/guest.json +++ b/public/language/en-US/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/en-x-pirate/admin/settings/guest.json b/public/language/en-x-pirate/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/en-x-pirate/admin/settings/guest.json +++ b/public/language/en-x-pirate/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/es/admin/settings/guest.json b/public/language/es/admin/settings/guest.json index 2ec54ccb9c..c0bfdf5877 100644 --- a/public/language/es/admin/settings/guest.json +++ b/public/language/es/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Permitir manejo de visitantes", "handles.enabled-help": "Esta opción expone un nuevo campo que permite a los invitados escoger un nombre para asociarse con cada entrada/respuesta que hagan. Si está desactivado, se les llamará simplemente \"Invitado\".", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/et/admin/settings/guest.json b/public/language/et/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/et/admin/settings/guest.json +++ b/public/language/et/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/fa-IR/admin/settings/guest.json b/public/language/fa-IR/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/fa-IR/admin/settings/guest.json +++ b/public/language/fa-IR/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/fi/admin/settings/guest.json b/public/language/fi/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/fi/admin/settings/guest.json +++ b/public/language/fi/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/fr/admin/settings/guest.json b/public/language/fr/admin/settings/guest.json index f8853ee263..8352c80508 100644 --- a/public/language/fr/admin/settings/guest.json +++ b/public/language/fr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Paramètres", - "guest-settings": "Paramètres d'invité", + "guest-settings": "Guest Settings", "handles.enabled": "Autoriser les invités à poster", "handles.enabled-help": "Cette option affiche un nouveau champ qui permet aux invités de choisir un nom qui sera associé à chaque message qu'ils rédigent. Si désactivé, il seront simplement nommés \"Invité\".", "topic-views.enabled": "Autoriser les invités à augmenter le nombre de consultations de sujets", diff --git a/public/language/gl/admin/settings/guest.json b/public/language/gl/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/gl/admin/settings/guest.json +++ b/public/language/gl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/he/admin/settings/guest.json b/public/language/he/admin/settings/guest.json index fbdf6f275e..00bbe93b66 100644 --- a/public/language/he/admin/settings/guest.json +++ b/public/language/he/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "הגדרות", - "guest-settings": "הגדרות אורחים", + "guest-settings": "Guest Settings", "handles.enabled": "אפשר נקודות אחיזה לאורחים", "handles.enabled-help": "אפשרות זו חושפת שדה חדש המאפשר לאורחים לבחור שם שישויך לכל פוסט שהם מבצעים. אם מושבת, הם פשוט יקראו \"אורח\"", "topic-views.enabled": "הגדל מספר צפיות בנושא על-ידי צפיות של אורחים", diff --git a/public/language/hr/admin/settings/guest.json b/public/language/hr/admin/settings/guest.json index 7bfe85ba29..35efe569eb 100644 --- a/public/language/hr/admin/settings/guest.json +++ b/public/language/hr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Dozvoli upravljanje gostima", "handles.enabled-help": "Ova opcija omogućava gostima da izaberi ime za svaku objavu koju naprave.Ako je onemogućena gosti će se zvati \"gost\".", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/hu/admin/settings/guest.json b/public/language/hu/admin/settings/guest.json index 9a65d80c92..8205281f5b 100644 --- a/public/language/hu/admin/settings/guest.json +++ b/public/language/hu/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Beállítások", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Vendég név beállítás engedélyezése", "handles.enabled-help": "Ez a beállítás engedélyez egy új mezőt, amivel a vendégek minden hozzászólásnál választhatnak egy nevet ami megjelenik ott. Ha nincs engedélyezve, egyszerűen \"Vendég\"-ként jelennek meg.", "topic-views.enabled": "Témakör látogatások számának növelésének engedélyezése vendégek számára", diff --git a/public/language/hy/admin/settings/guest.json b/public/language/hy/admin/settings/guest.json index 4f4946d811..e55fa62efb 100644 --- a/public/language/hy/admin/settings/guest.json +++ b/public/language/hy/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Կարգավորումներ", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Թույլատրել guest handles", "handles.enabled-help": "Այս ընտրանքը բացահայտում է նոր դաշտ, որը թույլ է տալիս հյուրերին ընտրել անուն՝ իրենց կատարած յուրաքանչյուր գրառման հետ կապելու համար: Եթե անջատված են, նրանք պարզապես կանվանվեն «Հյուր»", "topic-views.enabled": "Թույլ տվեք հյուրերին ավելացնել թեմայի դիտումների քանակը", diff --git a/public/language/id/admin/settings/guest.json b/public/language/id/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/id/admin/settings/guest.json +++ b/public/language/id/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/it/admin/settings/guest.json b/public/language/it/admin/settings/guest.json index 6798438054..13607d6b24 100644 --- a/public/language/it/admin/settings/guest.json +++ b/public/language/it/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Impostazioni", - "guest-settings": "Impostazioni dell'ospite", + "guest-settings": "Guest Settings", "handles.enabled": "Consenti nome utente ospite", "handles.enabled-help": "Questa opzione mostra un nuovo campo che permette agli ospiti di scegliere un nome da associare ad ogni post che fanno. Se disabilitata, saranno semplicemente chiamati \"Ospite\".", "topic-views.enabled": "Consentire agli ospiti di aumentare il numero di visualizzazioni della discussione", diff --git a/public/language/ja/admin/settings/guest.json b/public/language/ja/admin/settings/guest.json index 94efb6ff4a..7bf33c0014 100644 --- a/public/language/ja/admin/settings/guest.json +++ b/public/language/ja/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "ゲストハンドルを有効にする", "handles.enabled-help": "このオプションでは新しい投稿が表示される時に、ゲストは自分が投稿する各投稿に関連付ける名前を選択できます。無効にすると、単に「ゲスト」と呼ばれます。", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ko/admin/settings/guest.json b/public/language/ko/admin/settings/guest.json index c252faa745..9e03858a44 100644 --- a/public/language/ko/admin/settings/guest.json +++ b/public/language/ko/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "설정", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "비회원 닉네임 설정 허가", "handles.enabled-help": "이 옵션은 비회원들이 포스트를 작성할 때 이름을 적는 공간을 제공합니다. 이 옵션이 비활성화 상태라면 \"Guest\" 라고 표시될 것입니다.", "topic-views.enabled": "비회원의 방문으로 화제 조회수 증가", diff --git a/public/language/lt/admin/settings/guest.json b/public/language/lt/admin/settings/guest.json index d564091e0f..70d90332d6 100644 --- a/public/language/lt/admin/settings/guest.json +++ b/public/language/lt/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Nustatymai", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/lv/admin/settings/guest.json b/public/language/lv/admin/settings/guest.json index cfbded0bbc..e8904c3260 100644 --- a/public/language/lv/admin/settings/guest.json +++ b/public/language/lv/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Atļaut viesu iesaukas", "handles.enabled-help": "Parādīt lauku, kas viesiem ļaus izvēlēties savu iesauku, kas saistīts ar katru viņu publicēto rakstu. Ja ir atspējots, viņus vienkārši sauks par \"Viesiem\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ms/admin/settings/guest.json b/public/language/ms/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/ms/admin/settings/guest.json +++ b/public/language/ms/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/nb/admin/settings/guest.json b/public/language/nb/admin/settings/guest.json index 1d9d08f38e..760cb7000d 100644 --- a/public/language/nb/admin/settings/guest.json +++ b/public/language/nb/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Innstillinger ", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "Dette alternativet viser et nytt felt som lar gjestene velge et navn som kan knyttes til hvert innlegg de lager. Hvis de er deaktivert, vil de bare bli kalt \"Gjest\"", "topic-views.enabled": "La gjestene øke antall visninger av emner", diff --git a/public/language/nl/admin/settings/guest.json b/public/language/nl/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/nl/admin/settings/guest.json +++ b/public/language/nl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/pl/admin/settings/guest.json b/public/language/pl/admin/settings/guest.json index 7bb8cf219d..c18a0defe7 100644 --- a/public/language/pl/admin/settings/guest.json +++ b/public/language/pl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Ustawienia", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Zezwalaj gościom na podpisywanie się", "handles.enabled-help": "Opcja ta udostępnia gościom nowe pole, w którym mogą wybrać nazwę, pod jaką będą publikować posty. Jeśli opcja jest wyłączona, stosowana będzie po prostu nazwa „Gość”", "topic-views.enabled": "Zezwalaj gościom na zwiększenie liczbę wyświetleń tematu", diff --git a/public/language/pt-BR/admin/settings/guest.json b/public/language/pt-BR/admin/settings/guest.json index 8f2355f38f..6888fa5c17 100644 --- a/public/language/pt-BR/admin/settings/guest.json +++ b/public/language/pt-BR/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Configurações", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Permitir que visitantes escolham um nome", "handles.enabled-help": "Esta opção mostra um novo campo que permite visitantes de escolher um nome para associar a cada post que eles fizerem. Se desabilitado, eles serão simplesmente chamados de \"Visitante\".", "topic-views.enabled": "Permitir que visitantes aumentem a contagem de visualizações do tópico", diff --git a/public/language/pt-PT/admin/settings/guest.json b/public/language/pt-PT/admin/settings/guest.json index 87ad4aa00d..4dfa11df73 100644 --- a/public/language/pt-PT/admin/settings/guest.json +++ b/public/language/pt-PT/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Permitir nomes para visitantes", "handles.enabled-help": "Esta opção expôe um novo campo que permite a visitantes escolher um nome para associar a cada publicação que eles criem. Se desabilitada, eles simplesmente se chamarão \"Visitante\" ", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ro/admin/settings/guest.json b/public/language/ro/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/ro/admin/settings/guest.json +++ b/public/language/ro/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/ru/admin/settings/guest.json b/public/language/ru/admin/settings/guest.json index 40b14618e2..36e489cc74 100644 --- a/public/language/ru/admin/settings/guest.json +++ b/public/language/ru/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Настройки", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Разрешить гостям выбирать имена", "handles.enabled-help": "Эта настройка добавляет поле, в котором гость сможет указать имя, под которым он хочет оставить сообщение. Когда она выключена, вместо имени будет написано просто «Гость».", "topic-views.enabled": "Разрешить гостям увеличивать количество просмотров тем", diff --git a/public/language/rw/admin/settings/guest.json b/public/language/rw/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/rw/admin/settings/guest.json +++ b/public/language/rw/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sc/admin/settings/guest.json b/public/language/sc/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sc/admin/settings/guest.json +++ b/public/language/sc/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sk/admin/settings/guest.json b/public/language/sk/admin/settings/guest.json index c366f3e35e..bb1633e743 100644 --- a/public/language/sk/admin/settings/guest.json +++ b/public/language/sk/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Povoliť upravovanie zaobchádzania s hosťami", "handles.enabled-help": "Táto možnosť odkryje nové pole, ktoré umožňuje hosťom vybrať meno, ktoré sa pripojí ku každému príspevku, ktorý vytvorí. Ak bude zakázané, budú jednoducho nazývaní 'Hosť'", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sl/admin/settings/guest.json b/public/language/sl/admin/settings/guest.json index a01f6934f3..c974a34ef5 100644 --- a/public/language/sl/admin/settings/guest.json +++ b/public/language/sl/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Nastavitve", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sq-AL/admin/settings/guest.json b/public/language/sq-AL/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sq-AL/admin/settings/guest.json +++ b/public/language/sq-AL/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sr/admin/settings/guest.json b/public/language/sr/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sr/admin/settings/guest.json +++ b/public/language/sr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/sv/admin/settings/guest.json b/public/language/sv/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/sv/admin/settings/guest.json +++ b/public/language/sv/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/th/admin/settings/guest.json b/public/language/th/admin/settings/guest.json index 44370e3668..a0062ef75a 100644 --- a/public/language/th/admin/settings/guest.json +++ b/public/language/th/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Allow guest handles", "handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/tr/admin/settings/guest.json b/public/language/tr/admin/settings/guest.json index 9757591fbd..0f870c7122 100644 --- a/public/language/tr/admin/settings/guest.json +++ b/public/language/tr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Ayarlar", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Misafir üyelere izin ver", "handles.enabled-help": "Bu seçenek, misafirlerin yaptıkları her gönderiyle ilişkilendirebilecekleri bir isim alanı sunar. Devre dışı bırakılırsa, gönderenin ismi basitçe \"Misafir\" olarak adlandırılacaktır.", "topic-views.enabled": "Ziyaretçilerin konu bakış sayısını arttırmasına izin ver", diff --git a/public/language/uk/admin/settings/guest.json b/public/language/uk/admin/settings/guest.json index 4ce2a3a6aa..0a434cfcc4 100644 --- a/public/language/uk/admin/settings/guest.json +++ b/public/language/uk/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Дозволити гостьові імена", "handles.enabled-help": "Ця опція надає додаткове поле, що дозволяє гостям обрати собі ім'я для кожного посту. Якщо вимкнено, вони будуть просто зватися \"Гість\"", "topic-views.enabled": "Allow guests to increase topic view counts", diff --git a/public/language/vi/admin/settings/guest.json b/public/language/vi/admin/settings/guest.json index 4b9200ce6f..8c7aa35a6d 100644 --- a/public/language/vi/admin/settings/guest.json +++ b/public/language/vi/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Cài đặt", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "Cho phép xử lý khách", "handles.enabled-help": "Tùy chọn này hiển thị một trường mới cho phép khách chọn tên để liên kết với mỗi bài đăng mà họ thực hiện. Nếu bị tắt, họ sẽ chỉ được gọi là \"Khách\"", "topic-views.enabled": "Cho phép khách tăng lượt xem chủ đề", diff --git a/public/language/zh-CN/admin/settings/guest.json b/public/language/zh-CN/admin/settings/guest.json index c9ebe43739..acf4410aab 100644 --- a/public/language/zh-CN/admin/settings/guest.json +++ b/public/language/zh-CN/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "设置", - "guest-settings": "访客设置", + "guest-settings": "Guest Settings", "handles.enabled": "允许游客用户名", "handles.enabled-help": "这个选项将允许游客使用一个额外的输入框来设置发帖时的用户名,如果被禁用,仅会统一显示为“游客”", "topic-views.enabled": "将来自游客的浏览记入帖子的浏览数", diff --git a/public/language/zh-TW/admin/settings/guest.json b/public/language/zh-TW/admin/settings/guest.json index ca59f2b225..08d7c5c1ab 100644 --- a/public/language/zh-TW/admin/settings/guest.json +++ b/public/language/zh-TW/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Settings", - "guest-settings": "Guest settings", + "guest-settings": "Guest Settings", "handles.enabled": "允許訪客使用者名", "handles.enabled-help": "這個選項將允許訪客使用一個額外的輸入框來設置發文時的使用者名,如果被禁用,僅會統一顯示為“訪客”", "topic-views.enabled": "Allow guests to increase topic view counts", From a766f74f0e38d8a96f806ff08bf723c6d228ace2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 18:08:31 -0400 Subject: [PATCH 090/300] fix: on leave/kick remove matching sockets from rooms --- src/api/chats.js | 3 ++- src/socket.io/helpers.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/api/chats.js b/src/api/chats.js index 2d9c31a1fe..1df828075d 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -228,10 +228,11 @@ chatsAPI.kick = async (caller, data) => { // Additional checks if kicking vs leaving if (data.uids.length === 1 && parseInt(data.uids[0], 10) === caller.uid) { await messaging.leaveRoom([caller.uid], data.roomId); + await socketHelpers.removeSocketsFromRoomByUids([caller.uid], data.roomId); return []; } await messaging.removeUsersFromRoom(caller.uid, data.uids, data.roomId); - + await socketHelpers.removeSocketsFromRoomByUids(data.uids, data.roomId); delete data.uids; return chatsAPI.users(caller, data); }; diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js index 4dd3a31dd4..36b3384d24 100644 --- a/src/socket.io/helpers.js +++ b/src/socket.io/helpers.js @@ -196,4 +196,19 @@ SocketHelpers.emitToUids = async function (event, data, uids) { uids.forEach(toUid => websockets.in(`uid_${toUid}`).emit(event, data)); }; +SocketHelpers.removeSocketsFromRoomByUids = async function (uids, roomId) { + const sockets = _.flatten( + await Promise.all(uids.map(uid => websockets.in(`uid_${uid}`).fetchSockets())) + ); + + for (const s of sockets) { + if (s.rooms.has(`chat_room_${roomId}`)) { + websockets.in(s.id).socketsLeave(`chat_room_${roomId}`); + } + if (s.rooms.has(`chat_room_public_${roomId}`)) { + websockets.in(s.id).socketsLeave(`chat_room_public_${roomId}`); + } + } +}; + require('../promisify')(SocketHelpers); From 35ac434c2ce470e214b864173c57ca526f9d06f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 19:47:30 -0400 Subject: [PATCH 091/300] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 8df10a611a..534e854001 100644 --- a/install/package.json +++ b/install/package.json @@ -103,8 +103,8 @@ "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.1.4", "nodebb-theme-lavender": "7.1.1", - "nodebb-theme-peace": "2.1.1", - "nodebb-theme-persona": "13.2.3", + "nodebb-theme-peace": "2.1.2", + "nodebb-theme-persona": "13.2.4", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From 4c311502a26e1291cf1a3a67572cfb7581ddc7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 20:04:15 -0400 Subject: [PATCH 092/300] fix: allow escape to close chat modals --- public/src/client/chats.js | 1 + public/src/client/chats/create.js | 1 + public/src/client/chats/manage.js | 1 + 3 files changed, 3 insertions(+) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 8593d501a5..7307ae97bc 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -357,6 +357,7 @@ define('forum/chats', [ modal = bootbox.dialog({ title: '[[modules:chat.rename-room]]', message: html, + onEscape: true, buttons: { save: { label: '[[global:save]]', diff --git a/public/src/client/chats/create.js b/public/src/client/chats/create.js index 4c76248a16..6f5077e2e1 100644 --- a/public/src/client/chats/create.js +++ b/public/src/client/chats/create.js @@ -22,6 +22,7 @@ define('forum/chats/create', [ const modal = bootbox.dialog({ title: '[[modules:chat.create-room]]', message: html, + onEscape: true, buttons: { save: { label: '[[global:create]]', diff --git a/public/src/client/chats/manage.js b/public/src/client/chats/manage.js index 2bb2ec41c4..5936f58211 100644 --- a/public/src/client/chats/manage.js +++ b/public/src/client/chats/manage.js @@ -28,6 +28,7 @@ define('forum/chats/manage', [ modal = bootbox.dialog({ title: '[[modules:chat.manage-room]]', message: html, + onEscape: true, }); modal.attr('component', 'chat/manage-modal'); From 165b0f856581b0404ad1680e9f1a9e01c9677cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 21:19:07 -0400 Subject: [PATCH 093/300] fix: closes #11806, fix code blocks --- install/package.json | 4 ++-- public/src/client/topic.js | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/install/package.json b/install/package.json index 534e854001..bd53f322ca 100644 --- a/install/package.json +++ b/install/package.json @@ -96,12 +96,12 @@ "nodebb-plugin-dbsearch": "6.1.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", - "nodebb-plugin-markdown": "12.1.5", + "nodebb-plugin-markdown": "12.1.6", "nodebb-plugin-mentions": "4.3.0", "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.4", + "nodebb-theme-harmony": "1.1.5", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.1.2", "nodebb-theme-persona": "13.2.4", diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 7a0b228efd..79235656dd 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -242,6 +242,15 @@ define('forum/topic', [ function scrollbarVisible(element) { return element.scrollHeight > element.clientHeight; } + function offsetCodeBtn(codeEl) { + if (!codeEl.length) { return; } + if (!codeEl[0].scrollHeight) { + return setTimeout(offsetCodeBtn, 100, codeEl); + } + if (scrollbarVisible(codeEl.get(0))) { + codeEl.parent().parent().find('[component="copy/code/btn"]').css({ margin: '0.5rem 1.5rem 0 0' }); + } + } let codeBlocks = $('[component="topic"] [component="post/content"] code:not([data-button-added])'); codeBlocks = codeBlocks.filter((i, el) => $(el).text().includes('\n')); const container = $('
        '); @@ -250,9 +259,7 @@ define('forum/topic', [ preEls.wrap(container).parent().append(buttonDiv); preEls.parent().find('[component="copy/code/btn"]').translateAttr('title', '[[topic:copy-code]]'); preEls.each((index, el) => { - if (scrollbarVisible(el)) { - $(el).parent().find('[component="copy/code/btn"]').css({ margin: '0.5rem 1.5rem 0 0' }); - } + offsetCodeBtn($(el).find('code')); }); codeBlocks.attr('data-button-added', 1); } From d1132ac44afaac2a5e4885f455b1077cdddbd182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 22:21:10 -0400 Subject: [PATCH 094/300] chore: up plugins --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index bd53f322ca..b90164d120 100644 --- a/install/package.json +++ b/install/package.json @@ -96,8 +96,8 @@ "nodebb-plugin-dbsearch": "6.1.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", - "nodebb-plugin-markdown": "12.1.6", - "nodebb-plugin-mentions": "4.3.0", + "nodebb-plugin-markdown": "12.1.7", + "nodebb-plugin-mentions": "4.3.1", "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", From 052f1f223236540d746f5133e1146a4d464a38e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 22:23:29 -0400 Subject: [PATCH 095/300] add error message for testing --- src/database/mongo/hash.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index ec9cfa051b..cfa46f00a3 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -255,6 +255,7 @@ module.exports = function (module) { // https://github.com/NodeBB/NodeBB/issues/4467 // https://jira.mongodb.org/browse/SERVER-14322 // https://docs.mongodb.org/manual/reference/command/findAndModify/#upsert-and-unique-index + console.log('test', err.message); if (err && err.message.startsWith('E11000 duplicate key error')) { return await module.incrObjectFieldBy(key, field, value); } From 934df69e9d571a2bcf289c8782263f35179f5847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 23:30:19 -0400 Subject: [PATCH 096/300] test: log e11000 errors --- src/database/mongo/hash.js | 9 ++++++--- src/database/mongo/sets.js | 3 ++- src/database/mongo/sorted.js | 3 ++- src/database/mongo/sorted/add.js | 3 ++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index cfa46f00a3..641e3ca35f 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -26,7 +26,8 @@ module.exports = function (module) { await module.client.collection('objects').updateOne({ _key: key }, { $set: writeData }, { upsert: true }); } } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, data); return await module.setObject(key, data); } throw err; @@ -61,7 +62,8 @@ module.exports = function (module) { await bulk.execute(); } } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, data); return await module.setObjectBulk(data); } throw err; @@ -256,7 +258,8 @@ module.exports = function (module) { // https://jira.mongodb.org/browse/SERVER-14322 // https://docs.mongodb.org/manual/reference/command/findAndModify/#upsert-and-unique-index console.log('test', err.message); - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, field, value); return await module.incrObjectFieldBy(key, field, value); } throw err; diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index c4b9615c9e..42051bc2a4 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -51,7 +51,8 @@ module.exports = function (module) { try { await bulk.execute(); } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, keys, value); return await module.setsAdd(keys, value); } throw err; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 12859ed6a4..4e03a93509 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -443,7 +443,8 @@ module.exports = function (module) { // https://github.com/NodeBB/NodeBB/issues/4467 // https://jira.mongodb.org/browse/SERVER-14322 // https://docs.mongodb.org/manual/reference/command/findAndModify/#upsert-and-unique-index - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, increment, value); return await module.sortedSetIncrBy(key, increment, value); } throw err; diff --git a/src/database/mongo/sorted/add.js b/src/database/mongo/sorted/add.js index 13ee427c23..bc3a8bc8ec 100644 --- a/src/database/mongo/sorted/add.js +++ b/src/database/mongo/sorted/add.js @@ -19,7 +19,8 @@ module.exports = function (module) { try { await module.client.collection('objects').updateOne({ _key: key, value: value }, { $set: { score: parseFloat(score) } }, { upsert: true }); } catch (err) { - if (err && err.message.startsWith('E11000 duplicate key error')) { + if (err && err.message.includes('E11000 duplicate key error')) { + console.log(new Error('e11000').stack, key, score, value); return await module.sortedSetAdd(key, score, value); } throw err; From b93cc7884e36e8bc5f696fb214532ea612f49379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 15 Jul 2023 23:42:06 -0400 Subject: [PATCH 097/300] chore: remove test log --- src/database/mongo/hash.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index 641e3ca35f..699d63cc4e 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -257,7 +257,6 @@ module.exports = function (module) { // https://github.com/NodeBB/NodeBB/issues/4467 // https://jira.mongodb.org/browse/SERVER-14322 // https://docs.mongodb.org/manual/reference/command/findAndModify/#upsert-and-unique-index - console.log('test', err.message); if (err && err.message.includes('E11000 duplicate key error')) { console.log(new Error('e11000').stack, key, field, value); return await module.incrObjectFieldBy(key, field, value); From c734570b3992d09e7b32d6bc48f292aa9d692a8c Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 16 Jul 2023 09:18:43 +0000 Subject: [PATCH 098/300] Latest translations and fallbacks --- public/language/he/admin/advanced/errors.json | 8 ++--- public/language/he/admin/advanced/logs.json | 10 +++---- .../language/he/admin/development/logger.json | 8 ++--- public/language/he/admin/extend/plugins.json | 2 +- .../language/he/admin/manage/admins-mods.json | 2 +- .../language/he/admin/manage/privileges.json | 2 +- public/language/he/admin/menu.json | 6 ++-- public/language/he/admin/settings/email.json | 2 +- public/language/he/admin/settings/guest.json | 2 +- .../he/admin/settings/reputation.json | 2 +- public/language/he/admin/settings/tags.json | 2 +- public/language/he/error.json | 2 +- public/language/he/modules.json | 28 ++++++++--------- public/language/it/admin/manage/groups.json | 2 +- public/language/it/error.json | 2 +- public/language/it/modules.json | 30 +++++++++---------- 16 files changed, 55 insertions(+), 55 deletions(-) diff --git a/public/language/he/admin/advanced/errors.json b/public/language/he/admin/advanced/errors.json index f756e47ace..ac86dbfdbf 100644 --- a/public/language/he/admin/advanced/errors.json +++ b/public/language/he/admin/advanced/errors.json @@ -4,12 +4,12 @@ "error-events-per-day": "%1 אירועים ביום", "error.404": "לא נמצא 404", "error.503": "השירות אינו זמין 503", - "manage-error-log": "נהל רישום שגיאות", - "export-error-log": "יצא רישום שגיאות (CSV)", - "clear-error-log": "נקה רישום שגיאות", + "manage-error-log": "נהל לוג שגיאות", + "export-error-log": "יצא לוג שגיאות (CSV)", + "clear-error-log": "נקה לוג שגיאות", "route": "נתיב", "count": "ספירה", "no-routes-not-found": "הידד! אין שגיאות 404!", - "clear404-confirm": "האם אתה בטוח שאתה רוצה לנקות את רישום שגיאות 404?", + "clear404-confirm": "האם אתה בטוח שאתה רוצה לנקות את לוג שגיאות 404?", "clear404-success": "שגיאות \"404 לא נמצא\" נוקו" } \ No newline at end of file diff --git a/public/language/he/admin/advanced/logs.json b/public/language/he/admin/advanced/logs.json index 7c503395a1..a86c26a223 100644 --- a/public/language/he/admin/advanced/logs.json +++ b/public/language/he/admin/advanced/logs.json @@ -1,7 +1,7 @@ { - "logs": "רישומים", - "control-panel": "בקרת רישומים", - "reload": "טען רישומים מחדש", - "clear": "נקה רישומים", - "clear-success": "הרישומים נוקו!" + "logs": "לוגים", + "control-panel": "בקרת לוגים", + "reload": "טען מחדש לוג", + "clear": "נקה לוגים", + "clear-success": "הלוגים נוקו!" } \ No newline at end of file diff --git a/public/language/he/admin/development/logger.json b/public/language/he/admin/development/logger.json index 5e360652e3..a9b481dc70 100644 --- a/public/language/he/admin/development/logger.json +++ b/public/language/he/admin/development/logger.json @@ -1,13 +1,13 @@ { "logger": "Logger", - "logger-settings": "הגדרות מנהל הרישום", + "logger-settings": "הגדרות לוגים", "description": "על-ידי הפיכת תיבות הסימון לזמינות, תקבל יומני רישום למסוף שלך. אם תציין נתיב, יומני הרישום יישמרו בקובץ במקום זאת. רישום HTTP שימושי לאיסוף נתונים סטטיסטיים אודות מי ומתי אנשים נכנסים לפורום שלך. בנוסף לרישום בקשות ה-HTTP, אנו יכולים גם לרשום אירועי Socket.io, אשר בשילוב עם מודד redis-cli, יכול להיות מאוד מועיל ללימוד הפנימיים של NodeBB.", "explanation": "הפעל או ​בטל את סימון הגדרות הרישום כדי לאפשר או להשבית כניסה במהירות. אין צורך בהפעלה מחדש.", "enable-http": "הפעל רישום HTTP", "enable-socket": "הפעל רישום אירועים ב-socket.io", - "file-path": "נתיב קובץ יומן רישום", + "file-path": "נתיב קובץ לוג", "file-path-placeholder": "/path/to/log/file.log ::: השאר ריק כדי להיכנס לטרמינל שלך", - "control-panel": "לוח בקרת מנהל רישום", - "update-settings": "עדכן הגדרות מנהל רישום" + "control-panel": "ניהול לוגים", + "update-settings": "עדכן הגדרות לוגים" } \ No newline at end of file diff --git a/public/language/he/admin/extend/plugins.json b/public/language/he/admin/extend/plugins.json index 31ef5d4573..65cf7e280f 100644 --- a/public/language/he/admin/extend/plugins.json +++ b/public/language/he/admin/extend/plugins.json @@ -11,7 +11,7 @@ "plugin-search": "חיפוש תוספים", "plugin-search-placeholder": "חפש תוספים...", - "submit-anonymous-usage": "שלח נתוני שימוש אנונימיים בתוסף.", + "submit-anonymous-usage": "שלח נתוני שימוש אנונימיים בתוספים.", "reorder-plugins": "סדר מחדש תוספים", "order-active": "סדר תוספים פעילים", "dev-interested": "מתעניין בכתיבת תוספים ל-NodeBB?", diff --git a/public/language/he/admin/manage/admins-mods.json b/public/language/he/admin/manage/admins-mods.json index 7d86808d25..f089efd748 100644 --- a/public/language/he/admin/manage/admins-mods.json +++ b/public/language/he/admin/manage/admins-mods.json @@ -1,5 +1,5 @@ { - "manage-admins-and-mods": "Manage Admins & Mods", + "manage-admins-and-mods": "ניהול מנהלים & מנחים", "administrators": "מנהלים", "global-moderators": "מנחים גלובליים", "moderators": "מנחים", diff --git a/public/language/he/admin/manage/privileges.json b/public/language/he/admin/manage/privileges.json index 3d5104b204..3ec92f2515 100644 --- a/public/language/he/admin/manage/privileges.json +++ b/public/language/he/admin/manage/privileges.json @@ -38,7 +38,7 @@ "downvote-posts": "הצבעה נגד פוסטים", "delete-topics": "מחיקת נושא", "purge": "מחיקה לצמיתות", - "moderate": "Moderate", + "moderate": "הרשאות מנחה", "admin-dashboard": "לוח מחוונים", "admin-categories": "קטגוריות", "admin-privileges": "הרשאות", diff --git a/public/language/he/admin/menu.json b/public/language/he/admin/menu.json index 91250141b9..29be78b9ed 100644 --- a/public/language/he/admin/menu.json +++ b/public/language/he/admin/menu.json @@ -12,7 +12,7 @@ "manage/privileges": "הרשאות", "manage/tags": "תגיות", "manage/users": "משתמשים", - "manage/admins-mods": "מנהלים ומנהלים כלליים", + "manage/admins-mods": "מנחים ומנהלים", "manage/registration": "תור הרשמה", "manage/post-queue": "תור פוסטים", "manage/groups": "קבוצות", @@ -65,10 +65,10 @@ "advanced/database": "מסד נתונים", "advanced/events": "אירועים", "advanced/hooks": "Hooks", - "advanced/logs": "רישומים", + "advanced/logs": "לוג", "advanced/errors": "שגיאות", "advanced/cache": "עוגיות", - "development/logger": "מנהל הרישומים", + "development/logger": "ניהול לוג", "development/info": "מידע", "rebuild-and-restart-forum": "בנה והפעל מחדש את הפורום", diff --git a/public/language/he/admin/settings/email.json b/public/language/he/admin/settings/email.json index 2ff8132b24..0495768930 100644 --- a/public/language/he/admin/settings/email.json +++ b/public/language/he/admin/settings/email.json @@ -1,7 +1,7 @@ { "email-settings": "הגדרות דוא\"ל", "address": "כתובת דוא\"ל", - "address-help": "The following email address refers to the email that the recipient will see in the \"From\" and \"Reply To\" fields.", + "address-help": "שדה אימייל זה מתייחס לכתובת שהנמען יראה בשדות \"מאת\" ו\"השב אל\".", "from": "מאת", "from-help": "השם 'מאת' יוצג בדוא\"ל.", diff --git a/public/language/he/admin/settings/guest.json b/public/language/he/admin/settings/guest.json index 00bbe93b66..fbdf6f275e 100644 --- a/public/language/he/admin/settings/guest.json +++ b/public/language/he/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "הגדרות", - "guest-settings": "Guest Settings", + "guest-settings": "הגדרות אורחים", "handles.enabled": "אפשר נקודות אחיזה לאורחים", "handles.enabled-help": "אפשרות זו חושפת שדה חדש המאפשר לאורחים לבחור שם שישויך לכל פוסט שהם מבצעים. אם מושבת, הם פשוט יקראו \"אורח\"", "topic-views.enabled": "הגדל מספר צפיות בנושא על-ידי צפיות של אורחים", diff --git a/public/language/he/admin/settings/reputation.json b/public/language/he/admin/settings/reputation.json index 85cf78a260..db9974f451 100644 --- a/public/language/he/admin/settings/reputation.json +++ b/public/language/he/admin/settings/reputation.json @@ -27,5 +27,5 @@ "flags.action-on-resolve": "בצע את הפעולות הבאות כאשר דיווח נפתר", "flags.action-on-reject": "בצע את הפעולות הבאות כאשר דיווח נדחה", "flags.action.nothing": "אל תעשה כלום", - "flags.action.rescind": "Rescind the notification sent to moderators/administrators" + "flags.action.rescind": "בטל את ההודעה שנשלחה למנחים/מנהלי מערכת" } \ No newline at end of file diff --git a/public/language/he/admin/settings/tags.json b/public/language/he/admin/settings/tags.json index be2a1788e7..e533d85ba5 100644 --- a/public/language/he/admin/settings/tags.json +++ b/public/language/he/admin/settings/tags.json @@ -2,7 +2,7 @@ "tag": "הגדרות תגיות", "link-to-manage": "נהל תגיות", "system-tags": "תגיות מערכת", - "system-tags-help": "רק מנהלים יכולים להשתמש בתגית זו", + "system-tags-help": "רק מנהלים יוכלו להשתמש בתגיות אלו", "tags-per-topic": "תגים פר נושא", "min-per-topic": "מינימום תגיות לנושא", "max-per-topic": "מקסימום תגיות לנושא", diff --git a/public/language/he/error.json b/public/language/he/error.json index 394d88fc05..14bfd8104c 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -199,7 +199,7 @@ "not-in-room": "משתמש זה אינו בחדר הצ'אט", "cant-kick-self": "אינכם יכולים להסיר את עצמכם מהקבוצה", "no-users-selected": "לא נבחרו משתמשים", - "no-groups-selected": "No group(s) selected", + "no-groups-selected": "לא נבחרו קבוצות", "invalid-home-page-route": "כתובת דף הבית שגויה", "invalid-session": "סשן לא תקין", "invalid-session-text": "נראה שסשן ההתחברות שלכם אינה פעילה יותר. אנא רעננו את הדף.", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index d260609c25..fcc497043e 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -27,29 +27,29 @@ "chat.three_months": "3 חודשים", "chat.delete_message_confirm": "האם למחוק הודעה זו?", "chat.retrieving-users": "מאחזר משתמשים...", - "chat.view-users-list": "View users list", - "chat.public-rooms": "Public Rooms (%1)", - "chat.private-rooms": "Private Rooms (%1)", - "chat.create-room": "Create Chat Room", - "chat.private.option": "Private (Only visible to users added to room)", - "chat.public.option": "Public (Visible to every user in selected groups)", - "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", + "chat.view-users-list": "הצג רשימת משתמשים", + "chat.public-rooms": "חדרים ציבוריים (%1)", + "chat.private-rooms": "חדרים פרטיים (%1)", + "chat.create-room": "צור חדר צ'אט", + "chat.private.option": "פרטי (גלוי רק למשתמשים שנוספו לחדר)", + "chat.public.option": "ציבורי (גלוי לכל משתמש בקבוצות שנבחרו)", + "chat.public.groups-help": "כדי ליצור חדר צ'אט הגלוי לכל המשתמשים בחר \"משתמשים רשומים\" מרשימת הקבוצות.", "chat.manage-room": "ניהול חדר צ'אט", - "chat.add-user": "Add User", - "chat.select-groups": "Select Groups", + "chat.add-user": "הוסף משתמש", + "chat.select-groups": "בחר קבוצות", "chat.add-user-help": "חפשו משתמשים כאן. כאשר משתמש נבחר, הוא יצורף לצ'אט. המשתמש החדש לא יוכל לראות הודעות שנכתבו לפני הצטרפותו. רק מנהלי החדר () יכולים להסיר משתמשים מהצ'אט.", "chat.confirm-chat-with-dnd-user": "משתמש זה שינה את הסטטוס שלו ל'לא להפריע'. אתם עדיין מעוניין לשוחח איתו?", - "chat.room-name-optional": "Room Name (Optional)", + "chat.room-name-optional": "שם חד (אופציונלי)", "chat.rename-room": "שינוי שם חדר", "chat.rename-placeholder": "הזינו את שם החדר שלכם כאן", "chat.rename-help": "שם החדר המוגדר כאן יהיה זמין לכל המשתתפים בחדר.", "chat.leave": "Leave", - "chat.leave-room": "Leave Room", + "chat.leave-room": "עזוב חדר", "chat.leave-prompt": "האם לעזוב שיחה זו?", "chat.leave-help": "עזיבת שיחה, תסיר אתכם מהתכתבות עתידית בצ'אט זה. אם תצטרפו מחדש בעתיד, לא תראו את היסטוריית הצ'אט שלפני הצטרפותכם מחדש.", - "chat.delete": "Delete", - "chat.delete-room": "Delete Room", - "chat.delete-prompt": "Are you sure you wish to delete this chat room?", + "chat.delete": "מחיקה", + "chat.delete-room": "מחק חדר", + "chat.delete-prompt": "האם אתה בטוח שברצונך למחוק את חדר הצ'אט הזה?", "chat.in-room": "בתוך חדר זה", "chat.kick": "הוצא", "chat.show-ip": "הצג IP", diff --git a/public/language/it/admin/manage/groups.json b/public/language/it/admin/manage/groups.json index 11363639ed..978be53017 100644 --- a/public/language/it/admin/manage/groups.json +++ b/public/language/it/admin/manage/groups.json @@ -14,7 +14,7 @@ "hidden": "Nascosto", "private": "Privato", "edit": "Modifica", - "delete": "Cancella", + "delete": "Elimina", "privileges": "Privilegi", "members-csv": "Membri (CSV)", "search-placeholder": "Cerca", diff --git a/public/language/it/error.json b/public/language/it/error.json index 9f5975d10f..80ca66a53d 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -199,7 +199,7 @@ "not-in-room": "L'utente non è in questa stanza", "cant-kick-self": "Non puoi espellerti dal gruppo", "no-users-selected": "Nessun utente selezionato", - "no-groups-selected": "No group(s) selected", + "no-groups-selected": "Nessun gruppo(i) selezionato", "invalid-home-page-route": "Percorso della pagina iniziale non valido", "invalid-session": "Sessione non valida", "invalid-session-text": "Sembra che la tua sessione di accesso non sia più attiva. Si prega di aggiornare questa pagina.", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index c392de3990..42e451a1b4 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -27,29 +27,29 @@ "chat.three_months": "3 Mesi", "chat.delete_message_confirm": "Sei sicuro di voler eliminare questo messaggio?", "chat.retrieving-users": "Estrapolando gli utenti...", - "chat.view-users-list": "View users list", - "chat.public-rooms": "Public Rooms (%1)", - "chat.private-rooms": "Private Rooms (%1)", - "chat.create-room": "Create Chat Room", - "chat.private.option": "Private (Only visible to users added to room)", - "chat.public.option": "Public (Visible to every user in selected groups)", - "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", + "chat.view-users-list": "Visualizza elenco utenti", + "chat.public-rooms": "Stanze pubbliche (%1)", + "chat.private-rooms": "Stanze private (%1)", + "chat.create-room": "Crea stanza chat ", + "chat.private.option": "Privato (visibile solo agli utenti aggiunti alla stanza)", + "chat.public.option": "Pubblico (visibile a tutti gli utenti nei gruppi selezionati)", + "chat.public.groups-help": "Per creare una stanza chat visibile a tutti gli utenti, seleziona gli utenti registrati dall'elenco dei gruppi.", "chat.manage-room": "Gestisci stanza chat", - "chat.add-user": "Add User", - "chat.select-groups": "Select Groups", + "chat.add-user": "Aggiungi utente", + "chat.select-groups": "Seleziona gruppi", "chat.add-user-help": "Cerca qui gli utenti. Quando selezionato, l'utente sarà aggiunto alla chat.\nIl nuovo utente non sarà in grado di vedere i messaggi della chat scritti prima della sua partecipazione alla conversazione.\nSolo i proprietari della stanza () possono rimuovere gli utenti dalla stanza della chat.", "chat.confirm-chat-with-dnd-user": "Questo utente ha impostato il suo stato su Non Disturbare. Sei sicuro di voler iniziare una conversazione?", - "chat.room-name-optional": "Room Name (Optional)", + "chat.room-name-optional": "Nome stanza (facoltativo)", "chat.rename-room": "Rinomina stanza", "chat.rename-placeholder": "Inserisci qui il nome della stanza", "chat.rename-help": "Il nome della stanza qui impostato sarà visibile da tutti i partecipanti nella stanza.", - "chat.leave": "Leave", - "chat.leave-room": "Leave Room", + "chat.leave": "Lascia", + "chat.leave-room": "Lascia stanza", "chat.leave-prompt": "Sei sicuro di volere abbandonare questa chat?", "chat.leave-help": "Abbandonando questa chat perderai ogni sua traccia. Anche dopo un tuo eventuale rientro, non vedrai nessun messaggio precedente.", - "chat.delete": "Delete", - "chat.delete-room": "Delete Room", - "chat.delete-prompt": "Are you sure you wish to delete this chat room?", + "chat.delete": "Elimina", + "chat.delete-room": "Elimina stanza", + "chat.delete-prompt": "Sei sicuro di voler eliminare questa stanza chat?", "chat.in-room": "In questa stanza", "chat.kick": "Butta fuori", "chat.show-ip": "Mostra indirizzo IP", From 3b7b0d41d04cf9f5c33fcc3ebba4b436b3576f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 16 Jul 2023 12:06:45 -0400 Subject: [PATCH 099/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b90164d120..899b4d78c4 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.5", + "nodebb-theme-harmony": "1.1.6", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.1.2", "nodebb-theme-persona": "13.2.4", From 08491053c0f54efacffb96cda5e07d6087c3e3a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 16 Jul 2023 12:15:44 -0400 Subject: [PATCH 100/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 899b4d78c4..bda8f6f508 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.6", + "nodebb-theme-harmony": "1.1.7", "nodebb-theme-lavender": "7.1.1", "nodebb-theme-peace": "2.1.2", "nodebb-theme-persona": "13.2.4", From 6b017eb19cd430197d3c6c6cab35637ac3fe8af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 16 Jul 2023 19:49:54 -0400 Subject: [PATCH 101/300] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index bda8f6f508..ef14412f74 100644 --- a/install/package.json +++ b/install/package.json @@ -102,9 +102,9 @@ "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.1.7", - "nodebb-theme-lavender": "7.1.1", + "nodebb-theme-lavender": "7.1.2", "nodebb-theme-peace": "2.1.2", - "nodebb-theme-persona": "13.2.4", + "nodebb-theme-persona": "13.2.5", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.3", "nprogress": "0.2.0", From 3e7ca4f20e8a10641685a3d78eaacdf745518de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 16 Jul 2023 22:44:17 -0400 Subject: [PATCH 102/300] fix: unread notif filter --- src/api/chats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/chats.js b/src/api/chats.js index 1df828075d..f7dd083355 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -152,7 +152,7 @@ chatsAPI.mark = async (caller, data) => { match: `chat_*`, }); chatNids = chatNids.filter( - nid => nid && !nid.startsWith(`chat_${caller.uid}`) && nid.endsWith(`_${roomId}`) + nid => nid && !nid.startsWith(`chat_${caller.uid}_`) && nid.endsWith(`_${roomId}`) ); await notifications.markReadMultiple(chatNids, caller.uid); From fab76551c8ac7ea27b3f33759a0a6cc68492493b Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 17 Jul 2023 09:19:14 +0000 Subject: [PATCH 103/300] Latest translations and fallbacks --- public/language/bg/admin/settings/guest.json | 2 +- public/language/he/admin/advanced/logs.json | 2 +- public/language/he/modules.json | 2 +- public/language/it/admin/settings/guest.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/language/bg/admin/settings/guest.json b/public/language/bg/admin/settings/guest.json index 7a9cf58dda..32436ebbd7 100644 --- a/public/language/bg/admin/settings/guest.json +++ b/public/language/bg/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Настройки", - "guest-settings": "Guest Settings", + "guest-settings": "Настройки за гостите", "handles.enabled": "Позволяване на имената за гостите", "handles.enabled-help": "Тази възможност предоставя ново поле, което позволява на гостите да си изберат име, което да се използва за всяка публикация, която правят. Ако е изключено, всички те просто ще имат името „Гост“.", "topic-views.enabled": "Гостите да допринасят за броя на преглеждания на темите", diff --git a/public/language/he/admin/advanced/logs.json b/public/language/he/admin/advanced/logs.json index a86c26a223..5c1dd85a15 100644 --- a/public/language/he/admin/advanced/logs.json +++ b/public/language/he/admin/advanced/logs.json @@ -1,7 +1,7 @@ { "logs": "לוגים", "control-panel": "בקרת לוגים", - "reload": "טען מחדש לוג", + "reload": "טען לוג מחדש", "clear": "נקה לוגים", "clear-success": "הלוגים נוקו!" } \ No newline at end of file diff --git a/public/language/he/modules.json b/public/language/he/modules.json index fcc497043e..925d0790b0 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -39,7 +39,7 @@ "chat.select-groups": "בחר קבוצות", "chat.add-user-help": "חפשו משתמשים כאן. כאשר משתמש נבחר, הוא יצורף לצ'אט. המשתמש החדש לא יוכל לראות הודעות שנכתבו לפני הצטרפותו. רק מנהלי החדר () יכולים להסיר משתמשים מהצ'אט.", "chat.confirm-chat-with-dnd-user": "משתמש זה שינה את הסטטוס שלו ל'לא להפריע'. אתם עדיין מעוניין לשוחח איתו?", - "chat.room-name-optional": "שם חד (אופציונלי)", + "chat.room-name-optional": "שם חדר (אופציונלי)", "chat.rename-room": "שינוי שם חדר", "chat.rename-placeholder": "הזינו את שם החדר שלכם כאן", "chat.rename-help": "שם החדר המוגדר כאן יהיה זמין לכל המשתתפים בחדר.", diff --git a/public/language/it/admin/settings/guest.json b/public/language/it/admin/settings/guest.json index 13607d6b24..feeff7e25e 100644 --- a/public/language/it/admin/settings/guest.json +++ b/public/language/it/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Impostazioni", - "guest-settings": "Guest Settings", + "guest-settings": "Impostazioni ospite", "handles.enabled": "Consenti nome utente ospite", "handles.enabled-help": "Questa opzione mostra un nuovo campo che permette agli ospiti di scegliere un nome da associare ad ogni post che fanno. Se disabilitata, saranno semplicemente chiamati \"Ospite\".", "topic-views.enabled": "Consentire agli ospiti di aumentare il numero di visualizzazioni della discussione", From efc250f22fdc7d53c9aec0cf845d4a738241ae3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 17 Jul 2023 10:55:00 -0400 Subject: [PATCH 104/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index ef14412f74..b8f0b22a40 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.7", + "nodebb-theme-harmony": "1.1.8", "nodebb-theme-lavender": "7.1.2", "nodebb-theme-peace": "2.1.2", "nodebb-theme-persona": "13.2.5", From 48a04eb7777c7c2e7d956a179870d16450d6934b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 17 Jul 2023 15:33:41 -0400 Subject: [PATCH 105/300] chore: up composer --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b8f0b22a40..189a214533 100644 --- a/install/package.json +++ b/install/package.json @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.1.3", - "nodebb-plugin-composer-default": "10.2.4", + "nodebb-plugin-composer-default": "10.2.5", "nodebb-plugin-dbsearch": "6.1.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", From 4b92df75df6a7cd1027e6e54e82ad82f3c6c6bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 17 Jul 2023 22:17:13 -0400 Subject: [PATCH 106/300] chore: up mentions --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 189a214533..0654f45bff 100644 --- a/install/package.json +++ b/install/package.json @@ -97,7 +97,7 @@ "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", - "nodebb-plugin-mentions": "4.3.1", + "nodebb-plugin-mentions": "4.3.2", "nodebb-plugin-ntfy": "1.0.16", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", From 91642cb324c38d2f12b3f48718d91645e74fc531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 17 Jul 2023 22:42:00 -0400 Subject: [PATCH 107/300] feat: allow multiple room owners, closes #6503 --- public/language/en-GB/modules.json | 1 + public/openapi/components/schemas/Chats.yaml | 5 ++- .../read/user/userslug/chats/roomid.yaml | 6 ---- public/src/client/chats/manage.js | 13 +++++++ public/src/client/chats/recent.js | 4 +-- public/src/client/chats/user-list.js | 1 + src/api/chats.js | 7 ++-- src/messaging/rooms.js | 35 +++++++++++++++---- src/socket.io/modules.js | 25 ++++++++++++- src/upgrades/3.3.0/chat_room_owners.js | 34 ++++++++++++++++++ src/views/modals/create-room.tpl | 2 +- .../partials/chats/manage-room-users.tpl | 15 +++++--- test/messaging.js | 9 ++--- 13 files changed, 124 insertions(+), 33 deletions(-) create mode 100644 src/upgrades/3.3.0/chat_room_owners.js diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index 07f0f4515d..9d114b3fbc 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", diff --git a/public/openapi/components/schemas/Chats.yaml b/public/openapi/components/schemas/Chats.yaml index 7451c93542..3b7383c774 100644 --- a/public/openapi/components/schemas/Chats.yaml +++ b/public/openapi/components/schemas/Chats.yaml @@ -1,9 +1,6 @@ RoomObject: type: object properties: - owner: - type: number - description: the uid of the chat room owner (usually the user who created the room initially) roomId: type: number description: unique identifier for the chat room @@ -143,6 +140,8 @@ RoomUserList: type: boolean canKick: type: boolean + canToggleOwner: + type: boolean index: type: number online: diff --git a/public/openapi/read/user/userslug/chats/roomid.yaml b/public/openapi/read/user/userslug/chats/roomid.yaml index e8b0876eaf..a9a6ae9faf 100644 --- a/public/openapi/read/user/userslug/chats/roomid.yaml +++ b/public/openapi/read/user/userslug/chats/roomid.yaml @@ -24,8 +24,6 @@ get: allOf: - type: object properties: - owner: - type: number roomId: type: number roomName: @@ -173,10 +171,6 @@ get: items: type: object properties: - owner: - oneOf: - - type: number - - type: string roomId: type: number roomName: diff --git a/public/src/client/chats/manage.js b/public/src/client/chats/manage.js index 5936f58211..9edb7df0c3 100644 --- a/public/src/client/chats/manage.js +++ b/public/src/client/chats/manage.js @@ -35,6 +35,7 @@ define('forum/chats/manage', [ refreshParticipantsList(roomId, modal); addKickHandler(roomId, modal); + addToggleOwnerHandler(roomId, modal); const userListEl = modal.find('[component="chat/manage/user/list"]'); const userListElSearch = modal.find('[component="chat/manage/user/list/search"]'); @@ -89,6 +90,17 @@ define('forum/chats/manage', [ }); } + function addToggleOwnerHandler(roomId, modal) { + modal.on('click', '[data-action="toggleOwner"]', async function () { + const uid = parseInt(this.getAttribute('data-uid'), 10); + const $this = $(this); + await socket.emit('modules.chats.toggleOwner', { roomId: roomId, uid: uid }); + $this.parents('[data-uid]') + .find('[component="chat/manage/user/owner/icon"]') + .toggleClass('hidden'); + }); + } + async function refreshParticipantsList(roomId, modal, data) { const listEl = modal.find('[component="chat/manage/user/list"]'); @@ -101,6 +113,7 @@ define('forum/chats/manage', [ } listEl.html(await app.parseAndTranslate('partials/chats/manage-room-users', data)); + listEl.find('[data-bs-toggle="tooltip"]').tooltip(); } return manage; diff --git a/public/src/client/chats/recent.js b/public/src/client/chats/recent.js index 68a01b62ea..a4f6490f4b 100644 --- a/public/src/client/chats/recent.js +++ b/public/src/client/chats/recent.js @@ -19,13 +19,13 @@ define('forum/chats/recent', ['alerts', 'api', 'chat'], function (alerts, api, c chat.toggleReadState(chatEl); }); - $('[component="chat/recent"]').on('scroll', function () { + $('[component="chat/recent"]').on('scroll', utils.debounce(function () { const $this = $(this); const bottom = ($this[0].scrollHeight - $this.height()) * 0.9; if ($this.scrollTop() > bottom) { loadMoreRecentChats(); } - }); + }, 100)); }); }; diff --git a/public/src/client/chats/user-list.js b/public/src/client/chats/user-list.js index 419e699032..84fd8147f1 100644 --- a/public/src/client/chats/user-list.js +++ b/public/src/client/chats/user-list.js @@ -45,6 +45,7 @@ define('forum/chats/user-list', ['api'], function (api) { if (ajaxify.data.template.chats && app.isFocused && userListEl.scrollTop() === 0 && !userListEl.hasClass('hidden')) { const data = await api.get(`/chats/${roomId}/users`, { start: 0 }); userListEl.html(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); + userListEl.find('[data-bs-toggle="tooltip"]').tooltip(); } } diff --git a/src/api/chats.js b/src/api/chats.js index f7dd083355..029841648a 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -169,19 +169,22 @@ chatsAPI.users = async (caller, data) => { const start = data.hasOwnProperty('start') ? data.start : 0; const stop = start + 39; const io = require('../socket.io'); - const [isOwner, isUserInRoom, users, onlineUids] = await Promise.all([ + const [isOwner, isUserInRoom, users, isAdmin, onlineUids] = await Promise.all([ messaging.isRoomOwner(caller.uid, data.roomId), messaging.isUserInRoom(caller.uid, data.roomId), messaging.getUsersInRoomFromSet( `chat:room:${data.roomId}:uids:online`, data.roomId, start, stop, true ), + user.isAdministrator(caller.uid), io.getUidsInRoom(`chat_room_${data.roomId}`), ]); if (!isUserInRoom) { throw new Error('[[error:no-privileges]]'); } users.forEach((user) => { - user.canKick = isOwner && (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)); + const isSelf = parseInt(user.uid, 10) === parseInt(caller.uid, 10); + user.canKick = isOwner && !isSelf; + user.canToggleOwner = (isAdmin || isOwner) && !isSelf; user.online = parseInt(user.uid, 10) === parseInt(caller.uid, 10) || onlineUids.includes(String(user.uid)); }); return { users }; diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 9ab00ed7b6..bd6e3afaef 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -74,7 +74,6 @@ module.exports = function (Messaging) { const now = Date.now(); const roomId = await db.incrObjectField('global', 'nextChatRoomId'); const room = { - owner: uid, roomId: roomId, timestamp: now, }; @@ -93,6 +92,7 @@ module.exports = function (Messaging) { await Promise.all([ db.setObject(`chat:room:${roomId}`, room), db.sortedSetAdd('chat:rooms', now, roomId), + db.sortedSetAdd(`chat:room:${roomId}:owners`, now, uid), db.sortedSetsAdd([ `chat:room:${roomId}:uids`, `chat:room:${roomId}:uids:online`, @@ -143,6 +143,7 @@ module.exports = function (Messaging) { db.deleteAll([ ...roomIds.map(id => `chat:room:${id}`), ...roomIds.map(id => `chat:room:${id}:uids`), + ...roomIds.map(id => `chat:room:${id}:owners`), ...roomIds.map(id => `chat:room:${id}:uids:online`), ]), db.sortedSetRemove('chat:rooms', roomIds), @@ -207,16 +208,27 @@ module.exports = function (Messaging) { if (!isArray) { uids = [uids]; } - const owner = await db.getObjectField(`chat:room:${roomId}`, 'owner'); - const isOwners = uids.map(uid => parseInt(uid, 10) === parseInt(owner, 10)); + const isOwners = await db.isSortedSetMembers(`chat:room:${roomId}:owners`, uids); const result = await Promise.all(isOwners.map(async (isOwner, index) => { - const payload = await plugins.hooks.fire('filter:messaging.isRoomOwner', { uid: uids[index], roomId, owner, isOwner }); + const payload = await plugins.hooks.fire('filter:messaging.isRoomOwner', { uid: uids[index], roomId, isOwner }); return payload.isOwner; })); return isArray ? result : result[0]; }; + Messaging.toggleOwner = async (uid, roomId) => { + if (!(parseInt(uid, 10) > 0) || !roomId) { + return; + } + const isOwner = await Messaging.isRoomOwner(uid, roomId); + if (isOwner) { + await db.sortedSetRemove(`chat:room:${roomId}:owners`, uid); + } else { + await db.sortedSetAdd(`chat:room:${roomId}:owners`, Date.now(), uid); + } + }; + Messaging.isRoomPublic = async function (roomId) { return parseInt(await db.getObjectField(`chat:room:${roomId}`, 'public'), 10) === 1; }; @@ -285,6 +297,7 @@ module.exports = function (Messaging) { await Promise.all([ db.sortedSetRemove([ `chat:room:${roomId}:uids`, + `chat:room:${roomId}:owners`, `chat:room:${roomId}:uids:online`, ], uids), db.sortedSetsRemove(keys, roomId), @@ -301,6 +314,7 @@ module.exports = function (Messaging) { const roomKeys = [ ...roomIds.map(roomId => `chat:room:${roomId}:uids`), + ...roomIds.map(roomId => `chat:room:${roomId}:owners`), ...roomIds.map(roomId => `chat:room:${roomId}:uids:online`), ]; await Promise.all([ @@ -319,9 +333,16 @@ module.exports = function (Messaging) { }; async function updateOwner(roomId) { - const uids = await db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, 0); - const newOwner = uids[0] || 0; - await db.setObjectField(`chat:room:${roomId}`, 'owner', newOwner); + let nextOwner = await db.getSortedSetRange(`chat:room:${roomId}:owners`, 0, 0); + if (!nextOwner[0]) { + // no owners left grab next user + nextOwner = await db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, 0); + } + + const newOwner = nextOwner[0] || 0; + if (parseInt(newOwner, 10) > 0) { + await db.sortedSetAdd(`chat:room:${roomId}:owners`, Date.now(), newOwner); + } } Messaging.getAllUidsInRoomFromSet = async function (set) { diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 559bbdd5be..e244892d01 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -110,7 +110,13 @@ async function joinLeave(socket, roomIds, method, prefix = 'chat_room') { await Promise.all(roomIds.map(async (roomId, idx) => { const isPublic = roomData[idx] && roomData[idx].public; const roomGroups = roomData[idx] && roomData[idx].groups; - if (isAdmin || (inRooms[idx] && (!isPublic || await groups.isMemberOfAny(socket.uid, roomGroups)))) { + + if (isAdmin || + ( + inRooms[idx] && + (!isPublic || !roomGroups.length || await groups.isMemberOfAny(socket.uid, roomGroups)) + ) + ) { socket[method](`${prefix}_${roomId}`); } })); @@ -177,4 +183,21 @@ SocketModules.chats.searchMembers = async function (socket, data) { return { users: roomUsers }; }; +SocketModules.chats.toggleOwner = async (socket, data) => { + if (!data || !data.uid || !data.roomId) { + throw new Error('[[error:invalid-data]]'); + } + + const [isAdmin, inRoom, isRoomOwner] = await Promise.all([ + user.isAdministrator(socket.uid), + Messaging.isUserInRoom(socket.uid, data.roomId), + Messaging.isRoomOwner(socket.uid, data.roomId), + ]); + if (!isAdmin && (!inRoom || !isRoomOwner)) { + throw new Error('[[error:no-privileges]]'); + } + + await Messaging.toggleOwner(data.uid, data.roomId); +}; + require('../promisify')(SocketModules); diff --git a/src/upgrades/3.3.0/chat_room_owners.js b/src/upgrades/3.3.0/chat_room_owners.js new file mode 100644 index 0000000000..ddb4af3865 --- /dev/null +++ b/src/upgrades/3.3.0/chat_room_owners.js @@ -0,0 +1,34 @@ +'use strict'; + + +const db = require('../../database'); +const batch = require('../../batch'); + + +module.exports = { + name: 'Create chat:room::owners zset', + timestamp: Date.UTC(2023, 6, 17), + method: async function () { + const { progress } = this; + + progress.total = await db.sortedSetCard('chat:rooms'); + + await batch.processSortedSet('chat:rooms', async (roomIds) => { + progress.incr(roomIds.length); + const roomData = await db.getObjects( + roomIds.map(id => `chat:room:${id}`) + ); + + const bulkAdd = []; + roomData.forEach((room) => { + if (room && room.roomId && room.owner) { + bulkAdd.push([`chat:room:${room.roomId}:owners`, room.timestamp, room.owner]); + } + }); + + await db.sortedSetAddBulk(bulkAdd); + }, { + batch: 500, + }); + }, +}; diff --git a/src/views/modals/create-room.tpl b/src/views/modals/create-room.tpl index dcb470cd6e..4df85c294d 100644 --- a/src/views/modals/create-room.tpl +++ b/src/views/modals/create-room.tpl @@ -19,7 +19,7 @@ {{{ each selectedUsers }}}
      • {buildAvatar(@value, "24px", true)} {./username} - +
      • {{{ end }}} diff --git a/src/views/partials/chats/manage-room-users.tpl b/src/views/partials/chats/manage-room-users.tpl index 0c7a0c5c0f..8489cbb15b 100644 --- a/src/views/partials/chats/manage-room-users.tpl +++ b/src/views/partials/chats/manage-room-users.tpl @@ -1,12 +1,17 @@ {{{ each users }}} -
      • +
      • {buildAvatar(users, "24px", true)} - {./username}{{{ if ./isOwner }}} {{{ end }}} + {./username}
        +
        + {{{ if ./canToggleOwner }}} + + {{{ end }}} - {{{ if ./canKick }}} - - {{{ end }}} + {{{ if ./canKick }}} + + {{{ end }}} +
      • {{{ end }}} \ No newline at end of file diff --git a/test/messaging.js b/test/messaging.js index 24bbebfc19..9b07ff3670 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -226,8 +226,7 @@ describe('Messaging Library', () => { await callv3API('delete', `/chats/${roomId}/users/${mocks.users.baz.uid}`, {}, 'baz'); const isUserInRoom = await Messaging.isUserInRoom(mocks.users.baz.uid, roomId); assert.equal(isUserInRoom, false); - const data = await Messaging.getRoomData(roomId); - assert.equal(data.owner, mocks.users.foo.uid); + assert(await Messaging.isRoomOwner(mocks.users.foo.uid, roomId)); }); it('should send a user-leave system message when a user leaves the chat room', async () => { @@ -263,8 +262,7 @@ describe('Messaging Library', () => { await callv3API('delete', `/chats/${body.response.roomId}/users/${mocks.users.herp.uid}`, {}, 'herp'); - const data = await Messaging.getRoomData(body.response.roomId); - assert.equal(data.owner, mocks.users.foo.uid); + assert(await Messaging.isRoomOwner(mocks.users.foo.uid, roomId)); }); it('should change owner if owner is deleted', async () => { @@ -284,8 +282,7 @@ describe('Messaging Library', () => { }, }); await User.deleteAccount(sender); - const data = await Messaging.getRoomData(response.roomId); - assert.equal(data.owner, receiver); + assert(await Messaging.isRoomOwner(receiver, response.roomId)); }); it('should fail to remove user from room', async () => { From a7dae508ecbfc68639dab427642cf757e51a8078 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 18 Jul 2023 02:42:29 +0000 Subject: [PATCH 108/300] chore(i18n): fallback strings for new resources: nodebb.modules --- public/language/ar/modules.json | 1 + public/language/bg/modules.json | 1 + public/language/bn/modules.json | 1 + public/language/cs/modules.json | 1 + public/language/da/modules.json | 1 + public/language/de/modules.json | 1 + public/language/el/modules.json | 1 + public/language/en-US/modules.json | 1 + public/language/en-x-pirate/modules.json | 1 + public/language/es/modules.json | 1 + public/language/et/modules.json | 1 + public/language/fa-IR/modules.json | 1 + public/language/fi/modules.json | 1 + public/language/fr/modules.json | 1 + public/language/gl/modules.json | 1 + public/language/he/modules.json | 1 + public/language/hr/modules.json | 1 + public/language/hu/modules.json | 1 + public/language/hy/modules.json | 1 + public/language/id/modules.json | 1 + public/language/it/modules.json | 1 + public/language/ja/modules.json | 1 + public/language/ko/modules.json | 1 + public/language/lt/modules.json | 1 + public/language/lv/modules.json | 1 + public/language/ms/modules.json | 1 + public/language/nb/modules.json | 1 + public/language/nl/modules.json | 1 + public/language/pl/modules.json | 1 + public/language/pt-BR/modules.json | 1 + public/language/pt-PT/modules.json | 1 + public/language/ro/modules.json | 1 + public/language/ru/modules.json | 1 + public/language/rw/modules.json | 1 + public/language/sc/modules.json | 1 + public/language/sk/modules.json | 1 + public/language/sl/modules.json | 1 + public/language/sq-AL/modules.json | 1 + public/language/sr/modules.json | 33 ++++++++++++------------ public/language/sv/modules.json | 1 + public/language/th/modules.json | 1 + public/language/tr/modules.json | 1 + public/language/uk/modules.json | 1 + public/language/vi/modules.json | 1 + public/language/zh-CN/modules.json | 1 + public/language/zh-TW/modules.json | 1 + 46 files changed, 62 insertions(+), 16 deletions(-) diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index b056086291..14fb8d7a39 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index da07e9a1b4..225a61d2d1 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Изгонване", "chat.show-ip": "Показване на IP адреса", "chat.owner": "Собственик на стаята", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 се присъедини към стаята", "chat.system.user-leave": "%1 напусна стаята", "chat.system.room-rename": "%2 преименува тази стая: %1", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index d7d1a20825..6088d96ae3 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index c6c377fb9c..0b750313bb 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Vykopnout", "chat.show-ip": "Zobrazit IP", "chat.owner": "Majitel místnosti", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 se připojil k místnosti", "chat.system.user-leave": "%1 opustil místnost", "chat.system.room-rename": "%2 přejmenoval tuto místnost: %1", diff --git a/public/language/da/modules.json b/public/language/da/modules.json index b59998229f..d448c6d6fe 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index fdad54ed4b..90c8e23fb6 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Rauswerfen", "chat.show-ip": "IP anzeigen", "chat.owner": "Raumbesitzer", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 ist dem Raum beigetreten", "chat.system.user-leave": "%1 hat den Raum verlassen", "chat.system.room-rename": "%2 hat den Raum umbenannt: %1", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index 05f5807fa1..d6917f1c81 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/en-US/modules.json b/public/language/en-US/modules.json index 05f5807fa1..d6917f1c81 100644 --- a/public/language/en-US/modules.json +++ b/public/language/en-US/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/en-x-pirate/modules.json b/public/language/en-x-pirate/modules.json index 2f6f7d0487..3116610a92 100644 --- a/public/language/en-x-pirate/modules.json +++ b/public/language/en-x-pirate/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index eef7863278..634041c012 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index 7ae2cb934e..eb17f01921 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/fa-IR/modules.json b/public/language/fa-IR/modules.json index 1bace70e5d..2e4bb47b09 100644 --- a/public/language/fa-IR/modules.json +++ b/public/language/fa-IR/modules.json @@ -54,6 +54,7 @@ "chat.kick": "اخراج", "chat.show-ip": "نشان دادن IP", "chat.owner": "مدیر چت روم", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index 1f98a56893..55f86dce0b 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index f120d4fd83..1886f0361a 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Exclure", "chat.show-ip": "Voir IP", "chat.owner": "Espace Admin", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 a rejoint la discussion", "chat.system.user-leave": "%1 a quitté la discussion", "chat.system.room-rename": "%2 a renommé la discussion: %1", diff --git a/public/language/gl/modules.json b/public/language/gl/modules.json index 02bbb5a9c3..56232ccd1c 100644 --- a/public/language/gl/modules.json +++ b/public/language/gl/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index 925d0790b0..69904ed684 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -54,6 +54,7 @@ "chat.kick": "הוצא", "chat.show-ip": "הצג IP", "chat.owner": "מנהלי החדר", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 הצטרף לחדר", "chat.system.user-leave": "%1 יצא מהחדר", "chat.system.room-rename": "%2 שינה את שם החדר: %1", diff --git a/public/language/hr/modules.json b/public/language/hr/modules.json index 2bfef4fe7f..ab17f9929f 100644 --- a/public/language/hr/modules.json +++ b/public/language/hr/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index 648d64d749..63db09d574 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kirúgás", "chat.show-ip": "IP cím mutatása", "chat.owner": "Szoba tulajdonos", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 csatlakozott a szobához", "chat.system.user-leave": "%1 elhagyta a szobát", "chat.system.room-rename": "%2 megváltoztatta ennek a szobának a nevét: %1", diff --git a/public/language/hy/modules.json b/public/language/hy/modules.json index 1bd8032980..a30fea4b4a 100644 --- a/public/language/hy/modules.json +++ b/public/language/hy/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Ցույց տալ IP", "chat.owner": "Սենյակի սեփականատեր", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1-ը միացել է սենյակին", "chat.system.user-leave": "%1 դուրս է եկել սենյակից", "chat.system.room-rename": "%2-ը վերանվանել է այս սենյակը՝ %1", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index b5dc60f0e7..fbd944f1ca 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 42e451a1b4..80d49dd462 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Butta fuori", "chat.show-ip": "Mostra indirizzo IP", "chat.owner": "Propietario stanza", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 si è iscritto alla stanza", "chat.system.user-leave": "%1 ha lasciato la stanza", "chat.system.room-rename": "%2 ha rinominato questa stanza: %1", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index 88798bb517..7ba8596be1 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -54,6 +54,7 @@ "chat.kick": "キック", "chat.show-ip": "IP表示", "chat.owner": "部屋の管理者", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index 69f34746af..aaf66e705a 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -54,6 +54,7 @@ "chat.kick": "추방", "chat.show-ip": "IP 보이기", "chat.owner": "채팅 관리자", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1님이 입장하셨습니다.", "chat.system.user-leave": "%1님이 퇴장하셨습니다.", "chat.system.room-rename": "%2님의 채팅방 이름 변경: %1", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index fe4a4bebc5..aefebd4237 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/lv/modules.json b/public/language/lv/modules.json index 9a4e39bc1d..b1c8c70e84 100644 --- a/public/language/lv/modules.json +++ b/public/language/lv/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Izslēgt", "chat.show-ip": "Rādīt IP adresi", "chat.owner": "Tērzētavas īpašnieks", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index 02cb0c4037..7f811f93c1 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index d0eae25530..2d8cac650c 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index 8fee0946c5..b86f3c50be 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Schop", "chat.show-ip": "Geef IP weer", "chat.owner": "Chatroom-eigenaar", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 neemt nu deel aan de chatroom", "chat.system.user-leave": "%1 heeft de chatroom verlaten", "chat.system.room-rename": "%2 heeft deze chatroom hernoemd: %1", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 9d9021efb2..ef69f1a3d3 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Wyrzuć", "chat.show-ip": "Pokaż IP", "chat.owner": "Właściciel pokoju", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 dołączył(a) do pokoju", "chat.system.user-leave": "%1 opuścił(a) pokój", "chat.system.room-rename": "%2 zmienił(a) nazwę pokoju: %1", diff --git a/public/language/pt-BR/modules.json b/public/language/pt-BR/modules.json index 06d16e8752..91bb7f21c3 100644 --- a/public/language/pt-BR/modules.json +++ b/public/language/pt-BR/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", "chat.owner": "Dono da Sala", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 entrou na sala", "chat.system.user-leave": "%1 saiu da sala", "chat.system.room-rename": "%2 renomeou esta sala: %1", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index 96f3bcbcff..3a897738b4 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Expulsar", "chat.show-ip": "Mostrar IP", "chat.owner": "Dono da Sala", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 entrou na sala", "chat.system.user-leave": "%1 saiu da sala", "chat.system.room-rename": "%2 renomeou esta sala: %1", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index fcf29f083b..33b4c9d2b1 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index f1ca046db6..3f5a26ba5b 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Исключить", "chat.show-ip": "Показать IP", "chat.owner": "Владелец комнаты", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 присоединился к беседе", "chat.system.user-leave": "%1 покинул беседу", "chat.system.room-rename": "%2 переименовал беседу: %1", diff --git a/public/language/rw/modules.json b/public/language/rw/modules.json index 0b4a2cb3ac..c4ce295bfa 100644 --- a/public/language/rw/modules.json +++ b/public/language/rw/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index d7afcd8310..65dd4fa80c 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index 1ebff8e966..cd3f3833d2 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Vykopnúť", "chat.show-ip": "Zobraziť IP adresu", "chat.owner": "Majiteľ miestnosti", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/sl/modules.json b/public/language/sl/modules.json index d575d00a0a..1500e8b5bc 100644 --- a/public/language/sl/modules.json +++ b/public/language/sl/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Pokaži IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/sq-AL/modules.json b/public/language/sq-AL/modules.json index 1ce34f9498..d04fc96198 100644 --- a/public/language/sq-AL/modules.json +++ b/public/language/sq-AL/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Largo", "chat.show-ip": "Shfaq IP", "chat.owner": "Administratori i hapësirës", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 i është bashkuar hapësirës", "chat.system.user-leave": "%1 ka dalë nga hapësira", "chat.system.room-rename": "%2 e ka riemërtuar këtë hapësirë: %1", diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index 078377f0a0..45f4402bb0 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -27,33 +27,34 @@ "chat.three_months": "3 месеца", "chat.delete_message_confirm": "Да ли сте сигурни да желите да избришете ову поруку?", "chat.retrieving-users": "Преузимање корисника...", - "chat.view-users-list": "View users list", - "chat.public-rooms": "Public Rooms (%1)", - "chat.private-rooms": "Private Rooms (%1)", - "chat.create-room": "Create Chat Room", - "chat.private.option": "Private (Only visible to users added to room)", - "chat.public.option": "Public (Visible to every user in selected groups)", - "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", + "chat.view-users-list": "Погледај листу корисника", + "chat.public-rooms": "Јавне собе (%1)", + "chat.private-rooms": "Приватне собе (%1)", + "chat.create-room": "Креирај собу за ћаскање", + "chat.private.option": "Приватно (видљиво само корисницима додатим у собу)", + "chat.public.option": "Јавно (видљиво сваком кориснику у изабраним групама)", + "chat.public.groups-help": "За креирање собе за ћаскање која је видљива свим корисницима, изаберите регистроване кориснике са листе група.", "chat.manage-room": "Управљај собом за ћаскање", - "chat.add-user": "Add User", - "chat.select-groups": "Select Groups", + "chat.add-user": "Додај корисника", + "chat.select-groups": "Изаберите групе", "chat.add-user-help": "Потражите кориснике овде. Када буде изабран, корисник ће бити додан у ћаскање. Нови корисник неће бити у могућности да види поруке написане пре него што је додан у преписку. Само власници соба () могу уклонити кориснике из соба за ћаскање.", - "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на \"Не узнемиравај\". Да ли и даље желите да ћаскате са њим?", - "chat.room-name-optional": "Room Name (Optional)", + "chat.confirm-chat-with-dnd-user": "Овај корисник је поставио свој статус на „Не узнемиравај”. Да ли и даље желите да ћаскате са њим?", + "chat.room-name-optional": "Име собе (опционо)", "chat.rename-room": "Преименуј собу", "chat.rename-placeholder": "Унесите назив собе овде", "chat.rename-help": "Име собе постављено овде биће видљиво свим учесницима у соби.", - "chat.leave": "Leave", - "chat.leave-room": "Leave Room", + "chat.leave": "Напусти", + "chat.leave-room": "Напусти собу", "chat.leave-prompt": "Да ли сте сигурни да желите да напустите ово ћаскање?", "chat.leave-help": "Напуштање овог ћаскања ће вас уклонити из будућих преписки у овом ћаскању. Ако будете поново додани у будућности, нећете видети историју ћаскања од пре вашег поновног придруживања.", - "chat.delete": "Delete", - "chat.delete-room": "Delete Room", - "chat.delete-prompt": "Are you sure you wish to delete this chat room?", + "chat.delete": "Избриши", + "chat.delete-room": "Избриши собу", + "chat.delete-prompt": "Да ли сте сигурни да желите да избришете ову собу за ћаскање?", "chat.in-room": "У овој соби", "chat.kick": "Избаци", "chat.show-ip": "Прикажи IP", "chat.owner": "Власник собе", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 се придружио соби", "chat.system.user-leave": "%1 је напустио собу", "chat.system.room-rename": "%2 је преименовао собу: %1", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 3ec3cd1eae..42274d2f02 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Sparka ut", "chat.show-ip": "Visa IP", "chat.owner": "Rummets ägare", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 har anslutit till rummet", "chat.system.user-leave": "%1 har lämnat rummet", "chat.system.room-rename": "%2 har döpt om rummet: %1", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index 9d287d729f..421ac4d22c 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Kick", "chat.show-ip": "Show IP", "chat.owner": "Room Owner", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 has joined the room", "chat.system.user-leave": "%1 has left the room", "chat.system.room-rename": "%2 has renamed this room: %1", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 51ef7af90e..113c91d5f4 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Dışarı At", "chat.show-ip": "IP Göster", "chat.owner": "Oda Sahibi", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 odaya katıldı", "chat.system.user-leave": "%1 odadan çıktı", "chat.system.room-rename": "%2 şu grubun ismini değiştirdi: %1", diff --git a/public/language/uk/modules.json b/public/language/uk/modules.json index 15732c3e12..8d755a5fc9 100644 --- a/public/language/uk/modules.json +++ b/public/language/uk/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Штурхнути", "chat.show-ip": "Показати IP", "chat.owner": "Власник кімнати", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 зайшов в кімнату", "chat.system.user-leave": "%1 покинув кімнату", "chat.system.room-rename": "%2 перейменував кімнату на: %1", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 3eefa5fd2d..808e7b0315 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -54,6 +54,7 @@ "chat.kick": "Loại ra", "chat.show-ip": "Hiện IP", "chat.owner": "Chủ Phòng", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 đã vào phòng", "chat.system.user-leave": "%1 đã rời phòng", "chat.system.room-rename": "%2 đã đổi tên phòng: %1", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index b1f6f7ad8c..93135173ff 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -54,6 +54,7 @@ "chat.kick": "踢出", "chat.show-ip": "显示 IP", "chat.owner": "房间所有者", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 加入了房间", "chat.system.user-leave": "%1 离开了房间", "chat.system.room-rename": "%2 更改房间名为:%1", diff --git a/public/language/zh-TW/modules.json b/public/language/zh-TW/modules.json index 37e0d91642..534e79dcfd 100644 --- a/public/language/zh-TW/modules.json +++ b/public/language/zh-TW/modules.json @@ -54,6 +54,7 @@ "chat.kick": "踢出", "chat.show-ip": "顯示 IP", "chat.owner": "房間所有者", + "chat.grant-rescind-ownership": "Grant/Rescind Ownership", "chat.system.user-join": "%1 加入了房間", "chat.system.user-leave": "%1 離開了房間", "chat.system.room-rename": "%2 更改房間名為:%1", From 16fe1eb98cb95e8f1c99b1aa5810c93b5dafa181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 17 Jul 2023 22:49:02 -0400 Subject: [PATCH 109/300] fix: updateOwner if there is another owner don't do anything if not then make the next user in the room the owner --- src/messaging/rooms.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index bd6e3afaef..2b212b7b74 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -334,14 +334,13 @@ module.exports = function (Messaging) { async function updateOwner(roomId) { let nextOwner = await db.getSortedSetRange(`chat:room:${roomId}:owners`, 0, 0); - if (!nextOwner[0]) { + if (!nextOwner.length) { // no owners left grab next user nextOwner = await db.getSortedSetRange(`chat:room:${roomId}:uids`, 0, 0); - } - - const newOwner = nextOwner[0] || 0; - if (parseInt(newOwner, 10) > 0) { - await db.sortedSetAdd(`chat:room:${roomId}:owners`, Date.now(), newOwner); + const newOwner = nextOwner[0] || 0; + if (parseInt(newOwner, 10) > 0) { + await db.sortedSetAdd(`chat:room:${roomId}:owners`, Date.now(), newOwner); + } } } From 6e2d49e405192662a2f9dec6adf91d06ded9055e Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 18 Jul 2023 09:19:12 +0000 Subject: [PATCH 110/300] Latest translations and fallbacks --- public/language/bg/modules.json | 2 +- public/language/sr/error.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 225a61d2d1..9b6d3bd35f 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -54,7 +54,7 @@ "chat.kick": "Изгонване", "chat.show-ip": "Показване на IP адреса", "chat.owner": "Собственик на стаята", - "chat.grant-rescind-ownership": "Grant/Rescind Ownership", + "chat.grant-rescind-ownership": "Даване/отнемане на собственост", "chat.system.user-join": "%1 се присъедини към стаята", "chat.system.user-leave": "%1 напусна стаята", "chat.system.room-rename": "%2 преименува тази стая: %1", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index e6dcd287dd..1940af289e 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -199,7 +199,7 @@ "not-in-room": "Корисник није у соби", "cant-kick-self": "Не можете избацити себе из групе", "no-users-selected": "Није одабран корисник", - "no-groups-selected": "No group(s) selected", + "no-groups-selected": "Није изабрана ниједна група.", "invalid-home-page-route": "Неважећа путања матичне странице", "invalid-session": "Неважећа сесија", "invalid-session-text": "Изгледа да ваша сесија пријављивања није више активна. Поново учитајте ову страницу.", From 86dd04d5fd0d9a0beda054552ef254bc20a90094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 18 Jul 2023 09:46:51 -0400 Subject: [PATCH 111/300] get rid of tooltips before refreshing list --- public/src/client/chats/manage.js | 2 +- public/src/client/chats/user-list.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/public/src/client/chats/manage.js b/public/src/client/chats/manage.js index 9edb7df0c3..065a970606 100644 --- a/public/src/client/chats/manage.js +++ b/public/src/client/chats/manage.js @@ -111,7 +111,7 @@ define('forum/chats/manage', [ listEl.find('li').text(await translator.translate('[[error:invalid-data]]')); } } - + listEl.find('[data-bs-toggle="tooltip"]').tooltip('dispose'); listEl.html(await app.parseAndTranslate('partials/chats/manage-room-users', data)); listEl.find('[data-bs-toggle="tooltip"]').tooltip(); } diff --git a/public/src/client/chats/user-list.js b/public/src/client/chats/user-list.js index 84fd8147f1..2b936c0698 100644 --- a/public/src/client/chats/user-list.js +++ b/public/src/client/chats/user-list.js @@ -44,6 +44,7 @@ define('forum/chats/user-list', ['api'], function (api) { async function updateUserList(roomId, userListEl) { if (ajaxify.data.template.chats && app.isFocused && userListEl.scrollTop() === 0 && !userListEl.hasClass('hidden')) { const data = await api.get(`/chats/${roomId}/users`, { start: 0 }); + userListEl.find('[data-bs-toggle="tooltip"]').tooltip('dispose'); userListEl.html(await app.parseAndTranslate('partials/chats/user-list', 'users', data)); userListEl.find('[data-bs-toggle="tooltip"]').tooltip(); } From 00be053e948f0db210ba23527aa0ae594540418c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 18 Jul 2023 12:38:17 -0400 Subject: [PATCH 112/300] fix: topic postercount field if owner is changed also fix when posts are purged --- src/posts/delete.js | 10 ++++++++++ src/posts/user.js | 3 +++ test/posts.js | 4 +++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/posts/delete.js b/src/posts/delete.js index fb285b5128..66c8269334 100644 --- a/src/posts/delete.js +++ b/src/posts/delete.js @@ -116,7 +116,9 @@ module.exports = function (Posts) { const topicPostCountTasks = []; const topicTasks = []; const zsetIncrBulk = []; + const tids = []; for (const [tid, posts] of Object.entries(postsByTopic)) { + tids.push(tid); incrObjectBulk.push([`topic:${tid}`, { postcount: -posts.length }]); if (posts.length && posts[0]) { const topicData = posts[0].topic; @@ -142,6 +144,14 @@ module.exports = function (Posts) { user.updatePostCount(_.uniq(postData.map(p => p.uid))), notifications.rescind(...postData.map(p => `new_post:tid:${p.tid}:pid:${p.pid}:uid:${p.uid}`)), ]); + const tidPosterZsets = tids.map(tid => `tid:${tid}:posters`); + await db.sortedSetsRemoveRangeByScore(tidPosterZsets, '-inf', 0); + const posterCounts = await db.sortedSetsCard(tidPosterZsets); + await db.setObjectBulk( + tids.map((tid, idx) => ( + [`topic:${tid}`, { postercount: posterCounts[idx] || 0 }] + )) + ); } async function deleteFromCategoryRecentPosts(postData) { diff --git a/src/posts/user.js b/src/posts/user.js index 960e4960a6..4d9ab4d21e 100644 --- a/src/posts/user.js +++ b/src/posts/user.js @@ -206,6 +206,9 @@ module.exports = function (Posts) { await async.eachOf(postsByUser, async (posts, uid) => { await db.sortedSetIncrBy(`tid:${tid}:posters`, -posts.length, uid); }); + await db.sortedSetsRemoveRangeByScore([`tid:${tid}:posters`], '-inf', 0); + const posterCount = await db.sortedSetCard(`tid:${tid}:posters`); + await topics.setTopicField(tid, 'postercount', posterCount); }); } diff --git a/test/posts.js b/test/posts.js index 866fc3b529..ef4069ec81 100644 --- a/test/posts.js +++ b/test/posts.js @@ -114,7 +114,7 @@ describe('Post\'s', () => { await posts.changeOwner([pid1, pid2], newUid); - assert.deepStrictEqual(await db.sortedSetScores(`tid:${postResult.topicData.tid}:posters`, [oldUid, newUid]), [0, 2]); + assert.deepStrictEqual(await db.sortedSetScores(`tid:${postResult.topicData.tid}:posters`, [oldUid, newUid]), [null, 2]); assert.deepStrictEqual(await posts.isOwner([pid1, pid2], oldUid), [false, false]); assert.deepStrictEqual(await posts.isOwner([pid1, pid2], newUid), [true, true]); @@ -130,6 +130,8 @@ describe('Post\'s', () => { assert.strictEqual(await topics.isOwner(postResult.topicData.tid, oldUid), false); assert.strictEqual(await topics.isOwner(postResult.topicData.tid, newUid), true); + + assert.strictEqual(await topics.getTopicField(postResult.topicData.tid, 'postercount'), 1); }); it('should fail to change owner if new owner does not exist', async () => { From eb0fcd3235606cbeb5e092cb1fc8dfcd52f970b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 18 Jul 2023 13:12:06 -0400 Subject: [PATCH 113/300] feat: closes #11812, add unread public rooms into digest --- public/language/en-GB/email.json | 2 ++ src/user/digest.js | 16 +++++++++++++--- src/views/emails/digest.tpl | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/public/language/en-GB/email.json b/public/language/en-GB/email.json index 15cbf3cf26..3f8043cc67 100644 --- a/public/language/en-GB/email.json +++ b/public/language/en-GB/email.json @@ -30,6 +30,8 @@ "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/src/user/digest.js b/src/user/digest.js index d45cf8e576..b07f54d1c3 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -8,6 +8,7 @@ const batch = require('../batch'); const meta = require('../meta'); const user = require('./index'); const topics = require('../topics'); +const messaging = require('../messaging'); const plugins = require('../plugins'); const emailer = require('../emailer'); const utils = require('../utils'); @@ -94,13 +95,16 @@ Digest.send = async function (data) { return; } await Promise.all(userData.map(async (userObj) => { - const [notifications, topics] = await Promise.all([ + const [publicRooms, notifications, topics] = await Promise.all([ + getUnreadPublicRooms(userObj.uid), user.notifications.getUnreadInterval(userObj.uid, data.interval), getTermTopics(data.interval, userObj.uid), ]); const unreadNotifs = notifications.filter(Boolean); - // If there are no notifications and no new topics, don't bother sending a digest - if (!unreadNotifs.length && !topics.top.length && !topics.popular.length && !topics.recent.length) { + // If there are no notifications and no new topics and no unread chats, don't bother sending a digest + if (!unreadNotifs.length && + !topics.top.length && !topics.popular.length && !topics.recent.length && + !publicRooms.length) { return; } @@ -120,6 +124,7 @@ Digest.send = async function (data) { username: userObj.username, userslug: userObj.userslug, notifications: unreadNotifs, + publicRooms: publicRooms, recent: topics.recent, topTopics: topics.top, popularTopics: topics.popular, @@ -212,3 +217,8 @@ async function getTermTopics(term, uid) { }); return { top, popular, recent }; } + +async function getUnreadPublicRooms(uid) { + const publicRooms = await messaging.getPublicRooms(uid, uid); + return publicRooms.filter(r => r && r.unread); +} diff --git a/src/views/emails/digest.tpl b/src/views/emails/digest.tpl index b6d827187c..cd278d6c6f 100644 --- a/src/views/emails/digest.tpl +++ b/src/views/emails/digest.tpl @@ -43,6 +43,26 @@
        +

        [[email:digest.unread-rooms]]

        + +
        From 3613d1e6230e32b68e5fc66701a454f0a1746efa Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 18 Jul 2023 17:12:32 +0000 Subject: [PATCH 114/300] chore(i18n): fallback strings for new resources: nodebb.email --- public/language/ar/email.json | 2 ++ public/language/bg/email.json | 2 ++ public/language/bn/email.json | 2 ++ public/language/cs/email.json | 2 ++ public/language/da/email.json | 2 ++ public/language/de/email.json | 2 ++ public/language/el/email.json | 2 ++ public/language/en-US/email.json | 2 ++ public/language/en-x-pirate/email.json | 2 ++ public/language/es/email.json | 2 ++ public/language/et/email.json | 2 ++ public/language/fa-IR/email.json | 2 ++ public/language/fi/email.json | 2 ++ public/language/fr/email.json | 2 ++ public/language/gl/email.json | 2 ++ public/language/he/email.json | 2 ++ public/language/hr/email.json | 2 ++ public/language/hu/email.json | 2 ++ public/language/hy/email.json | 2 ++ public/language/id/email.json | 2 ++ public/language/it/email.json | 2 ++ public/language/ja/email.json | 2 ++ public/language/ko/email.json | 2 ++ public/language/lt/email.json | 2 ++ public/language/lv/email.json | 2 ++ public/language/ms/email.json | 2 ++ public/language/nb/email.json | 2 ++ public/language/nl/email.json | 2 ++ public/language/pl/email.json | 2 ++ public/language/pt-BR/email.json | 2 ++ public/language/pt-PT/email.json | 2 ++ public/language/ro/email.json | 2 ++ public/language/ru/email.json | 2 ++ public/language/rw/email.json | 2 ++ public/language/sc/email.json | 2 ++ public/language/sk/email.json | 2 ++ public/language/sl/email.json | 2 ++ public/language/sq-AL/email.json | 2 ++ public/language/sr/email.json | 2 ++ public/language/sv/email.json | 2 ++ public/language/th/email.json | 2 ++ public/language/tr/email.json | 2 ++ public/language/uk/email.json | 2 ++ public/language/vi/email.json | 2 ++ public/language/zh-CN/email.json | 2 ++ public/language/zh-TW/email.json | 2 ++ 46 files changed, 92 insertions(+) diff --git a/public/language/ar/email.json b/public/language/ar/email.json index f807ddbfa3..8ee0473c61 100644 --- a/public/language/ar/email.json +++ b/public/language/ar/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "تم تغيير كلمة المرور بنجاح", "reset.notify.text1": "نحيطك علما أن كلمة مرورك قد تم تغييرها في %1", "reset.notify.text2": "إن لم يكن لديك علم بهذا، المرجو إشعار مدبر النظام بأسرع مايمكن.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "آخر المستجدات من %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/bg/email.json b/public/language/bg/email.json index b7d616f427..8bf5ee7c1d 100644 --- a/public/language/bg/email.json +++ b/public/language/bg/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Паролата беше променена успешно", "reset.notify.text1": "Известяваме Ви, че на %1, Вашата парола беше променена успешно.", "reset.notify.text2": "Ако не сте поискали това, моля, свържете се незабавно с администратор.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Последни теми от %1", "digest.top-topics": "Най-интересните теми от %1", "digest.popular-topics": "Популярни теми от %1", diff --git a/public/language/bn/email.json b/public/language/bn/email.json index a8870a96bb..89e667c75f 100644 --- a/public/language/bn/email.json +++ b/public/language/bn/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "পাসওয়ার্ড পরিবর্তন সফল হয়েছে", "reset.notify.text1": "আপনাকে জানাচ্ছি যে %1 এ আপনার পাসওয়ার্ড পরিবর্তন হয়েছে", "reset.notify.text2": "এটা আপনার অজান্তে হলে এখনই প্রশাসককে আবহিত করুন", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "%1 এর সর্বশেষ টপিকসমূহ", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/cs/email.json b/public/language/cs/email.json index fada8d0597..8ee84565ae 100644 --- a/public/language/cs/email.json +++ b/public/language/cs/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Heslo úspěšně změněno", "reset.notify.text1": "Informujeme Vás, že na %1 vaše heslo bylo úspěšně změněno.", "reset.notify.text2": "Pokud jste to neschválil, prosíme neprodleně kontaktujte správce.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Nejnovější témata od %1", "digest.top-topics": "Nejlepší témata od %1", "digest.popular-topics": "Oblíbená témata od %1", diff --git a/public/language/da/email.json b/public/language/da/email.json index f8fe687dff..2687f24acb 100644 --- a/public/language/da/email.json +++ b/public/language/da/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Dit kodeord er nu ændret", "reset.notify.text1": "Bemærk: %1 gang blev dit kodeord ændret.", "reset.notify.text2": "Hvis du ikke godkendte dette, kontakt straks en administrator.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Nyeste emne fra %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/de/email.json b/public/language/de/email.json index 212334e87f..f025b5fcdd 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Passwort erfolgreich geändert", "reset.notify.text1": "Wir benachrichtigen dich, dass dein Passwort am %1 erfolgreich geändert wurde.", "reset.notify.text2": "Bitte benachrichtige umgehend einen Administrator, wenn du dies nicht autorisiert hast.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Neueste Themen auf %1", "digest.top-topics": "Top-Themen von %1", "digest.popular-topics": "Beliebte Themen von %1", diff --git a/public/language/el/email.json b/public/language/el/email.json index 83a2f5c64e..fd5957829e 100644 --- a/public/language/el/email.json +++ b/public/language/el/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Πρόσφατα θέματα στο %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/en-US/email.json b/public/language/en-US/email.json index 9f748a2e61..3e35d7514c 100644 --- a/public/language/en-US/email.json +++ b/public/language/en-US/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/en-x-pirate/email.json b/public/language/en-x-pirate/email.json index fe7ea95293..e31b3cf3cd 100644 --- a/public/language/en-x-pirate/email.json +++ b/public/language/en-x-pirate/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/es/email.json b/public/language/es/email.json index aba236eb0d..a07a86913e 100644 --- a/public/language/es/email.json +++ b/public/language/es/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Se ha modificado correctamente la contraseña.", "reset.notify.text1": "Te estamos notificando que en %1, tu contraseña ha sido cambiada correctamente.", "reset.notify.text2": "Si no has sido tú, por favor notifica al administrador inmediatamente.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Últimos temas de %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/et/email.json b/public/language/et/email.json index ae0b32b56a..7bb5323856 100644 --- a/public/language/et/email.json +++ b/public/language/et/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Parool edukalt muudetud", "reset.notify.text1": "Teatame, et sinu parooli muutmine kuupäeval %1 oli edukas.", "reset.notify.text2": "Kui te ei ole lubanud seda, siis teavitage koheselt administraatorit.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Viimased teemad %1 poolt", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/fa-IR/email.json b/public/language/fa-IR/email.json index cc9a6b6964..64225662e5 100644 --- a/public/language/fa-IR/email.json +++ b/public/language/fa-IR/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "کلمه عبور با موفقیت تغییر کرد", "reset.notify.text1": "به شما اعلام میداریم که در %1، کلمه عبور شما با موفقیت بازنشانی شد.", "reset.notify.text2": "اگر این را تایید نمیکنید، لطفا بلافاصله به یک مدیر اطلاع دهید.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "آخرین پست های %1:", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/fi/email.json b/public/language/fi/email.json index 9147b31642..f0e2f1e2fa 100644 --- a/public/language/fi/email.json +++ b/public/language/fi/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Salasana onnistuneesti vaihdettu", "reset.notify.text1": "Ilmoitamme sinua että %1, salasanasi vaihdettiin onnistuneesti.", "reset.notify.text2": "Jos et tunnista tätä toimintoa, ilmoita välittömästi ylläpitäjälle.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Viimeisimmät viestiketjut henkilöltä %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/fr/email.json b/public/language/fr/email.json index 21542e57d6..f17e26ee17 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Mot de passe modifié", "reset.notify.text1": "Nous vous informons que le %1, votre mot de passe a été modifié.", "reset.notify.text2": "Si vous n'avez pas autorisé ceci, veuillez contacter immédiatement un administrateur.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Derniers sujets de %1 :", "digest.top-topics": "Meilleurs sujets de %1", "digest.popular-topics": "Sujets populaires de %1", diff --git a/public/language/gl/email.json b/public/language/gl/email.json index ca56e064bd..6cd015df60 100644 --- a/public/language/gl/email.json +++ b/public/language/gl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Contrasinal cambiado", "reset.notify.text1": "Estámosche a notificar que nun %1, o seu contrasinal foi cambiado correctamente.", "reset.notify.text2": "Se ti non autorizache isto, por favor notifica inmediatamente a un administrador.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Últimos temas de %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/he/email.json b/public/language/he/email.json index ef5916f6db..d3d46db336 100644 --- a/public/language/he/email.json +++ b/public/language/he/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "הסיסמה שונתה בהצלחה.", "reset.notify.text1": "אנו מודיעים לך שב%1, סיסמתך שונתה בהצלחה.", "reset.notify.text2": "אם לא אישרת בקשה זו, אנא הודע למנהל מיד.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "נושאים אחרונים מ%1", "digest.top-topics": "נושאים עם הכי הרבה הצבעות מ-%1", "digest.popular-topics": "הנושאים הכי פופולריים מ-%1", diff --git a/public/language/hr/email.json b/public/language/hr/email.json index 3367f4ef06..f2bbfc0ab2 100644 --- a/public/language/hr/email.json +++ b/public/language/hr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Lozinka uspješno promijenjena.", "reset.notify.text1": "Obavještavamo vas da vam je lozinka na %1 uspješno promijenjena.", "reset.notify.text2": "Ako niste ovo odobrili, molimo vas obavijestite administratora.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Posljednje teme s %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/hu/email.json b/public/language/hu/email.json index c2594b9d37..19ff665c48 100644 --- a/public/language/hu/email.json +++ b/public/language/hu/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Jelszó sikeresen módosítva", "reset.notify.text1": "Értesítünk, hogy a(z) %1 névhez tartozó jelszavad sikeresen megváltozott.", "reset.notify.text2": "Ha nem te voltál az, kérlek, azonnal értesíts egy adminisztrátort.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Legutóbbi témakörök a következőből: %1", "digest.top-topics": "Legfontosabb témakörök innen: %1", "digest.popular-topics": "Népszerű témakörök innen: %1", diff --git a/public/language/hy/email.json b/public/language/hy/email.json index 891b72ad04..d14651774b 100644 --- a/public/language/hy/email.json +++ b/public/language/hy/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Գաղտնաբառը հաջողությամբ փոխված է", "reset.notify.text1": "Մենք ծանուցում ենք ձեզ, որ %1-ում ձեր գաղտնաբառը հաջողությամբ փոխվել է:", "reset.notify.text2": "Եթե դուք չեք թույլատրել սա, խնդրում ենք անմիջապես տեղեկացնել ադմինիստրատորին:", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Վերջին թեմաները %1-ից", "digest.top-topics": "Հիմնական թեմաները %1-ից", "digest.popular-topics": "Հանրաճանաչ թեմաներ %1-ից", diff --git a/public/language/id/email.json b/public/language/id/email.json index 7ccd3ff608..e4c86cf523 100644 --- a/public/language/id/email.json +++ b/public/language/id/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Kata Sandi berhasil diganti", "reset.notify.text1": "Kami beritahukan bahwa pada %1 password anda berhasil diubah.", "reset.notify.text2": "Jika ini bukan kehendak anda, silakan segera hubungi administrator.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Topik-topik terbaru dari %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/it/email.json b/public/language/it/email.json index e6cc55ba1b..6064f59210 100644 --- a/public/language/it/email.json +++ b/public/language/it/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password modificata con successo.", "reset.notify.text1": "Ti informiamo che il %1, la password è stata cambiata con successo.", "reset.notify.text2": "Se non hai autorizzato questo, per favore informa immediatamente l'amministratore.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ultime discussioni da %1", "digest.top-topics": "Argomenti principali da %1", "digest.popular-topics": "Argomenti popolari da %1", diff --git a/public/language/ja/email.json b/public/language/ja/email.json index 4a26703cda..de460531ba 100644 --- a/public/language/ja/email.json +++ b/public/language/ja/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "パスワードをリセットしました", "reset.notify.text1": "%1にてパスワードのリセットが行われたことをお知らせします。", "reset.notify.text2": "もしあなたがリセットを行っていない場合は、すぐに管理者に通報してください。", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "%1からの新しいスレッド", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ko/email.json b/public/language/ko/email.json index 8209341327..a035d592de 100644 --- a/public/language/ko/email.json +++ b/public/language/ko/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "비밀번호가 성공적으로 변경되었습니다.", "reset.notify.text1": "%1에 관해 통지합니다. 귀하의 비밀번호가 성공적으로 변경되었습니다.", "reset.notify.text2": "만약 이 인증을 요청하지 않았다면 즉시 관리자에게 통보하시기 바랍니다.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "%1의 최근 주제", "digest.top-topics": "%1의 TOP 주제", "digest.popular-topics": "%1의 인기 주제", diff --git a/public/language/lt/email.json b/public/language/lt/email.json index 6b505399b7..d0cd26dd08 100644 --- a/public/language/lt/email.json +++ b/public/language/lt/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Slaptažodis sėkmingai pakeistas", "reset.notify.text1": "Mes tikriname ar jūs tikrai esate %1, jūsų slaptažodis buvo pakeistas sėkmingai", "reset.notify.text2": "Jeigu jūs neprašėte šito, prašome perspėti administratoriu nedelsiant", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Paskutinės temos iš %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/lv/email.json b/public/language/lv/email.json index 8767a5552d..ff037d7d0c 100644 --- a/public/language/lv/email.json +++ b/public/language/lv/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Parole veiksmīgi mainīta", "reset.notify.text1": "Mēs Tevi informējam, ka %1 Tava parole tika veiksmīgi mainīta.", "reset.notify.text2": "Ja neesi to pilnvarojis, nekavējoties informē administratoru par to.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Jaunākie temati no %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ms/email.json b/public/language/ms/email.json index ed309b518d..1b28462a1d 100644 --- a/public/language/ms/email.json +++ b/public/language/ms/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Kata laluan berjaya ditukar", "reset.notify.text1": "Pada %1, kata laluan anda berjaya ditukar.", "reset.notify.text2": "Sekiranya anda tidak pernah melakukannya, sila hubungi pendtadbir / admin dengan segera.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Topik terkini dari %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/nb/email.json b/public/language/nb/email.json index e36f798865..29e13b8e98 100644 --- a/public/language/nb/email.json +++ b/public/language/nb/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Passordet ble endret", "reset.notify.text1": "Vi gjør deg oppmerksom på at du endret passordet ditt den %1.", "reset.notify.text2": "Hvis det ikke var deg som autoriserte dette, vennligst gi beskjed til en administrator umiddelbart.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Siste emner fra %1", "digest.top-topics": "Toppemner fra %1 ", "digest.popular-topics": "Populære emner fra %1", diff --git a/public/language/nl/email.json b/public/language/nl/email.json index 3d82870e7c..ab0f933f17 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Wachtwoord succesvol gewijzigd", "reset.notify.text1": "Op %1 is het wachtwoord van je account succesvol gewijzigd.", "reset.notify.text2": "Neem onmiddellijk contact met een beheerder op wanneer je hiervoor geen toestemming hebt gegeven.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "De meest recente onderwerpen van %1", "digest.top-topics": "Top onderwerpen van %1", "digest.popular-topics": "Populaire onderwerpen van %1", diff --git a/public/language/pl/email.json b/public/language/pl/email.json index 13dd96a274..8b3ea2bfc8 100644 --- a/public/language/pl/email.json +++ b/public/language/pl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Hasło zmienione pomyślnie", "reset.notify.text1": "Informujemy, że Twoje hasło na %1 zostało zmienione.", "reset.notify.text2": "Jeśli nie wyraziłeś na to zgody, niezwłocznie poinformuj administratora.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ostatnie tematy z %1", "digest.top-topics": "Topowe tematy z %1", "digest.popular-topics": "Najpopularniejsze tematy z %1", diff --git a/public/language/pt-BR/email.json b/public/language/pt-BR/email.json index cbbdcb074d..a608bc6a8d 100644 --- a/public/language/pt-BR/email.json +++ b/public/language/pt-BR/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Senha alterada com sucesso", "reset.notify.text1": "Nós estamos notificando você que em %1, sua senha foi alterada com sucesso.", "reset.notify.text2": "Se você não autorizou isso, por favor notifique um administrador imediatamente.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Últimos tópicos de %1", "digest.top-topics": "Tópicos principais de %1", "digest.popular-topics": "Tópicos populares de %1", diff --git a/public/language/pt-PT/email.json b/public/language/pt-PT/email.json index 6eb33c397a..5123fc6507 100644 --- a/public/language/pt-PT/email.json +++ b/public/language/pt-PT/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "A tua palavra-passe foi alterada com sucesso", "reset.notify.text1": "Estamos a notificar-te que a %1, a tua palavra-passe foi alterada com sucesso.", "reset.notify.text2": "Se não autorizaste isto, por favor notifica o administrador imediatamente.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Tópicos recentes de %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ro/email.json b/public/language/ro/email.json index e805de385d..d00213c89c 100644 --- a/public/language/ro/email.json +++ b/public/language/ro/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Parola a fost schimbată cu succes", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ultimele mesaje de la %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/ru/email.json b/public/language/ru/email.json index 6c010cff83..94a15a0dd0 100644 --- a/public/language/ru/email.json +++ b/public/language/ru/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Пароль был успешно изменён", "reset.notify.text1": "Мы уведомляем вас о том, что %1 ваш пароль был успешно изменён.", "reset.notify.text2": "Если вы не совершали этого действия, пожалуйста, незамедлительно свяжитесь с администратором сайта.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Последние темы на форуме %1", "digest.top-topics": "Лучшие темы на форуме %1", "digest.popular-topics": "Популярные темы из %1", diff --git a/public/language/rw/email.json b/public/language/rw/email.json index 5c1e305db6..2bb545eb3f 100644 --- a/public/language/rw/email.json +++ b/public/language/rw/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Ijambobanga ryahinduwe nta ngorane", "reset.notify.text1": "Turakumenyesha ko kuri %1, ijambobanga wakoreshaga ryahinduwe nk'uko byari byasabwe.", "reset.notify.text2": "Niba atari wowe wari wabisabye ku bushake bwawe, bimenyeshe umuyobozi w'urubuga aka kanya. ", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Ibiganiro biheruka bya %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sc/email.json b/public/language/sc/email.json index 9f748a2e61..3e35d7514c 100644 --- a/public/language/sc/email.json +++ b/public/language/sc/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Password successfully changed", "reset.notify.text1": "We are notifying you that on %1, your password was changed successfully.", "reset.notify.text2": "If you did not authorise this, please notify an administrator immediately.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Latest topics from %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sk/email.json b/public/language/sk/email.json index daaa6d84fe..416a278a74 100644 --- a/public/language/sk/email.json +++ b/public/language/sk/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Heslo bolo úspešne zmenené", "reset.notify.text1": "Oznamujeme Vám že %1, bolo Vaše heslo úspešne zmenené.", "reset.notify.text2": "Ak ste o to nežiadali, kontaktujte čo najskôr správcu.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Najnovšie témy od %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sl/email.json b/public/language/sl/email.json index cd775ca7e0..bcf7936a0d 100644 --- a/public/language/sl/email.json +++ b/public/language/sl/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Geslo je bilo uspešno spremenjeno.", "reset.notify.text1": "Obveščamo vas, da je bilo na forumu %1 uspešno spremenjeno vaše geslo.", "reset.notify.text2": "Če tega niste zahtevali, prosimo, da nemudoma obvestite skrbnika.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Zadnje teme na forumu %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/sq-AL/email.json b/public/language/sq-AL/email.json index efba38a58b..991fbbe5cf 100644 --- a/public/language/sq-AL/email.json +++ b/public/language/sq-AL/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Fjalëkalimi u ndryshua me sukses", "reset.notify.text1": "Po ju njoftojmë se në %1, fjalëkalimi juaj u ndryshua me sukses.", "reset.notify.text2": "Nëse nuk e keni autorizuar këtë, ju lutemi njoftoni menjëherë një administrator të VIAL.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Temat e fundit nga %1", "digest.top-topics": "Temat kryesore nga %1", "digest.popular-topics": "Tema të njohura nga %1", diff --git a/public/language/sr/email.json b/public/language/sr/email.json index 44c271e691..ebb6c7e76f 100644 --- a/public/language/sr/email.json +++ b/public/language/sr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Лозика је успешно змењена", "reset.notify.text1": "Обавештавамо вас да вам је лозинка на %1 успешно ресетована.", "reset.notify.text2": "Уколико нисте ви ово одобрили, молимо одмах контактирајте администратора.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Недавне теме од %1", "digest.top-topics": "Најбоље теме од %1", "digest.popular-topics": "Популарне теме од %1", diff --git a/public/language/sv/email.json b/public/language/sv/email.json index 4491c449b8..087ab72f79 100644 --- a/public/language/sv/email.json +++ b/public/language/sv/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Lösenordet ändrat", "reset.notify.text1": "Vi vill uppmärksamma dig på att ditt lösenord ändrades den %1.", "reset.notify.text2": "Om du inte godkänt det här så vänligen kontakta en administratör snarast. ", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Senaste ämnen från %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/th/email.json b/public/language/th/email.json index cae9571202..d3245240c4 100644 --- a/public/language/th/email.json +++ b/public/language/th/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "ตั้งค่ารหัสผ่านใหม่เรียบร้อยแล้ว", "reset.notify.text1": "เรากำลังแจ้งคุณว่าตอน %1 รหัสผ่านของคุณถูกเปลี่ยนเรียบร้อยแล้ว", "reset.notify.text2": "หากคุณไม่ได้เป็นคนอนุญาตสิ่งนี้ กรุณาแจ้งไปยังผู้ดูแลระบบโดยทันที", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "หัวข้อสนทนาล่าสุดจาก %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/tr/email.json b/public/language/tr/email.json index 6765b0b154..6698f65f45 100644 --- a/public/language/tr/email.json +++ b/public/language/tr/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Şifre başarıyla değiştirildi", "reset.notify.text1": "Şifrenizin %1 zamanında başarı ile değiştirildiğini bildirmek isteriz.", "reset.notify.text2": "Bunu siz yetkilendirmediyseniz, lütfen hiç vakit kaybetmeden site yöneticisine bu durumu bildiriniz.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "'daki En Güncel Konular", "digest.top-topics": "%1 tarafından zirve başlıklar", "digest.popular-topics": "%1 tarafından popüler başlıklar", diff --git a/public/language/uk/email.json b/public/language/uk/email.json index e5503fab37..d337e16249 100644 --- a/public/language/uk/email.json +++ b/public/language/uk/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Пароль змінено", "reset.notify.text1": "Ми повідомляємо вас, що на %1, ваш пароль було успішно змінено", "reset.notify.text2": "Якщо ви не авторизували це, повідомте негайно адміністратора", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Останні теми від %1", "digest.top-topics": "Top topics from %1", "digest.popular-topics": "Popular topics from %1", diff --git a/public/language/vi/email.json b/public/language/vi/email.json index 88aeb4bb50..f92942ae98 100644 --- a/public/language/vi/email.json +++ b/public/language/vi/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "Thay đổi mật khẩu thành công", "reset.notify.text1": "Xin thông báo với bạn: mật khẩu của bạn trên %1 đã được thay đổi thành công.", "reset.notify.text2": "Nếu bạn không cho phép điều này, vui lòng thông báo cho quản trị viên ngay lập tức.", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "Chủ đề mới nhất từ %1", "digest.top-topics": "Chủ đề hàng đầu từ %1", "digest.popular-topics": "Các chủ đề phổ biến từ %1", diff --git a/public/language/zh-CN/email.json b/public/language/zh-CN/email.json index d4d5e1fc8e..30fff5787f 100644 --- a/public/language/zh-CN/email.json +++ b/public/language/zh-CN/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "更改密码成功", "reset.notify.text1": "您在 %1 上的密码已经成功修改。", "reset.notify.text2": "如果您没有授权此操作,请立即联系管理员。", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "来自 %1 的最新主题", "digest.top-topics": "来自 %1 的关注主题", "digest.popular-topics": "来自 %1 的热门主题 ", diff --git a/public/language/zh-TW/email.json b/public/language/zh-TW/email.json index 66eb2196e4..f97f57a397 100644 --- a/public/language/zh-TW/email.json +++ b/public/language/zh-TW/email.json @@ -22,6 +22,8 @@ "reset.notify.subject": "更改密碼成功", "reset.notify.text1": "您在 %1 上的密碼已經成功修改。", "reset.notify.text2": "如果您沒有授權此操作,請立即聯繫管理員。", + "digest.unread-rooms": "Unread rooms", + "digest.room-name-unreadcount": "%1 (%2 unread)", "digest.latest_topics": "來自 %1 的最新主題", "digest.top-topics": "來自 %1 的置頂主題", "digest.popular-topics": "來自 %1 的熱門主題", From 6cc86b6eaf220a12b613426507f5f16b20270339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 18 Jul 2023 16:46:20 -0400 Subject: [PATCH 115/300] fix: dont error if timestamp is missing --- src/upgrades/3.3.0/chat_room_owners.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrades/3.3.0/chat_room_owners.js b/src/upgrades/3.3.0/chat_room_owners.js index ddb4af3865..7d608af9d4 100644 --- a/src/upgrades/3.3.0/chat_room_owners.js +++ b/src/upgrades/3.3.0/chat_room_owners.js @@ -21,7 +21,7 @@ module.exports = { const bulkAdd = []; roomData.forEach((room) => { - if (room && room.roomId && room.owner) { + if (room && room.roomId && room.owner && room.timestamp) { bulkAdd.push([`chat:room:${room.roomId}:owners`, room.timestamp, room.owner]); } }); From 9c0b98df7bff035c17c514467e3201a02b3dca66 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 18 Jul 2023 20:47:19 +0000 Subject: [PATCH 116/300] chore(i18n): fallback strings for new resources: nodebb.topic --- public/language/ar/topic.json | 2 +- public/language/bg/topic.json | 2 +- public/language/bn/topic.json | 2 +- public/language/cs/topic.json | 2 +- public/language/da/topic.json | 2 +- public/language/de/topic.json | 2 +- public/language/el/topic.json | 2 +- public/language/en-US/topic.json | 2 +- public/language/en-x-pirate/topic.json | 2 +- public/language/es/topic.json | 2 +- public/language/et/topic.json | 2 +- public/language/fa-IR/topic.json | 2 +- public/language/fi/topic.json | 2 +- public/language/fr/topic.json | 2 +- public/language/gl/topic.json | 2 +- public/language/he/topic.json | 2 +- public/language/hr/topic.json | 2 +- public/language/hu/topic.json | 2 +- public/language/hy/topic.json | 2 +- public/language/id/topic.json | 2 +- public/language/it/topic.json | 2 +- public/language/ja/topic.json | 2 +- public/language/ko/topic.json | 2 +- public/language/lt/topic.json | 2 +- public/language/lv/topic.json | 2 +- public/language/ms/topic.json | 2 +- public/language/nb/topic.json | 2 +- public/language/nl/topic.json | 2 +- public/language/pl/topic.json | 2 +- public/language/pt-BR/topic.json | 4 ++-- public/language/pt-PT/topic.json | 2 +- public/language/ro/topic.json | 2 +- public/language/ru/topic.json | 2 +- public/language/rw/topic.json | 2 +- public/language/sc/topic.json | 2 +- public/language/sk/topic.json | 2 +- public/language/sl/topic.json | 2 +- public/language/sq-AL/topic.json | 2 +- public/language/sr/topic.json | 2 +- public/language/sv/topic.json | 2 +- public/language/th/topic.json | 2 +- public/language/tr/topic.json | 2 +- public/language/uk/topic.json | 2 +- public/language/vi/topic.json | 2 +- public/language/zh-CN/topic.json | 2 +- public/language/zh-TW/topic.json | 2 +- 46 files changed, 47 insertions(+), 47 deletions(-) diff --git a/public/language/ar/topic.json b/public/language/ar/topic.json index 22e96b3fcf..44e149abdf 100644 --- a/public/language/ar/topic.json +++ b/public/language/ar/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/bg/topic.json b/public/language/bg/topic.json index 70f8d1e8f3..b5fc93e4cc 100644 --- a/public/language/bg/topic.json +++ b/public/language/bg/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "писа ", "wrote-on": "писа на ", "replied-to-user-ago": "отговори на %3 ", - "replied-to-user-on": "отговори на %3 на ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 заключи тази тема %2", "user-locked-topic-on": "%1 заключи тази тема на %2", "user-unlocked-topic-ago": "%1 отключи тази тема %2", diff --git a/public/language/bn/topic.json b/public/language/bn/topic.json index 6f1ee4c364..2d59e3907c 100644 --- a/public/language/bn/topic.json +++ b/public/language/bn/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/cs/topic.json b/public/language/cs/topic.json index f553244383..4198b2384f 100644 --- a/public/language/cs/topic.json +++ b/public/language/cs/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/da/topic.json b/public/language/da/topic.json index ecd42e9d00..dab738c0a5 100644 --- a/public/language/da/topic.json +++ b/public/language/da/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 2bd15c587a..a00bd53389 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "schrieb ", "wrote-on": "schrieb am ", "replied-to-user-ago": "antwortete an %3 ", - "replied-to-user-on": "antwortete an %3 am ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 sperrte dieses Thema %2", "user-locked-topic-on": "%1 sperrte dieses Thema am %2", "user-unlocked-topic-ago": "%1 entsperrte dieses Thema %2", diff --git a/public/language/el/topic.json b/public/language/el/topic.json index dd96139266..e360ec36f6 100644 --- a/public/language/el/topic.json +++ b/public/language/el/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/en-US/topic.json b/public/language/en-US/topic.json index 6ca9450d0f..30bbd10cd7 100644 --- a/public/language/en-US/topic.json +++ b/public/language/en-US/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/en-x-pirate/topic.json b/public/language/en-x-pirate/topic.json index 6ca9450d0f..30bbd10cd7 100644 --- a/public/language/en-x-pirate/topic.json +++ b/public/language/en-x-pirate/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/es/topic.json b/public/language/es/topic.json index f46e57a467..477dc3a6c5 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "escribió ", "wrote-on": "escribió en ", "replied-to-user-ago": "respondió a %3 ", - "replied-to-user-on": "respondió a %3 en ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/et/topic.json b/public/language/et/topic.json index 777797037a..1fb9c80cdf 100644 --- a/public/language/et/topic.json +++ b/public/language/et/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/fa-IR/topic.json b/public/language/fa-IR/topic.json index 32128f8391..f415d3e46c 100644 --- a/public/language/fa-IR/topic.json +++ b/public/language/fa-IR/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "نوشته‌شده ", "wrote-on": "نوشته‌شده در ", "replied-to-user-ago": "پاسخ داده شده به %3 در", - "replied-to-user-on": "پاسخ به %3 در", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "1% این موضوع را قفل کرد%2", "user-locked-topic-on": "1% این موضوع را در %2 قفل کرد ", "user-unlocked-topic-ago": "1% قفل این موضوع را باز کرد %2", diff --git a/public/language/fi/topic.json b/public/language/fi/topic.json index 20026d743f..b882d88949 100644 --- a/public/language/fi/topic.json +++ b/public/language/fi/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index c7009253f3..ccfd7a11a6 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "écrit ", "wrote-on": "a écrit sur ", "replied-to-user-ago": "a répondu à %3 ", - "replied-to-user-on": "a répondu à %3 sur ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 a verrouillé ce sujet %2", "user-locked-topic-on": "%1 a verrouillé ce sujet sur %2", "user-unlocked-topic-ago": "%1 a déverrouillé ce sujet %2", diff --git a/public/language/gl/topic.json b/public/language/gl/topic.json index a72421dc7a..e3e1c1d0fd 100644 --- a/public/language/gl/topic.json +++ b/public/language/gl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 5bd26e66db..940d924f8e 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "כתב ", "wrote-on": "כתב ב", "replied-to-user-ago": "השיב ל%3 ", - "replied-to-user-on": "השיב ל%3 ב", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 נעל נושא זה %2", "user-locked-topic-on": "%1 נעל נושא זה ב-%2", "user-unlocked-topic-ago": "%1 ביטל את נעילת נושא זה %2", diff --git a/public/language/hr/topic.json b/public/language/hr/topic.json index 3bbaf047e7..7c21cd9d3f 100644 --- a/public/language/hr/topic.json +++ b/public/language/hr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/hu/topic.json b/public/language/hu/topic.json index 7f57b58d8c..40e3cdb3ad 100644 --- a/public/language/hu/topic.json +++ b/public/language/hu/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "írta ", "wrote-on": "írta ", "replied-to-user-ago": "válaszolt %3 ", - "replied-to-user-on": "válaszolt %3", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 lezárta ezt a témakört %2", "user-locked-topic-on": "%1 lezárta ezt a témakört %2", "user-unlocked-topic-ago": "%1 feloldotta ezt a témakört %2", diff --git a/public/language/hy/topic.json b/public/language/hy/topic.json index 8656434f70..84b6b4ef8f 100644 --- a/public/language/hy/topic.json +++ b/public/language/hy/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/id/topic.json b/public/language/id/topic.json index add9fd3e79..7e4401d006 100644 --- a/public/language/id/topic.json +++ b/public/language/id/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/it/topic.json b/public/language/it/topic.json index f947fcb09a..9f0e587a9c 100644 --- a/public/language/it/topic.json +++ b/public/language/it/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "scritto ", "wrote-on": "scritto su ", "replied-to-user-ago": "risposto a %3 ", - "replied-to-user-on": "risposto a %3 su ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 ha bloccato questa discussione %2", "user-locked-topic-on": "%1 ha bloccato questa discussione su %2", "user-unlocked-topic-ago": "%1 ha sbloccato questa discussione %2", diff --git a/public/language/ja/topic.json b/public/language/ja/topic.json index 52befd5df0..ef1ac555ff 100644 --- a/public/language/ja/topic.json +++ b/public/language/ja/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ko/topic.json b/public/language/ko/topic.json index 8af1a48a8e..94654f0f42 100644 --- a/public/language/ko/topic.json +++ b/public/language/ko/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/lt/topic.json b/public/language/lt/topic.json index 9576935b5c..ee5c31be86 100644 --- a/public/language/lt/topic.json +++ b/public/language/lt/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/lv/topic.json b/public/language/lv/topic.json index 8a177ee1b7..4f46a3b821 100644 --- a/public/language/lv/topic.json +++ b/public/language/lv/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ms/topic.json b/public/language/ms/topic.json index d2cded93be..98eb032da7 100644 --- a/public/language/ms/topic.json +++ b/public/language/ms/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 40b7c1520b..f63153bd45 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index db0295d2c0..ee43c94b1c 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/pl/topic.json b/public/language/pl/topic.json index 9c265da6b4..52a1296339 100644 --- a/public/language/pl/topic.json +++ b/public/language/pl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/pt-BR/topic.json b/public/language/pt-BR/topic.json index f1e68d9b62..bcd91e3566 100644 --- a/public/language/pt-BR/topic.json +++ b/public/language/pt-BR/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", @@ -203,7 +203,7 @@ "last-post": "Último post", "go-to-my-next-post": "Go to my next post", "no-more-next-post": "You don't have more posts in this topic", - "post-quick-reply": "Quick reply", + "post-quick-reply": "Resposta rápida", "navigator.index": "Post %1 of %2", "navigator.unread": "%1 unread" } \ No newline at end of file diff --git a/public/language/pt-PT/topic.json b/public/language/pt-PT/topic.json index 474f6822b0..f3575fff06 100644 --- a/public/language/pt-PT/topic.json +++ b/public/language/pt-PT/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ro/topic.json b/public/language/ro/topic.json index dcc47d9645..0c9643ddf6 100644 --- a/public/language/ro/topic.json +++ b/public/language/ro/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/ru/topic.json b/public/language/ru/topic.json index 3b4f4c88ed..4936adcc0d 100644 --- a/public/language/ru/topic.json +++ b/public/language/ru/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "написал ", "wrote-on": "написал в ", "replied-to-user-ago": "ответил %3 ", - "replied-to-user-on": "ответил %3 в ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 закрыл эту тему %2", "user-locked-topic-on": "%1 закрыл эту тему в %2", "user-unlocked-topic-ago": "%1 открыл эту тему %2", diff --git a/public/language/rw/topic.json b/public/language/rw/topic.json index 6957755a88..9d69c81546 100644 --- a/public/language/rw/topic.json +++ b/public/language/rw/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sc/topic.json b/public/language/sc/topic.json index 809f67530f..a179e7ff4e 100644 --- a/public/language/sc/topic.json +++ b/public/language/sc/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sk/topic.json b/public/language/sk/topic.json index 7d9be5a489..61418318df 100644 --- a/public/language/sk/topic.json +++ b/public/language/sk/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sl/topic.json b/public/language/sl/topic.json index 6da76ee923..c70112203d 100644 --- a/public/language/sl/topic.json +++ b/public/language/sl/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sq-AL/topic.json b/public/language/sq-AL/topic.json index 7d3ef7d883..6ff59cd6a3 100644 --- a/public/language/sq-AL/topic.json +++ b/public/language/sq-AL/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/sr/topic.json b/public/language/sr/topic.json index 65fb76a8d5..3448e4f2f0 100644 --- a/public/language/sr/topic.json +++ b/public/language/sr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "написао ", "wrote-on": "написао ", "replied-to-user-ago": "одговорио кориснику %3 ", - "replied-to-user-on": "одговорио кориснику %3 ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 је закључао ову тему %2", "user-locked-topic-on": "%1 је закључао ову тему %2", "user-unlocked-topic-ago": "%1 је откључао ову тему %2", diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index a946b6fd43..87fb6c8b54 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/th/topic.json b/public/language/th/topic.json index 8f7dfb09e7..469bfde3b6 100644 --- a/public/language/th/topic.json +++ b/public/language/th/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index ee9ccf74cc..885beae1e5 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": " yazdı", "wrote-on": " tarihinde yazdı", "replied-to-user-ago": "%3 başlığına cevap verdi", - "replied-to-user-on": "%3 başlığına tarihinde cevap verdi", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 , %2 bu başlığı kilitledi", "user-locked-topic-on": "%1 , %2 tarihinde bu başlığı kilitledi", "user-unlocked-topic-ago": "%1 , %2 bu başlığın kilidini kaldırdı", diff --git a/public/language/uk/topic.json b/public/language/uk/topic.json index f100cd844c..27c4eca889 100644 --- a/public/language/uk/topic.json +++ b/public/language/uk/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json index 19f602ad0c..dcc1eca402 100644 --- a/public/language/vi/topic.json +++ b/public/language/vi/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 đã khóa chủ đề này %2", "user-locked-topic-on": "%1 đã khóa chủ đề này trên %2", "user-unlocked-topic-ago": "%1 đã mở khóa chủ đề này %2", diff --git a/public/language/zh-CN/topic.json b/public/language/zh-CN/topic.json index 678e3c5ad1..0f7bd5397e 100644 --- a/public/language/zh-CN/topic.json +++ b/public/language/zh-CN/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "编写", "wrote-on": "写于", "replied-to-user-ago": "回复了%3 ", - "replied-to-user-on": "在 中回复了%3", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 锁定了该主题 %2", "user-locked-topic-on": "%1 在 %2 中锁定了该主题", "user-unlocked-topic-ago": "%1 解锁了该主题 %2", diff --git a/public/language/zh-TW/topic.json b/public/language/zh-TW/topic.json index 5bc0248fdf..9abb730376 100644 --- a/public/language/zh-TW/topic.json +++ b/public/language/zh-TW/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "wrote ", "wrote-on": "wrote on ", "replied-to-user-ago": "replied to %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "replied to %3 on ", "user-locked-topic-ago": "%1 locked this topic %2", "user-locked-topic-on": "%1 locked this topic on %2", "user-unlocked-topic-ago": "%1 unlocked this topic %2", From 77550a50dbfe0c4699521bf5cea844ba75873129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 18 Jul 2023 17:19:57 -0400 Subject: [PATCH 117/300] fix: fallback for room timestamp --- src/upgrades/3.3.0/chat_room_owners.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/upgrades/3.3.0/chat_room_owners.js b/src/upgrades/3.3.0/chat_room_owners.js index 7d608af9d4..9824091e39 100644 --- a/src/upgrades/3.3.0/chat_room_owners.js +++ b/src/upgrades/3.3.0/chat_room_owners.js @@ -12,6 +12,8 @@ module.exports = { const { progress } = this; progress.total = await db.sortedSetCard('chat:rooms'); + const users = await db.getSortedSetRangeWithScores(`users:joindate`, 0, 0); + const timestamp = users.length ? users[0].score : Date.now(); await batch.processSortedSet('chat:rooms', async (roomIds) => { progress.incr(roomIds.length); @@ -19,9 +21,17 @@ module.exports = { roomIds.map(id => `chat:room:${id}`) ); + const arrayOfUids = await Promise.all( + roomIds.map(roomId => db.getSortedSetRangeWithScores(`chat:room:${roomId}:uids`, 0, 0)) + ); + const bulkAdd = []; - roomData.forEach((room) => { - if (room && room.roomId && room.owner && room.timestamp) { + roomData.forEach((room, idx) => { + if (room && room.roomId && room.owner) { + // if room doesn't have timestamp for some reason use the first user timestamp + room.timestamp = room.timestamp || ( + arrayOfUids[idx].length ? (arrayOfUids[idx][0].score || timestamp) : timestamp + ); bulkAdd.push([`chat:room:${room.roomId}:owners`, room.timestamp, room.owner]); } }); From de13aae6438d5f843dc83f1722d5304e0c651e98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 17:20:14 -0400 Subject: [PATCH 118/300] fix(deps): update dependency esbuild to v0.18.14 (#11813) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0654f45bff..330924820b 100644 --- a/install/package.json +++ b/install/package.json @@ -62,7 +62,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.13", + "esbuild": "0.18.14", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 4095cda6a4d903b3914ed5bd8bb924eb22f5ded8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 17:20:26 -0400 Subject: [PATCH 119/300] fix(deps): update dependency webpack to v5.88.2 (#11811) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 330924820b..8b9260f4df 100644 --- a/install/package.json +++ b/install/package.json @@ -143,7 +143,7 @@ "tinycon": "0.6.8", "toobusy-js": "0.5.1", "validator": "13.9.0", - "webpack": "5.88.1", + "webpack": "5.88.2", "webpack-merge": "5.9.0", "winston": "3.10.0", "xml": "1.0.1", From 0dce4c46b5cd985b689ee30f0e3cd745812ad07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 19 Jul 2023 04:31:19 -0400 Subject: [PATCH 120/300] https://github.com/NodeBB/NodeBB/issues/11818 --- public/scss/admin/general/dashboard.scss | 13 --------- public/src/admin/dashboard.js | 20 ++++++------- public/src/modules/helpers.common.js | 11 ++++++- public/src/utils.common.js | 2 +- src/views/admin/advanced/database.tpl | 30 ++++++++++---------- src/views/admin/manage/users.tpl | 4 +-- src/views/admin/partials/dashboard/stats.tpl | 14 ++++----- 7 files changed, 45 insertions(+), 49 deletions(-) diff --git a/public/scss/admin/general/dashboard.scss b/public/scss/admin/general/dashboard.scss index b21799e51c..5ad836cdd9 100644 --- a/public/scss/admin/general/dashboard.scss +++ b/public/scss/admin/general/dashboard.scss @@ -138,19 +138,6 @@ } } - .stats { - .formatted-number { - font-size: 22px; - } - - .stat { - text-transform: uppercase; - font-weight: 600; - font-size: 10px; - color: #999; - } - } - .updatePageviewsGraph.active { font-weight: bold; } diff --git a/public/src/admin/dashboard.js b/public/src/admin/dashboard.js index ab151a2bad..afead1ff13 100644 --- a/public/src/admin/dashboard.js +++ b/public/src/admin/dashboard.js @@ -2,8 +2,8 @@ define('admin/dashboard', [ - 'Chart', 'translator', 'benchpress', 'bootbox', 'alerts', -], function (Chart, translator, Benchpress, bootbox, alerts) { + 'Chart', 'translator', 'benchpress', 'bootbox', 'alerts', 'helpers', +], function (Chart, translator, Benchpress, bootbox, alerts, helpers) { const Admin = {}; const intervals = { rooms: false, @@ -63,20 +63,20 @@ define('admin/dashboard', [ graphData.rooms = data; const html = '
        ' + - '' + data.onlineRegisteredCount + '' + - '
        [[admin/dashboard:active-users.users]]
        ' + + '' + helpers.formattedNumber(data.onlineRegisteredCount) + '' + + '
        [[admin/dashboard:active-users.users]]
        ' + '
        ' + '
        ' + - '' + data.onlineGuestCount + '' + - '
        [[admin/dashboard:active-users.guests]]
        ' + + '' + helpers.formattedNumber(data.onlineGuestCount) + '' + + '
        [[admin/dashboard:active-users.guests]]
        ' + '
        ' + '
        ' + - '' + (data.onlineRegisteredCount + data.onlineGuestCount) + '' + - '
        [[admin/dashboard:active-users.total]]
        ' + + '' + helpers.formattedNumber(data.onlineRegisteredCount + data.onlineGuestCount) + '' + + '
        [[admin/dashboard:active-users.total]]
        ' + '
        ' + '
        ' + - '' + data.socketCount + '' + - '
        [[admin/dashboard:active-users.connections]]
        ' + + '' + helpers.formattedNumber(data.socketCount) + '' + + '
        [[admin/dashboard:active-users.connections]]
        ' + '
        '; updateRegisteredGraph(data.onlineRegisteredCount, data.onlineGuestCount); diff --git a/public/src/modules/helpers.common.js b/public/src/modules/helpers.common.js index 123b5eccc6..8121ad171d 100644 --- a/public/src/modules/helpers.common.js +++ b/public/src/modules/helpers.common.js @@ -29,7 +29,8 @@ module.exports = function (utils, Benchpress, relative_path) { generateWrote, isoTimeToLocaleString, shouldHideReplyContainer, - + humanReadableNumber, + formattedNumber, register, __escape: identity, }; @@ -352,6 +353,14 @@ module.exports = function (utils, Benchpress, relative_path) { return false; } + function humanReadableNumber(number, toFixed = 1) { + return utils.makeNumberHumanReadable(number, toFixed); + } + + function formattedNumber(number) { + return utils.addCommas(number); + } + function register() { Object.keys(helpers).forEach(function (helperName) { Benchpress.registerHelper(helperName, helpers[helperName]); diff --git a/public/src/utils.common.js b/public/src/utils.common.js index f83b3924a2..5773fa1675 100644 --- a/public/src/utils.common.js +++ b/public/src/utils.common.js @@ -442,7 +442,7 @@ const utils = { makeNumberHumanReadable: function (num, toFixed = 1) { const n = parseInt(num, 10); if (!n) { - return num; + return String(num); } if (n > 999999) { return (n / 1000000).toFixed(toFixed) + 'm'; diff --git a/src/views/admin/advanced/database.tpl b/src/views/admin/advanced/database.tpl index 4e10d868d7..cdcf2a65ab 100644 --- a/src/views/admin/advanced/database.tpl +++ b/src/views/admin/advanced/database.tpl @@ -13,10 +13,10 @@
        [[admin/advanced/database:mongo.version]] {mongo.version}

        -
        [[admin/advanced/database:uptime-seconds]] {mongo.uptime}
        +
        [[admin/advanced/database:uptime-seconds]] {formattedNumber(mongo.uptime)}
        [[admin/advanced/database:mongo.storage-engine]] {mongo.storageEngine}
        -
        [[admin/advanced/database:mongo.collections]] {mongo.collections}
        -
        [[admin/advanced/database:mongo.objects]] {mongo.objects}
        +
        [[admin/advanced/database:mongo.collections]] {formattedNumber(mongo.collections)}
        +
        [[admin/advanced/database:mongo.objects]] {formattedNumber(mongo.objects)}
        [[admin/advanced/database:mongo.avg-object-size]] [[admin/advanced/database:x-b, {mongo.avgObjSize}]]

        [[admin/advanced/database:mongo.data-size]] [[admin/advanced/database:x-gb, {mongo.dataSize}]]
        @@ -47,23 +47,23 @@
        [[admin/advanced/database:redis.version]] {redis.redis_version}

        -
        [[admin/advanced/database:uptime-seconds]] {redis.uptime_in_seconds}
        +
        [[admin/advanced/database:uptime-seconds]] {formattedNumber(redis.uptime_in_seconds)}
        [[admin/advanced/database:uptime-days]] {redis.uptime_in_days}

        -
        [[admin/advanced/database:redis.keys]] {redis.keys}
        -
        [[admin/advanced/database:redis.expires]] {redis.expires}
        -
        [[admin/advanced/database:redis.avg-ttl]] {redis.avg_ttl}
        -
        [[admin/advanced/database:redis.connected-clients]] {redis.connected_clients}
        -
        [[admin/advanced/database:redis.connected-slaves]] {redis.connected_slaves}
        +
        [[admin/advanced/database:redis.keys]] {formattedNumber(redis.keys)}
        +
        [[admin/advanced/database:redis.expires]] {formattedNumber(redis.expires)}
        +
        [[admin/advanced/database:redis.avg-ttl]] {formattedNumber(redis.avg_ttl)}
        +
        [[admin/advanced/database:redis.connected-clients]] {formattedNumber(redis.connected_clients)}
        +
        [[admin/advanced/database:redis.connected-slaves]] {formattedNumber(redis.connected_slaves)}
        [[admin/advanced/database:redis.blocked-clients]] {redis.blocked_clients}

        [[admin/advanced/database:redis.used-memory]] [[admin/advanced/database:x-gb, {redis.used_memory_human}]]
        [[admin/advanced/database:redis.memory-frag-ratio]] {redis.mem_fragmentation_ratio}

        -
        [[admin/advanced/database:redis.total-connections-recieved]] {redis.total_connections_received}
        -
        [[admin/advanced/database:redis.total-commands-processed]] {redis.total_commands_processed}
        -
        [[admin/advanced/database:redis.iops]] {redis.instantaneous_ops_per_sec}
        +
        [[admin/advanced/database:redis.total-connections-recieved]] {formattedNumber(redis.total_connections_received)}
        +
        [[admin/advanced/database:redis.total-commands-processed]] {formattedNumber(redis.total_commands_processed)}
        +
        [[admin/advanced/database:redis.iops]] {formattedNumber(redis.instantaneous_ops_per_sec)}
        [[admin/advanced/database:redis.iinput]] [[admin/advanced/database:x-mb, {redis.instantaneous_input}]]
        [[admin/advanced/database:redis.ioutput]] [[admin/advanced/database:x-mb, {redis.instantaneous_output}]]
        @@ -71,8 +71,8 @@
        [[admin/advanced/database:redis.total-output]] [[admin/advanced/database:x-gb, {redis.total_net_output}]]

        -
        [[admin/advanced/database:redis.keyspace-hits]] {redis.keyspace_hits}
        -
        [[admin/advanced/database:redis.keyspace-misses]] {redis.keyspace_misses}
        +
        [[admin/advanced/database:redis.keyspace-hits]] {formattedNumber(redis.keyspace_hits)}
        +
        [[admin/advanced/database:redis.keyspace-misses]] {formattedNumber(redis.keyspace_misses)}
        @@ -87,7 +87,7 @@
        [[admin/advanced/database:postgres.version]] {postgres.version}

        -
        [[admin/advanced/database:uptime-seconds]] {postgres.uptime}
        +
        [[admin/advanced/database:uptime-seconds]] {formattedNumber(postgres.uptime)}
        diff --git a/src/views/admin/manage/users.tpl b/src/views/admin/manage/users.tpl index b87faf0ea9..7d417e9b5b 100644 --- a/src/views/admin/manage/users.tpl +++ b/src/views/admin/manage/users.tpl @@ -151,8 +151,8 @@ {{{ end }}}
        {users.postcount}{users.reputation}{formattedNumber(users.postcount)}{formattedNumber(users.reputation)} {{{ if users.flags }}}{users.flags}{{{ else }}}0{{{ end }}} {./yesterday}{./today}{formattedNumber(./yesterday)}{formattedNumber(./today)} {./dayIncrease}%{./lastweek}{./thisweek}{formattedNumber(./lastweek)}{formattedNumber(./thisweek)} {./weekIncrease}%{./lastmonth}{./thismonth}{formattedNumber(./lastmonth)}{formattedNumber(./thismonth)} {./monthIncrease}%{./alltime}{formattedNumber(./alltime)}
        - {{{ if ./picture }}} - - {{{ else }}} -
        {../icon:text}
        - {{{ end }}} -
        + {buildAvatar(privileges.users, "24px", true)} {{{ if privileges.users.banned }}} {{{ end }}} {privileges.users.username} + +
        {formattedNumber(users.postcount)}{formattedNumber(users.reputation)}{formattedNumber(users.reputation)} {{{ if users.flags }}}{users.flags}{{{ else }}}0{{{ end }}}
        +
        {./token} @@ -76,7 +76,7 @@ + diff --git a/src/views/admin/settings/navigation.tpl b/src/views/admin/settings/navigation.tpl index 2d071be170..8c438200cb 100644 --- a/src/views/admin/settings/navigation.tpl +++ b/src/views/admin/settings/navigation.tpl @@ -14,7 +14,7 @@
        - +
        - +
        \ No newline at end of file diff --git a/src/views/admin/settings/advanced.tpl b/src/views/admin/settings/advanced.tpl index fc3fcc4b8f..049942b2ee 100644 --- a/src/views/admin/settings/advanced.tpl +++ b/src/views/admin/settings/advanced.tpl @@ -7,8 +7,8 @@
        [[admin/settings/advanced:maintenance-mode]]
        - - + +

        [[admin/settings/advanced:maintenance-mode.help]] @@ -75,7 +75,7 @@

        - +

        [[admin/settings/advanced:headers.coep-help]]

        @@ -108,20 +108,20 @@
        [[admin/settings/advanced:hsts]]
        - - + +
        - - + +
        - - + +

        [[admin/settings/advanced:hsts.help, https:\/\/hstspreload.org\/]] @@ -168,8 +168,8 @@ [[admin/settings/advanced:compression.help]]

        - - + +
        diff --git a/src/views/admin/settings/api.tpl b/src/views/admin/settings/api.tpl index 3fff449d70..c5e9e27ce3 100644 --- a/src/views/admin/settings/api.tpl +++ b/src/views/admin/settings/api.tpl @@ -26,8 +26,8 @@
        - - + +

        [[admin/settings/api:require-https-caveat]]

        diff --git a/src/views/admin/settings/chat.tpl b/src/views/admin/settings/chat.tpl index 18e073e2ec..59a32445bd 100644 --- a/src/views/admin/settings/chat.tpl +++ b/src/views/admin/settings/chat.tpl @@ -9,14 +9,14 @@
        - +
        - +

        [[admin/settings/chat:disable-editing-help]]

        diff --git a/src/views/admin/settings/cookies.tpl b/src/views/admin/settings/cookies.tpl index 56d3abb832..e7c5fa6e70 100644 --- a/src/views/admin/settings/cookies.tpl +++ b/src/views/admin/settings/cookies.tpl @@ -8,7 +8,7 @@
        - +
        diff --git a/src/views/admin/settings/general.tpl b/src/views/admin/settings/general.tpl index bf3d79ded3..7092fab2be 100644 --- a/src/views/admin/settings/general.tpl +++ b/src/views/admin/settings/general.tpl @@ -181,8 +181,8 @@
        - - + +
        diff --git a/src/views/admin/settings/group.tpl b/src/views/admin/settings/group.tpl index 26fcf37a27..2d3f960007 100644 --- a/src/views/admin/settings/group.tpl +++ b/src/views/admin/settings/group.tpl @@ -6,15 +6,15 @@
        [[admin/settings/group:general]]
        - - + +

        [[admin/settings/group:private-groups.help]]

        [[admin/settings/group:private-groups.warning]]

        - - + +

        [[admin/settings/group:allow-multiple-badges-help]]

        diff --git a/src/views/admin/settings/navigation.tpl b/src/views/admin/settings/navigation.tpl index 8c438200cb..431b052361 100644 --- a/src/views/admin/settings/navigation.tpl +++ b/src/views/admin/settings/navigation.tpl @@ -86,13 +86,13 @@
        - - + +
        - - + +

        diff --git a/src/views/admin/settings/pagination.tpl b/src/views/admin/settings/pagination.tpl index 93d8aec911..4a510ae18f 100644 --- a/src/views/admin/settings/pagination.tpl +++ b/src/views/admin/settings/pagination.tpl @@ -6,8 +6,8 @@

        @@ -234,20 +234,20 @@
        [[admin/settings/post:signature]]
        - - + +
        - - + +
        - - + +
        - - + +
        diff --git a/src/views/admin/settings/reputation.tpl b/src/views/admin/settings/reputation.tpl index a2fea06559..6f5796170e 100644 --- a/src/views/admin/settings/reputation.tpl +++ b/src/views/admin/settings/reputation.tpl @@ -7,16 +7,16 @@
        [[admin/settings/reputation:reputation]]
        - - + +
        - - + +
        - - + +
        @@ -112,8 +112,8 @@
        - - + +
        diff --git a/src/views/admin/settings/uploads.tpl b/src/views/admin/settings/uploads.tpl index 88869f3418..58da4e3ff6 100644 --- a/src/views/admin/settings/uploads.tpl +++ b/src/views/admin/settings/uploads.tpl @@ -7,13 +7,13 @@
        [[admin/settings/uploads:posts]]
        - - + +
        - - + +
        @@ -79,8 +79,8 @@
        - - + +
        @@ -119,8 +119,8 @@
        [[admin/settings/uploads:orphans]]
        - - + +
        @@ -139,13 +139,13 @@
        [[admin/settings/uploads:profile-avatars]]
        - - + +
        - - + +
        @@ -181,8 +181,8 @@
        - - + +
        diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index 86ef732cce..1871f9dd67 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -14,41 +14,41 @@
        - - + +

        [[admin/settings/user:gdpr_enabled_help]]

        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        @@ -155,8 +155,8 @@
        - - + +
        @@ -218,8 +218,8 @@
        - - + +

        [[admin/settings/guest:handles.enabled-help]] @@ -227,14 +227,14 @@

        - - + +
        - - + +
        @@ -244,33 +244,33 @@
        [[admin/settings/user:default-user-settings]]
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        - - + +
        @@ -285,13 +285,13 @@
        - - + +
        - - + +
        diff --git a/src/views/admin/settings/web-crawler.tpl b/src/views/admin/settings/web-crawler.tpl index 8cdcd67702..ebb51d728d 100644 --- a/src/views/admin/settings/web-crawler.tpl +++ b/src/views/admin/settings/web-crawler.tpl @@ -16,13 +16,13 @@
        [[admin/settings/web-crawler:sitemap-feed-settings]]
        - - + +
        - - + +
        diff --git a/src/views/modals/temporary-ban.tpl b/src/views/modals/temporary-ban.tpl index 19b1047fed..d84bc28331 100644 --- a/src/views/modals/temporary-ban.tpl +++ b/src/views/modals/temporary-ban.tpl @@ -15,12 +15,12 @@
        - - + +
        - - + +
        diff --git a/src/views/modals/temporary-mute.tpl b/src/views/modals/temporary-mute.tpl index 87fab1890e..0025a909ee 100644 --- a/src/views/modals/temporary-mute.tpl +++ b/src/views/modals/temporary-mute.tpl @@ -6,12 +6,12 @@
        - - + +
        - - + +
        From 2f515329875bd344979bcdd0aeb75b4f44bbcb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 3 Aug 2023 19:19:08 -0400 Subject: [PATCH 227/300] fix nav colors --- public/scss/admin/general/navigation.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/scss/admin/general/navigation.scss b/public/scss/admin/general/navigation.scss index 561471576a..7233458abe 100644 --- a/public/scss/admin/general/navigation.scss +++ b/public/scss/admin/general/navigation.scss @@ -14,7 +14,7 @@ overflow: auto; .active { - background-color: $gray-700; + background-color: var(--bs-secondary-bg); } li a { @@ -24,9 +24,9 @@ li { display: inline-block; >a:hover, >a:focus { - color: $gray-300; - background-color: $gray-700; - } + color: var(--bs-secondary-color); + background-color: var(--bs-secondary-bg); + } } } From 3a2c11a5959f7868c2ed1b9fbb49989364d27380 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Fri, 4 Aug 2023 09:22:36 +0000 Subject: [PATCH 228/300] Latest translations and fallbacks --- public/language/bg/error.json | 2 +- public/language/bg/global.json | 4 ++-- public/language/it/admin/dashboard.json | 6 +++--- public/language/it/error.json | 2 +- public/language/tr/admin/admin.json | 8 ++++---- public/language/tr/admin/extend/plugins.json | 2 +- public/language/tr/admin/extend/rewards.json | 4 ++-- public/language/tr/user.json | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/public/language/bg/error.json b/public/language/bg/error.json index d7f105f59e..4066f46ba3 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -55,7 +55,7 @@ "user-banned-reason-until": "За съжаление, този акаунт е блокиран до %1 (Причина: %2)", "user-too-new": "Съжаляваме, но трябва да изчакате поне %1 секунда/и, преди да направите първата си публикация", "blacklisted-ip": "Съжаляваме, но Вашият IP адрес е забранен за ползване в тази общност. Ако смятате, че това е грешка, моля, свържете се с администратор.", - "cant-blacklist-self-ip": "You can't blacklist your own IP", + "cant-blacklist-self-ip": "Не може да добавите собствения си IP адрес в черния списък", "ban-expiry-missing": "Моля, задайте крайна дата за това блокиране", "no-category": "Категорията не съществува", "no-topic": "Темата не съществува", diff --git a/public/language/bg/global.json b/public/language/bg/global.json index 04658a0d3c..b8f2f1e085 100644 --- a/public/language/bg/global.json +++ b/public/language/bg/global.json @@ -51,8 +51,8 @@ "nextpage": "Следваща страница", "alert.success": "Готово", "alert.error": "Грешка", - "alert.warning": "Warning", - "alert.info": "Info", + "alert.warning": "Предупреждение", + "alert.info": "Информация", "alert.banned": "Блокиран", "alert.banned.message": "Вие току-що бяхте блокиран. Достъпът Ви до системата е ограничен.", "alert.unbanned": "Деблокиран", diff --git a/public/language/it/admin/dashboard.json b/public/language/it/admin/dashboard.json index c8dcc4f5bc..4c7414aff3 100644 --- a/public/language/it/admin/dashboard.json +++ b/public/language/it/admin/dashboard.json @@ -48,7 +48,7 @@ "restart-disabled": "La Riorganizzazione e il Riavvio del tuo NodeBB sono stati disabilitati in quanto non sembra che tu lo stia eseguendo tramite il demone appropriato.", "maintenance-mode": "Modalità Manutenzione", "maintenance-mode-title": "Clicca qui per impostare la modalità di manutenzione per NodeBB", - "dark-mode": "Dark Mode", + "dark-mode": "Modalità scura", "realtime-chart-updates": "Aggiornamento grafici in tempo reale", "active-users": "Utenti Attivi", @@ -91,6 +91,6 @@ "start": "Inizio", "end": "Fine", "filter": "Filtro", - "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "view-as-json": "Visualizza come JSON", + "expand-analytics": "Espandi l'analisi" } diff --git a/public/language/it/error.json b/public/language/it/error.json index 9f282585de..7808e7d256 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -55,7 +55,7 @@ "user-banned-reason-until": "Spiacente, questo account è stato bannato fino a %1 (Motivazione: %2)", "user-too-new": "Spiacente, devi attendere %1 secondo(i) prima di creare il tuo primo post", "blacklisted-ip": "Spiacente, il tuo indirizzo IP è stato bannato da questa comunità. Se ritieni che si tratti di un errore, contatta un amministratore.", - "cant-blacklist-self-ip": "You can't blacklist your own IP", + "cant-blacklist-self-ip": "Non puoi inserire nella blacklist il tuo IP", "ban-expiry-missing": "Per favore fornire una data di termine per questo ban", "no-category": "La Categoria non esiste", "no-topic": "La Discussione non esiste", diff --git a/public/language/tr/admin/admin.json b/public/language/tr/admin/admin.json index d0fd44bb6f..36cf3b16f9 100644 --- a/public/language/tr/admin/admin.json +++ b/public/language/tr/admin/admin.json @@ -4,13 +4,13 @@ "acp-title": "%1 | NodeBB Yönetici Kontrol Paneli", "settings-header-contents": "İçerikler", - "changes-saved": "Changes Saved", + "changes-saved": "Değişiklikler kaydedildi", "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", "changes-not-saved": "Değişiklikler kaydedilmedi", "changes-not-saved-message": "NodeBB değişiklikleri kaydederken bir hata oluştu (%1)", - "save-changes": "Save changes", - "min": "Min:", - "max": "Max:", + "save-changes": "Değişiklikleri Kaydet", + "min": "En az:", + "max": "En çok:", "view": "View", "edit": "Edit", "add": "Add", diff --git a/public/language/tr/admin/extend/plugins.json b/public/language/tr/admin/extend/plugins.json index b064fc7bb1..339920ea2e 100644 --- a/public/language/tr/admin/extend/plugins.json +++ b/public/language/tr/admin/extend/plugins.json @@ -1,5 +1,5 @@ { - "plugins": "Plugins", + "plugins": "Eklentiler", "trending": "Popüler", "installed": "Yüklenmiş", "active": "Etkin", diff --git a/public/language/tr/admin/extend/rewards.json b/public/language/tr/admin/extend/rewards.json index a95f454997..7eb384e6ff 100644 --- a/public/language/tr/admin/extend/rewards.json +++ b/public/language/tr/admin/extend/rewards.json @@ -1,12 +1,12 @@ { "rewards": "Ödüller", - "add-reward": "Add reward", + "add-reward": "Ödül Ekle", "condition-if-users": "Eğer bir kullanıcının", "condition-is": "şu ise:", "condition-then": "O halde:", "max-claims": "Ödül kaç kez alınabilir", "zero-infinite": "Sınırsız için 0 girin", - "select-reward": "Select reward", + "select-reward": "Ödül Seç", "delete": "Sil", "enable": "Etkinleştir", "disable": "Etkinsizleştir", diff --git a/public/language/tr/user.json b/public/language/tr/user.json index 5a91331b87..4c18f2409c 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -141,7 +141,7 @@ "group-order-help": "Bir grup seçin ve unvanları sıralamak için yön tuşlarını kullanın", "no-group-title": "Grup unvanı yok", "select-skin": "Bir tema seçin", - "default": "Default (%1)", + "default": "Varsayılan (%1)", "no-skin": "No Skin", "select-homepage": "Bir \"Anasayfa\" seçin", "homepage": "Anasayfa", From 4594cd67692de38069cce99afd06003acc48da6a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Aug 2023 09:44:31 -0400 Subject: [PATCH 229/300] fix(deps): update dependency validator to v13.11.0 (#11877) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 1e989cf543..0342559294 100644 --- a/install/package.json +++ b/install/package.json @@ -141,7 +141,7 @@ "timeago": "1.6.7", "tinycon": "0.6.8", "toobusy-js": "0.5.1", - "validator": "13.9.0", + "validator": "13.11.0", "webpack": "5.88.2", "webpack-merge": "5.9.0", "winston": "3.10.0", From 2c8bf84cadcd3a27caaff4d3b772383dff37b8be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Aug 2023 09:45:17 -0400 Subject: [PATCH 230/300] fix(deps): update fontsource monorepo to v5.0.7 (#11869) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 0342559294..6f1dfcc04c 100644 --- a/install/package.json +++ b/install/package.json @@ -29,8 +29,8 @@ }, "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", - "@fontsource/inter": "5.0.5", - "@fontsource/poppins": "5.0.5", + "@fontsource/inter": "5.0.7", + "@fontsource/poppins": "5.0.7", "@fortawesome/fontawesome-free": "6.4.0", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", From 7a29c2eb2ed7ef877f6b390dd27e67e3649a67f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 09:57:31 -0400 Subject: [PATCH 231/300] fix reconnect alert fade and move it to core --- public/src/sockets.js | 4 ++-- src/views/admin/footer.tpl | 4 ++-- src/views/partials/reconnect-alert.tpl | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 src/views/partials/reconnect-alert.tpl diff --git a/public/src/sockets.js b/public/src/sockets.js index 9325c0c595..a523a29597 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -165,7 +165,7 @@ app = window.app || {}; reconnectEl.tooltip('dispose'); reconnectEl.html(''); - reconnectAlert.addClass('hide'); + reconnectAlert.removeClass('show'); reconnecting = false; reJoinCurrentRoom(); @@ -202,7 +202,7 @@ app = window.app || {}; if (!reconnectEl.hasClass('active')) { reconnectEl.html(''); - reconnectAlert.removeClass('hide'); + reconnectAlert.addClass('show'); } reconnectEl.addClass('active').removeClass('hide').tooltip({ diff --git a/src/views/admin/footer.tpl b/src/views/admin/footer.tpl index 73ed1fb492..6de64023ef 100644 --- a/src/views/admin/footer.tpl +++ b/src/views/admin/footer.tpl @@ -5,8 +5,8 @@ {{{ if !isSpider }}}
        -
        - +
        +

        [[global:reconnecting-message, {config.siteTitle}]]

        diff --git a/src/views/partials/reconnect-alert.tpl b/src/views/partials/reconnect-alert.tpl new file mode 100644 index 0000000000..50a6e1e330 --- /dev/null +++ b/src/views/partials/reconnect-alert.tpl @@ -0,0 +1,4 @@ +
        + +

        [[global:reconnecting-message, {config.siteTitle}]]

        +
        \ No newline at end of file From 8b31815fab1c5ca7cec18fa65dd008ef87667269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 09:58:32 -0400 Subject: [PATCH 232/300] chore: up themes --- install/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/package.json b/install/package.json index 6f1dfcc04c..199bd2a84d 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.2.4", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.25", + "nodebb-theme-harmony": "1.1.26", "nodebb-theme-lavender": "7.1.3", - "nodebb-theme-peace": "2.1.7", - "nodebb-theme-persona": "13.2.12", + "nodebb-theme-peace": "2.1.8", + "nodebb-theme-persona": "13.2.13", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", From 7d5a86667245cf64fa8a85332b425d68e042e856 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:17:05 -0400 Subject: [PATCH 233/300] fix(deps): update dependency @fortawesome/fontawesome-free to v6.4.2 (#11870) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 199bd2a84d..f3d6da8e52 100644 --- a/install/package.json +++ b/install/package.json @@ -31,7 +31,7 @@ "@adactive/bootstrap-tagsinput": "0.8.2", "@fontsource/inter": "5.0.7", "@fontsource/poppins": "5.0.7", - "@fortawesome/fontawesome-free": "6.4.0", + "@fortawesome/fontawesome-free": "6.4.2", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", "ace-builds": "1.23.4", From bcb2733f5c7ea463fb6f4e05c7f104b811ebac16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 10:52:42 -0400 Subject: [PATCH 234/300] remove colors from spec --- public/openapi/components/schemas/TagObject.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/public/openapi/components/schemas/TagObject.yaml b/public/openapi/components/schemas/TagObject.yaml index 2b72c5a1c9..7b3583ef69 100644 --- a/public/openapi/components/schemas/TagObject.yaml +++ b/public/openapi/components/schemas/TagObject.yaml @@ -7,13 +7,12 @@ TagObject: score: type: number description: The number of topics containing this tag + class: + type: string + description: Class name that is applied to the to the tag html element valueEscaped: type: string - color: + description: value escaped with validator.escape + valueEncoded: type: string - description: Six-character hexadecimal string (with `#` prepended) - example: "#ff0000" - bgColor: - type: string - description: Six-character hexadecimal string (with `#` prepended) - example: "#ff0000" \ No newline at end of file + description: value url encoded From e4f8e5067e73441c51399013d62cbe1b73d35f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 11:08:03 -0400 Subject: [PATCH 235/300] fix category analytics tpl --- src/views/admin/manage/category-analytics.tpl | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/src/views/admin/manage/category-analytics.tpl b/src/views/admin/manage/category-analytics.tpl index 523e79cdfc..dcb6ce1d26 100644 --- a/src/views/admin/manage/category-analytics.tpl +++ b/src/views/admin/manage/category-analytics.tpl @@ -1,55 +1,53 @@ - - [[admin/manage/categories:analytics.back]] - -
        [[admin/manage/categories:analytics.title, {name}]]
        -
        +
        +
        [[admin/manage/categories:analytics.title, {name}]]
        +
        +
        +
        +
        +
        +
        +

        -

        -
        -
        -
        -
        -

        - -

        +

        +
        + +
        +
        +
        +
        +
        +
        +

        + +

        +
        +
        -
        -
        -
        -
        -
        -

        +

        +
        +
        +
        +
        +

        -

        +

        +
        +
        -
        -
        -
        -
        -
        -
        -
        -
        -

        +

        +
        +
        +
        +

        -

        +

        +
        +
        - -
        -
        -
        -
        -
        -
        -

        - -

        -
        -
        \ No newline at end of file From 2d883cbb6f8c302c8d3a99fcf2ec102efd65f755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 11:42:46 -0400 Subject: [PATCH 236/300] fix reconnect toast taking space when no visible --- public/src/sockets.js | 4 +++- src/views/partials/reconnect-alert.tpl | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/public/src/sockets.js b/public/src/sockets.js index a523a29597..9e840ec513 100644 --- a/public/src/sockets.js +++ b/public/src/sockets.js @@ -166,6 +166,7 @@ app = window.app || {}; reconnectEl.tooltip('dispose'); reconnectEl.html(''); reconnectAlert.removeClass('show'); + setTimeout(() => reconnectAlert.addClass('hide'), 100); reconnecting = false; reJoinCurrentRoom(); @@ -202,7 +203,8 @@ app = window.app || {}; if (!reconnectEl.hasClass('active')) { reconnectEl.html(''); - reconnectAlert.addClass('show'); + reconnectAlert.removeClass('hide'); + setTimeout(() => reconnectAlert.addClass('show'), 100); } reconnectEl.addClass('active').removeClass('hide').tooltip({ diff --git a/src/views/partials/reconnect-alert.tpl b/src/views/partials/reconnect-alert.tpl index 50a6e1e330..343cf90beb 100644 --- a/src/views/partials/reconnect-alert.tpl +++ b/src/views/partials/reconnect-alert.tpl @@ -1,4 +1,4 @@ -
        +

        [[global:reconnecting-message, {config.siteTitle}]]

        \ No newline at end of file From f23891977d0606e21f9db328815d5f2995ed96aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 11:48:54 -0400 Subject: [PATCH 237/300] fix acp too --- src/views/admin/footer.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/footer.tpl b/src/views/admin/footer.tpl index 6de64023ef..54312e423f 100644 --- a/src/views/admin/footer.tpl +++ b/src/views/admin/footer.tpl @@ -5,7 +5,7 @@ {{{ if !isSpider }}}
        -
        +

        [[global:reconnecting-message, {config.siteTitle}]]

        From 4f8aa1807edeab8ea49544e1a3e28f2b89b8b8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 12:49:44 -0400 Subject: [PATCH 238/300] allow first page too --- src/socket.io/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 0a90698115..169e207b0d 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -148,7 +148,7 @@ SocketCategories.isModerator = async function (socket, cid) { }; SocketCategories.loadMoreSubCategories = async function (socket, data) { - if (!data || !data.cid || !(parseInt(data.start, 10) > 0)) { + if (!data || !data.cid || !(parseInt(data.start, 10) >= 0)) { throw new Error('[[error:invalid-data]]'); } const allowed = await privileges.categories.can('read', data.cid, socket.uid); From acef5e3343afc459330e2348b38179ae439c19c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 13:22:48 -0400 Subject: [PATCH 239/300] feat: add category selector to analytics page closes #11878 --- .../manage/categories/category_id/analytics.yaml | 2 ++ public/src/admin/manage/category-analytics.js | 12 +++++++++++- src/controllers/admin/categories.js | 4 +++- src/views/admin/manage/category-analytics.tpl | 10 +++++++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/public/openapi/read/admin/manage/categories/category_id/analytics.yaml b/public/openapi/read/admin/manage/categories/category_id/analytics.yaml index 4805c4729b..eb6922114f 100644 --- a/public/openapi/read/admin/manage/categories/category_id/analytics.yaml +++ b/public/openapi/read/admin/manage/categories/category_id/analytics.yaml @@ -39,4 +39,6 @@ get: type: array items: type: number + selectedCategory: + $ref: ../../../../../components/schemas/CategoryObject.yaml#/CategoryObject - $ref: ../../../../../components/schemas/CommonProps.yaml#/CommonProps \ No newline at end of file diff --git a/public/src/admin/manage/category-analytics.js b/public/src/admin/manage/category-analytics.js index a4366d07d1..634f7a7e57 100644 --- a/public/src/admin/manage/category-analytics.js +++ b/public/src/admin/manage/category-analytics.js @@ -1,10 +1,20 @@ 'use strict'; -define('admin/manage/category-analytics', ['Chart'], function (Chart) { +define('admin/manage/category-analytics', [ + 'Chart', 'categorySelector', +], function (Chart, categorySelector) { const CategoryAnalytics = {}; CategoryAnalytics.init = function () { + categorySelector.init($('[component="category-selector"]'), { + onSelect: function (selectedCategory) { + ajaxify.go('admin/manage/categories/' + selectedCategory.cid + '/analytics'); + }, + showLinks: true, + template: 'admin/partials/category/selector-dropdown-right', + }); + const hourlyCanvas = document.getElementById('pageviews:hourly'); const dailyCanvas = document.getElementById('pageviews:daily'); const topicsCanvas = document.getElementById('topics:daily'); diff --git a/src/controllers/admin/categories.js b/src/controllers/admin/categories.js index 597f8ff55e..852adee41c 100644 --- a/src/controllers/admin/categories.js +++ b/src/controllers/admin/categories.js @@ -134,12 +134,14 @@ async function buildBreadcrumbs(categoryData, url) { categoriesController.buildBreadCrumbs = buildBreadcrumbs; categoriesController.getAnalytics = async function (req, res) { - const [name, analyticsData] = await Promise.all([ + const [name, analyticsData, selectedData] = await Promise.all([ categories.getCategoryField(req.params.category_id, 'name'), analytics.getCategoryAnalytics(req.params.category_id), + helpers.getSelectedCategory(req.params.category_id), ]); res.render('admin/manage/category-analytics', { name: name, analytics: analyticsData, + selectedCategory: selectedData.selectedCategory, }); }; diff --git a/src/views/admin/manage/category-analytics.tpl b/src/views/admin/manage/category-analytics.tpl index dcb6ce1d26..18ca7666c0 100644 --- a/src/views/admin/manage/category-analytics.tpl +++ b/src/views/admin/manage/category-analytics.tpl @@ -1,6 +1,14 @@
        -
        [[admin/manage/categories:analytics.title, {name}]]
        + +
        +
        +

        [[admin/manage/categories:analytics.title, {name}]]

        + +
        +
        + +
        From e2a198c59a78e76cf42363e69cc6f56422b98896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 13:35:34 -0400 Subject: [PATCH 240/300] fix 0 timeouts --- public/src/client/topic.js | 5 +---- public/src/modules/alerts.js | 10 +++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/public/src/client/topic.js b/public/src/client/topic.js index 79235656dd..30d58e25c6 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -160,7 +160,7 @@ define('forum/topic', [ alerts.alert({ alert_id: 'bookmark', message: '[[topic:bookmark_instructions]]', - timeout: 0, + timeout: 15000, type: 'info', clickfn: function () { navigator.scrollToIndex(parseInt(bookmark, 10), true); @@ -169,9 +169,6 @@ define('forum/topic', [ storage.removeItem('topic:' + tid + ':bookmark'); }, }); - setTimeout(function () { - alerts.remove('bookmark'); - }, 10000); } } diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 3cc82137ca..ae30c6c6b3 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -23,7 +23,7 @@ export function success(message, timeout) { title: '[[global:alert.success]]', message: message, type: 'success', - timeout: timeout || 5000, + timeout: timeout !== undefined ? timeout : 5000, }); } @@ -33,7 +33,7 @@ export function info(message, timeout) { title: '[[global:alert.info]]', message: message, type: 'info', - timeout: timeout || 5000, + timeout: timeout !== undefined ? timeout : 5000, }); } @@ -43,7 +43,7 @@ export function warning(message, timeout) { title: '[[global:alert.warning]]', message: message, type: 'warning', - timeout: timeout || 5000, + timeout: timeout !== undefined ? timeout : 5000, }); } @@ -118,7 +118,7 @@ function createNew(params) { } }); - if (params.timeout) { + if (parseInt(params.timeout, 10)) { startTimeout(alert, params); } @@ -142,7 +142,7 @@ function close(alert) { } function startTimeout(alert, params) { - const timeout = params.timeout; + const timeout = parseInt(params.timeout, 10); const timeoutId = setTimeout(function () { alert.removeAttr('timeoutId'); From 93bfb92a59a8edf2f60c8386f50798c76ff3bc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Aug 2023 13:37:12 -0400 Subject: [PATCH 241/300] fix margins on reconnect --- src/views/admin/footer.tpl | 2 +- src/views/partials/reconnect-alert.tpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/admin/footer.tpl b/src/views/admin/footer.tpl index 54312e423f..00c307ba55 100644 --- a/src/views/admin/footer.tpl +++ b/src/views/admin/footer.tpl @@ -7,7 +7,7 @@
        -

        [[global:reconnecting-message, {config.siteTitle}]]

        +

        [[global:reconnecting-message, {config.siteTitle}]]

        diff --git a/src/views/partials/reconnect-alert.tpl b/src/views/partials/reconnect-alert.tpl index 343cf90beb..90ab679fde 100644 --- a/src/views/partials/reconnect-alert.tpl +++ b/src/views/partials/reconnect-alert.tpl @@ -1,4 +1,4 @@
        -

        [[global:reconnecting-message, {config.siteTitle}]]

        +

        [[global:reconnecting-message, {config.siteTitle}]]

        \ No newline at end of file From 7710a5e63ab3242b0aea25ffd0149bafadfdd31e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:12:51 -0400 Subject: [PATCH 242/300] fix(deps): update dependency nodebb-plugin-ntfy to v1.2.5 (#11876) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f3d6da8e52..dd1feed7a9 100644 --- a/install/package.json +++ b/install/package.json @@ -98,7 +98,7 @@ "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", "nodebb-plugin-mentions": "4.3.4", - "nodebb-plugin-ntfy": "1.2.4", + "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.1.26", From 9a07cdbd51d4eecb732b25db661fba5db8157694 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 5 Aug 2023 20:13:22 -0400 Subject: [PATCH 243/300] fix(deps): update dependency esbuild to v0.18.18 (#11879) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index dd1feed7a9..6eb49189f8 100644 --- a/install/package.json +++ b/install/package.json @@ -63,7 +63,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.17", + "esbuild": "0.18.18", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 0316f324e786758b413746b8c240e15e80935304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 02:33:28 -0400 Subject: [PATCH 244/300] feat: add toMid to chat messages --- public/language/en-GB/modules.json | 1 + public/src/client/chats.js | 39 ++++++++---- public/src/client/chats/message-search.js | 22 +++---- public/src/client/chats/messages.js | 32 +++++++++- public/src/modules/chat.js | 45 +++++++------- src/api/chats.js | 1 + src/controllers/write/chats.js | 1 + src/messaging/create.js | 11 +++- src/messaging/data.js | 72 +++++++++++++++++++---- src/topics/posts.js | 14 +++-- 10 files changed, 173 insertions(+), 65 deletions(-) diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index d65ba7cbba..0fd767d049 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 7dab41cd22..d92d27a532 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -72,16 +72,18 @@ define('forum/chats', [ Chats.addEventListeners = function () { const { roomId } = ajaxify.data; const mainWrapper = $('[component="chat/main-wrapper"]'); + const chatMessageContent = $('[component="chat/message/content"]'); const chatControls = components.get('chat/controls'); Chats.addSendHandlers(roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]')); Chats.addPopoutHandler(); Chats.addActionHandlers(components.get('chat/messages'), roomId); - Chats.addManageHandler(roomId, chatControls.find('[data-action="members"]')); + Chats.addManageHandler(roomId, chatControls.find('[data-action="manage"]')); Chats.addRenameHandler(roomId, chatControls.find('[data-action="rename"]')); Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]')); Chats.addDeleteHandler(roomId, chatControls.find('[data-action="delete"]')); - Chats.addScrollHandler(roomId, ajaxify.data.uid, $('[component="chat/message/content"]')); - Chats.addScrollBottomHandler($('[component="chat/message/content"]')); + Chats.addScrollHandler(roomId, ajaxify.data.uid, chatMessageContent); + Chats.addScrollBottomHandler(chatMessageContent); + Chats.addParentHandler(chatMessageContent); Chats.addCharactersLeftHandler(mainWrapper); Chats.addTextareaResizeHandler(mainWrapper); Chats.addIPHandler(mainWrapper); @@ -98,10 +100,10 @@ define('forum/chats', [ Chats.switchChat(); }); userList.init(roomId, mainWrapper); - messageSearch.init(roomId); + Chats.addNotificationSettingHandler(roomId, mainWrapper); + messageSearch.init(roomId, mainWrapper); Chats.addPublicRoomSortHandler(); Chats.addTooltipHandler(); - Chats.addNotificationSettingHandler(); }; Chats.addPublicRoomSortHandler = function () { @@ -141,20 +143,32 @@ define('forum/chats', [ }); }; - Chats.addNotificationSettingHandler = function () { - const notifSettingEl = $('[component="chat/notification/setting"]'); + Chats.addNotificationSettingHandler = function (roomId, containerEl) { + const notifSettingEl = containerEl.find('[component="chat/notification/setting"]'); notifSettingEl.find('[data-value]').on('click', async function () { notifSettingEl.find('i.fa-check').addClass('hidden'); const $this = $(this); $this.find('i.fa-check').removeClass('hidden'); - $('[component="chat/notification/setting/icon"]').attr('class', `fa ${$this.attr('data-icon')}`); + notifSettingEl.find('[component="chat/notification/setting/icon"]').attr('class', `fa ${$this.attr('data-icon')}`); await socket.emit('modules.chats.setNotificationSetting', { - roomId: ajaxify.data.roomId, + roomId: roomId, value: $this.attr('data-value'), }); }); }; + Chats.addParentHandler = function (chatContent) { + chatContent.on('click', '[component="chat/message/parent"]', function () { + const parentEl = $(this); + parentEl.find('[component="chat/message/parent/content"]').toggleClass('line-clamp-1'); + parentEl.find('.chat-timestamp').toggleClass('hidden'); + parentEl.toggleClass('flex-column').toggleClass('flex-row'); + if (chatContent.length && messages.isAtBottom(chatContent)) { + messages.scrollToBottom(chatContent); + } + }); + }; + Chats.addUploadHandler = function (options) { uploadHelpers.init({ @@ -285,14 +299,15 @@ define('forum/chats', [ const action = this.getAttribute('data-action'); switch (action) { - case 'edit': { + case 'reply': + messages.prepReplyTo(msgEl, roomId); + break; + case 'edit': messages.prepEdit(msgEl, messageId, roomId); break; - } case 'delete': messages.delete(messageId, roomId); break; - case 'restore': messages.restore(messageId, roomId); break; diff --git a/public/src/client/chats/message-search.js b/public/src/client/chats/message-search.js index b46cd651dc..d6490c8b3e 100644 --- a/public/src/client/chats/message-search.js +++ b/public/src/client/chats/message-search.js @@ -11,17 +11,17 @@ define('forum/chats/message-search', [ let chatContent; let clearEl; let toggleEl; - let containerEl; - messageSearch.init = function (_roomId) { + let searchContainerEl; + messageSearch.init = function (_roomId, containerEl) { roomId = _roomId; - resultListEl = $('[component="chat/message/search/results"]'); - chatContent = $('[component="chat/message/content"]'); - clearEl = $('[component="chat/room/search/clear"]'); - containerEl = $('[component="chat/room/search/container"]'); - toggleEl = $('[component="chat/room/search/toggle"'); + resultListEl = containerEl.find('[component="chat/message/search/results"]'); + chatContent = containerEl.find('[component="chat/message/content"]'); + clearEl = containerEl.find('[component="chat/room/search/clear"]'); + searchContainerEl = containerEl.find('[component="chat/room/search/container"]'); + toggleEl = containerEl.find('[component="chat/room/search/toggle"'); - searchInputEl = $('[component="chat/room/search"]'); + searchInputEl = containerEl.find('[component="chat/room/search"]'); searchInputEl.on('keyup', utils.debounce(doSearch, 250)) .on('focus', () => { if (searchInputEl.val()) { @@ -29,14 +29,14 @@ define('forum/chats/message-search', [ } }); - $('[component="chat/input"]').on('focus', () => { + containerEl.find('[component="chat/input"]').on('focus', () => { resultListEl.addClass('hidden'); chatContent.removeClass('hidden'); }); clearEl.on('click', clearInputAndResults); toggleEl.on('click', () => { - containerEl.removeClass('hidden'); + searchContainerEl.removeClass('hidden'); toggleEl.addClass('hidden'); searchInputEl.trigger('focus'); }); @@ -52,7 +52,7 @@ define('forum/chats/message-search', [ removeResults(); resultListEl.addClass('hidden'); clearEl.addClass('hidden'); - containerEl.addClass('hidden'); + searchContainerEl.addClass('hidden'); chatContent.removeClass('hidden'); toggleEl.removeClass('hidden'); } diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 041cee4585..724a23bbf0 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -21,9 +21,13 @@ define('forum/chats/messages', [ messages.updateTextAreaHeight(chatContent); const payload = { roomId, message }; ({ roomId, message } = await hooks.fire('filter:chat.send', payload)); - - api.post(`/chats/${roomId}`, { message }).then(() => { + const replyToEl = inputEl.parents('[component="chat/composer"]') + .find('[component="chat/composer/replying-to"]'); + const toMid = replyToEl.attr('data-tomid'); + api.post(`/chats/${roomId}`, { message, toMid: toMid }).then(() => { hooks.fire('action:chat.sent', { roomId, message }); + replyToEl.addClass('hidden'); + replyToEl.attr('data-tomid', ''); }).catch((err) => { inputEl.val(message).trigger('input'); messages.updateRemainingLength(inputEl.parent()); @@ -76,7 +80,7 @@ define('forum/chats/messages', [ const lastSpeaker = parseInt(lastMsgEl.attr('data-uid'), 10); const lasttimestamp = parseInt(lastMsgEl.attr('data-timestamp'), 10); if (!Array.isArray(data)) { - data.newSet = lastSpeaker !== parseInt(data.fromuid, 10) || + data.newSet = data.toMid || lastSpeaker !== parseInt(data.fromuid, 10) || parseInt(data.timestamp, 10) > parseInt(lasttimestamp, 10) + (1000 * 60 * 3); } @@ -156,6 +160,28 @@ define('forum/chats/messages', [ .toggleClass('hidden', isAtBottom); }; + messages.prepReplyTo = async function (msgEl, roomId) { + const chatMessages = msgEl.parents(`[component="chat/messages"][data-roomid="${roomId}"]`); + const chatContent = chatMessages.find('[component="chat/message/content"]'); + const composerEl = chatMessages.find('[component="chat/composer"]'); + const mid = msgEl.attr('data-mid'); + const replyToEl = composerEl.find('[component="chat/composer/replying-to"]'); + replyToEl.attr('data-tomid', mid) + .find('[component="chat/composer/replying-to-text"]') + .translateText(`[[modules:chat.replying-to, ${msgEl.attr('data-username')}]]`); + replyToEl.removeClass('hidden'); + replyToEl.find('[component="chat/composer/replying-to-cancel"]').off('click') + .on('click', () => { + replyToEl.attr('data-tomid', ''); + replyToEl.addClass('hidden'); + }); + + if (chatContent.length && messages.isAtBottom(chatContent)) { + messages.scrollToBottom(chatContent); + } + composerEl.find('[component="chat/input"]').trigger('focus'); + }; + messages.prepEdit = async function (msgEl, mid, roomId) { const raw = await socket.emit('modules.chats.getRaw', { mid: mid, roomId: roomId }); const editEl = await app.parseAndTranslate('partials/chats/edit-message', { diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 33b3e9a16a..a932943e0a 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -190,7 +190,7 @@ define('chat', [ newMessage = data.self === 0; } data.message.self = data.self; - data.message.timestamp = Math.min(Date.now(), data.message.timetamp); + data.message.timestamp = Math.min(Date.now(), data.message.timestamp); data.message.timestampISO = utils.toISOString(data.message.timestamp); addMessageToModal(data); } @@ -203,13 +203,13 @@ define('chat', [ require(['forum/chats/messages'], function (ChatsMessages) { // don't add if already added if (!modal.find('[data-mid="' + data.message.messageId + '"]').length) { - ChatsMessages.appendChatMessage(modal.find('.chat-content'), data.message); + ChatsMessages.appendChatMessage(modal.find('[component="chat/message/content"]'), data.message); } if (modal.is(':visible')) { taskbar.updateActive(modal.attr('data-uuid')); - if (ChatsMessages.isAtBottom(modal.find('.chat-content'))) { - ChatsMessages.scrollToBottom(modal.find('.chat-content')); + if (ChatsMessages.isAtBottom(modal.find('[component="chat/message/content"]'))) { + ChatsMessages.scrollToBottom(modal.find('[component="chat/message/content"]')); } } else if (!ajaxify.data.template.chats) { module.toggleNew(modal.attr('data-uuid'), true, true); @@ -254,17 +254,18 @@ define('chat', [ module.createModal = function (data, callback) { callback = callback || function () {}; require([ - 'scrollStop', 'forum/chats', 'forum/chats/messages', - ], function (scrollStop, Chats, ChatsMessages) { + 'scrollStop', 'forum/chats', 'forum/chats/messages', 'forum/chats/message-search', + ], function (scrollStop, Chats, ChatsMessages, messageSearch) { app.parseAndTranslate('chat', data, function (chatModal) { - if (module.modalExists(data.roomId)) { + const roomId = data.roomId; + if (module.modalExists(roomId)) { return callback(module.getModal(data.roomId)); } const uuid = utils.generateUUID(); let dragged = false; - chatModal.attr('id', 'chat-modal-' + data.roomId); - chatModal.attr('data-roomid', data.roomId); + chatModal.attr('id', 'chat-modal-' + roomId); + chatModal.attr('data-roomid', roomId); chatModal.attr('intervalId', 0); chatModal.attr('data-uuid', uuid); chatModal.css('position', 'fixed'); @@ -313,7 +314,7 @@ define('chat', [ components.get('chat/input').val(text); }); - ajaxify.go('user/' + app.user.userslug + '/chats/' + chatModal.attr('data-roomid')); + ajaxify.go(`user/${app.user.userslug}/chats/${roomId}`); module.close(uuid); } @@ -340,23 +341,23 @@ define('chat', [ chatModal.on('mousemove keypress click', function () { if (newMessage) { - api.del(`/chats/${data.roomId}/state`, {}); + api.del(`/chats/${roomId}/state`, {}); newMessage = false; } }); - Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), data.roomId); - Chats.addRenameHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="rename"]'), data.roomName); - Chats.addLeaveHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="leave"]')); - Chats.addDeleteHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="delete"]')); - Chats.addSendHandlers(chatModal.attr('data-roomid'), chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); - Chats.addManageHandler(chatModal.attr('data-roomid'), chatModal.find('[data-action="members"]')); + Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), roomId); + Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]'), data.roomName); + Chats.addLeaveHandler(roomId, chatModal.find('[data-action="leave"]')); + Chats.addDeleteHandler(roomId, chatModal.find('[data-action="delete"]')); + Chats.addSendHandlers(roomId, chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); + Chats.addManageHandler(roomId, chatModal.find('[data-action="manage"]')); - Chats.createAutoComplete(chatModal.attr('data-roomid'), chatModal.find('[component="chat/input"]')); - - Chats.addScrollHandler(chatModal.attr('data-roomid'), data.uid, chatModal.find('.chat-content')); - Chats.addScrollBottomHandler(chatModal.find('.chat-content')); + Chats.createAutoComplete(roomId, chatModal.find('[component="chat/input"]')); + Chats.addScrollHandler(roomId, data.uid, chatModal.find('[component="chat/message/content"]')); + Chats.addScrollBottomHandler(chatModal.find('[component="chat/message/content"]')); + Chats.addParentHandler(chatModal.find('[component="chat/message/content"]')); Chats.addCharactersLeftHandler(chatModal); Chats.addTextareaResizeHandler(chatModal); Chats.addIPHandler(chatModal); @@ -370,6 +371,8 @@ define('chat', [ }); ChatsMessages.addSocketListeners(); + messageSearch.init(roomId, chatModal); + Chats.addNotificationSettingHandler(roomId, chatModal); taskbar.push('chat', chatModal.attr('data-uuid'), { title: '[[modules:chat.chatting_with]] ' + (data.roomName || (data.users.length ? data.users[0].username : '')), diff --git a/src/api/chats.js b/src/api/chats.js index 16a54de74d..dc46ec522d 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -87,6 +87,7 @@ chatsAPI.post = async (caller, data) => { uid: caller.uid, roomId: data.roomId, content: data.message, + toMid: data.toMid, timestamp: Date.now(), ip: caller.ip, }); diff --git a/src/controllers/write/chats.js b/src/controllers/write/chats.js index 2266795eec..f6b9378836 100644 --- a/src/controllers/write/chats.js +++ b/src/controllers/write/chats.js @@ -33,6 +33,7 @@ Chats.get = async (req, res) => { Chats.post = async (req, res) => { const messageObj = await api.chats.post(req, { message: req.body.message, + toMid: req.body.toMid, roomId: req.params.roomId, }); diff --git a/src/messaging/create.js b/src/messaging/create.js index 872f22613f..81da98d0d6 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -6,6 +6,7 @@ const meta = require('../meta'); const plugins = require('../plugins'); const db = require('../database'); const user = require('../user'); +const utils = require('../utils'); module.exports = function (Messaging) { Messaging.sendMessage = async (data) => { @@ -41,6 +42,9 @@ module.exports = function (Messaging) { if (!roomData) { throw new Error('[[error:no-room]]'); } + if (data.toMid && !utils.isNumber(data.toMid)) { + throw new Error('[[error:invalid-mid]]'); + } const mid = await db.incrObjectField('global', 'nextMid'); const timestamp = data.timestamp || Date.now(); let message = { @@ -50,7 +54,9 @@ module.exports = function (Messaging) { fromuid: uid, roomId: roomId, }; - + if (data.toMid) { + message.toMid = data.toMid; + } if (data.system) { message.system = data.system; } @@ -69,6 +75,9 @@ module.exports = function (Messaging) { db.sortedSetAdd('messages:mid', timestamp, mid), db.incrObjectField('global', 'messageCount'), ]; + if (data.toMid) { + tasks.push(db.sortedSetAdd(`mid:${data.toMid}:replies`, timestamp, mid)); + } if (roomData.public) { tasks.push( db.sortedSetAdd('chat:rooms:public:lastpost', timestamp, roomId) diff --git a/src/messaging/data.js b/src/messaging/data.js index 3542de799f..81d41e047a 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -1,5 +1,6 @@ 'use strict'; +const _ = require('lodash'); const validator = require('validator'); const db = require('../database'); @@ -73,16 +74,7 @@ module.exports = function (Messaging) { message.roomId = String(message.roomId || roomId); }); - messages = await Promise.all(messages.map(async (message) => { - if (message.system) { - message.content = validator.escape(String(message.content)); - return message; - } - - const result = await Messaging.parse(message.content, message.fromuid, uid, roomId, isNew); - message.content = result; - return message; - })); + await parseMessages(messages, uid, roomId, isNew); if (messages.length > 1) { // Add a spacer in between messages with time gaps between them @@ -96,7 +88,7 @@ module.exports = function (Messaging) { message.newSet = true; } else if (index > 0 && messages[index - 1].system) { message.newSet = true; - } else if (index === 0) { + } else if (index === 0 || message.toMid) { message.newSet = true; } @@ -111,7 +103,7 @@ module.exports = function (Messaging) { const fields = await Messaging.getMessageFields(mid, ['fromuid', 'timestamp']); if ((messages[0].timestamp > fields.timestamp + Messaging.newMessageCutoff) || (messages[0].fromuid !== fields.fromuid) || - messages[0].system) { + messages[0].system || messages[0].toMid) { // If it's been 5 minutes, this is a new set of messages messages[0].newSet = true; } @@ -120,6 +112,8 @@ module.exports = function (Messaging) { } } + await addParentMessages(messages, uid, roomId); + const data = await plugins.hooks.fire('filter:messaging.getMessages', { messages: messages, uid: uid, @@ -130,6 +124,60 @@ module.exports = function (Messaging) { return data && data.messages; }; + + async function addParentMessages(messages, uid, roomId) { + let parentMids = messages.map(msg => (msg && msg.hasOwnProperty('toMid') ? parseInt(msg.toMid, 10) : null)).filter(Boolean); + + if (!parentMids.length) { + return; + } + parentMids = _.uniq(parentMids); + const parentMessages = await Messaging.getMessagesFields(parentMids, [ + 'fromuid', 'content', 'timestamp', + ]); + const parentUids = _.uniq(parentMessages.map(msg => msg && msg.fromuid)); + const usersMap = _.zipObject( + parentUids, + await user.getUsersFields(parentUids, ['uid', 'username', 'userslug', 'picture']) + ); + + await Promise.all(parentMessages.map(async (parentMsg) => { + const foundMsg = messages.find(msg => parseInt(msg.mid, 10) === parseInt(parentMsg.mid, 10)); + if (foundMsg) { + parentMsg.content = foundMsg.content; + return; + } + parentMsg.content = await parseMessage(parentMsg, uid, roomId, false); + })); + + const parents = {}; + parentMessages.forEach((msg, i) => { + if (usersMap[msg.fromuid]) { + msg.user = usersMap[msg.fromuid]; + parents[parentMids[i]] = msg; + } + }); + + messages.forEach((msg) => { + if (parents[msg.toMid]) { + msg.parent = parents[msg.toMid]; + msg.parent.mid = msg.toMid; + } + }); + } + + async function parseMessages(messages, uid, roomId, isNew) { + await Promise.all(messages.map(async (message) => { + message.content = await parseMessage(message, uid, roomId, isNew); + })); + } + async function parseMessage(message, uid, roomId, isNew) { + if (message.system) { + return validator.escape(String(message.content)); + } + + return await Messaging.parse(message.content, message.fromuid, uid, roomId, isNew); + } }; async function modifyMessage(message, fields, mid) { diff --git a/src/topics/posts.js b/src/topics/posts.js index 438844d753..1d1b95af2b 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -189,14 +189,18 @@ module.exports = function (Topics) { const usersMap = _.zipObject(parentUids, userData); const parents = {}; parentPosts.forEach((post, i) => { - parents[parentPids[i]] = { - username: usersMap[post.uid].username, - displayname: usersMap[post.uid].displayname, - }; + if (usersMap[post.uid]) { + parents[parentPids[i]] = { + username: usersMap[post.uid].username, + displayname: usersMap[post.uid].displayname, + }; + } }); postData.forEach((post) => { - post.parent = parents[post.toPid]; + if (parents[post.toPid]) { + post.parent = parents[post.toPid]; + } }); }; From ab6686178fd071e17e293087774158991a3fa560 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 6 Aug 2023 06:33:54 +0000 Subject: [PATCH 245/300] chore(i18n): fallback strings for new resources: nodebb.modules --- public/language/ar/modules.json | 1 + public/language/bg/modules.json | 1 + public/language/bn/modules.json | 1 + public/language/cs/modules.json | 1 + public/language/da/modules.json | 1 + public/language/de/modules.json | 1 + public/language/el/modules.json | 1 + public/language/en-US/modules.json | 1 + public/language/en-x-pirate/modules.json | 1 + public/language/es/modules.json | 1 + public/language/et/modules.json | 1 + public/language/fa-IR/modules.json | 1 + public/language/fi/modules.json | 1 + public/language/fr/modules.json | 1 + public/language/gl/modules.json | 1 + public/language/he/modules.json | 1 + public/language/hr/modules.json | 1 + public/language/hu/modules.json | 1 + public/language/hy/modules.json | 1 + public/language/id/modules.json | 1 + public/language/it/modules.json | 1 + public/language/ja/modules.json | 1 + public/language/ko/modules.json | 1 + public/language/lt/modules.json | 1 + public/language/lv/modules.json | 1 + public/language/ms/modules.json | 1 + public/language/nb/modules.json | 1 + public/language/nl/modules.json | 1 + public/language/pl/modules.json | 1 + public/language/pt-BR/modules.json | 1 + public/language/pt-PT/modules.json | 1 + public/language/ro/modules.json | 1 + public/language/ru/modules.json | 1 + public/language/rw/modules.json | 1 + public/language/sc/modules.json | 1 + public/language/sk/modules.json | 1 + public/language/sl/modules.json | 1 + public/language/sq-AL/modules.json | 1 + public/language/sr/modules.json | 1 + public/language/sv/modules.json | 1 + public/language/th/modules.json | 1 + public/language/tr/modules.json | 1 + public/language/uk/modules.json | 1 + public/language/vi/modules.json | 1 + public/language/zh-CN/modules.json | 1 + public/language/zh-TW/modules.json | 1 + 46 files changed, 46 insertions(+) diff --git a/public/language/ar/modules.json b/public/language/ar/modules.json index fbdf7dfe4e..80e6716909 100644 --- a/public/language/ar/modules.json +++ b/public/language/ar/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "لا يوجد لديك دردشات نشطة.", "chat.user_typing": "%1 يكتب رسالة...", "chat.user_has_messaged_you": "%1 أرسل لك رسالة.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "المرجو اختيار مرسل إليه لمعاينة تاريخ الدردشات", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 22b4e1eeb3..9fee3beb51 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Нямате текущи разговори.", "chat.user_typing": "%1 пише...", "chat.user_has_messaged_you": "%1 Ви написа съобщение.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Всички разговори", "chat.mark_all_read": "Отбелязване на всички като прочетени", "chat.no-messages": "Моля, изберете получател, за да видите историята на съобщенията", diff --git a/public/language/bn/modules.json b/public/language/bn/modules.json index 34ed5158f8..18793084f6 100644 --- a/public/language/bn/modules.json +++ b/public/language/bn/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "আপনার কোন সচল কথোপকথন নেই", "chat.user_typing": "%1 লিখছেন", "chat.user_has_messaged_you": "%1 আপনাকে বার্তা পাঠিয়েছেন", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "মেসেজ হিস্টোরী দেখতে প্রাপক নির্বাচন করুন", diff --git a/public/language/cs/modules.json b/public/language/cs/modules.json index c85beb8727..369e9b0b4f 100644 --- a/public/language/cs/modules.json +++ b/public/language/cs/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nemáte žádné aktivní konverzace.", "chat.user_typing": "%1 píše…", "chat.user_has_messaged_you": "%1 Vám napsal.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Vyberte příjemce k prohlédnutí historie zpráv.", diff --git a/public/language/da/modules.json b/public/language/da/modules.json index 02b9f3c7b4..ed8526fabd 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du har ingen aktive chats.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har skrevet til dig.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Vælg en modtager for at se beskedhistorikken", diff --git a/public/language/de/modules.json b/public/language/de/modules.json index a59290000b..23a5321dc8 100644 --- a/public/language/de/modules.json +++ b/public/language/de/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du hast keine aktiven Chats.", "chat.user_typing": "%1 tippt gerade ...", "chat.user_has_messaged_you": "%1 hat dir geschrieben.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alle Chats", "chat.mark_all_read": "Alle als gelesen markieren", "chat.no-messages": "Bitte wähle einen Empfänger, um den jeweiligen Nachrichtenverlauf anzuzeigen.", diff --git a/public/language/el/modules.json b/public/language/el/modules.json index cabfa8feaa..070d1ba4f4 100644 --- a/public/language/el/modules.json +++ b/public/language/el/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", diff --git a/public/language/en-US/modules.json b/public/language/en-US/modules.json index cabfa8feaa..070d1ba4f4 100644 --- a/public/language/en-US/modules.json +++ b/public/language/en-US/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "You have no active chats.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", diff --git a/public/language/en-x-pirate/modules.json b/public/language/en-x-pirate/modules.json index ecd5f0f7f7..7bd33c38ec 100644 --- a/public/language/en-x-pirate/modules.json +++ b/public/language/en-x-pirate/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Ye be a lonely sailor.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", diff --git a/public/language/es/modules.json b/public/language/es/modules.json index 3270b233ec..55d8684a87 100644 --- a/public/language/es/modules.json +++ b/public/language/es/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "No tiene conversaciones activas.", "chat.user_typing": "%1 está escribiendo...", "chat.user_has_messaged_you": "%1 te ha enviado un mensaje.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor, selecciona un contacto para ver el historial de mensajes", diff --git a/public/language/et/modules.json b/public/language/et/modules.json index e4b95555a1..93a3f5a21f 100644 --- a/public/language/et/modules.json +++ b/public/language/et/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Sul ei ole hetkel aktiivseid vestlusi.", "chat.user_typing": "%1 kirjutab sõnumit...", "chat.user_has_messaged_you": "%1 saatis sulle sõnumi.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Vali sõnumisaaja, et vaadata sõnumite ajalugu.", diff --git a/public/language/fa-IR/modules.json b/public/language/fa-IR/modules.json index 42cba33bb6..7034b505e5 100644 --- a/public/language/fa-IR/modules.json +++ b/public/language/fa-IR/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "شما هیچ گفتگوی فعالی ندارید.", "chat.user_typing": "%1 در حال نوشتن است...", "chat.user_has_messaged_you": "%1 به شما پیام داده است.", + "chat.replying-to": "Replying to %1", "chat.see_all": "همه‌ی چت‌ها", "chat.mark_all_read": "همه را خوانده‌شده بگیر", "chat.no-messages": "مشخص کنید تاریخچه گفتگوها با چه کاربری را می‌خواهید ببینید", diff --git a/public/language/fi/modules.json b/public/language/fi/modules.json index 5bac4fcf40..38dc299ac9 100644 --- a/public/language/fi/modules.json +++ b/public/language/fi/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Sinulla ei ole aktiivisia keskusteluita.", "chat.user_typing": "%1 kirjoittaa ...", "chat.user_has_messaged_you": "%1 lähetti sinulle viestin.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Valitse vastaanottaja katsellaksesi keskusteluhistoriaa", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 451dafc5ba..dc49960d2d 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Vous n'avez aucune discussion en cours.", "chat.user_typing": "%1 est en train d'écrire ...", "chat.user_has_messaged_you": "%1 vous a envoyé un message.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Tous les chats", "chat.mark_all_read": "Marquez tous comme lu", "chat.no-messages": "Veuillez sélectionner un destinataire pour voir l'historique des discussions", diff --git a/public/language/gl/modules.json b/public/language/gl/modules.json index 793453dd84..985ed67510 100644 --- a/public/language/gl/modules.json +++ b/public/language/gl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Non tes charlas activas.", "chat.user_typing": "%1 está a escribir...", "chat.user_has_messaged_you": "%1 enviouche unha mensaxe.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor, seleccione un destinatario para ver o historial das mensaxes ", diff --git a/public/language/he/modules.json b/public/language/he/modules.json index d25b426051..1968510ea0 100644 --- a/public/language/he/modules.json +++ b/public/language/he/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "אין לכם צ'אטים פעילים.", "chat.user_typing": "%1 מקליד...", "chat.user_has_messaged_you": "ל%1 יש הודעה עבורכם.", + "chat.replying-to": "Replying to %1", "chat.see_all": "צפו בכל הצ'אטים", "chat.mark_all_read": "סמנו את כל הצ'אטים כ'נקראו'", "chat.no-messages": "בחרו משתמש על מנת לראות את שיחות הצ'אט ביניכם", diff --git a/public/language/hr/modules.json b/public/language/hr/modules.json index acf8cacc93..0009842c19 100644 --- a/public/language/hr/modules.json +++ b/public/language/hr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nemate aktivnih razgovora.", "chat.user_typing": "%1 piše poruku ...", "chat.user_has_messaged_you": "%1 vam je poslao poruku.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Odaberite primatelja da vidite povijest razgovora", diff --git a/public/language/hu/modules.json b/public/language/hu/modules.json index 9a058aa48e..8218e1b19d 100644 --- a/public/language/hu/modules.json +++ b/public/language/hu/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nincs aktív csevegésed.", "chat.user_typing": "%1 éppen ír ...", "chat.user_has_messaged_you": "%1 üzenetet küldött.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Összes csevegés", "chat.mark_all_read": "Összes olvasottként jelölése", "chat.no-messages": "Válasszuk ki a címzettet és tekintsük meg a chat előzményeket", diff --git a/public/language/hy/modules.json b/public/language/hy/modules.json index a73d40682f..15f507dc86 100644 --- a/public/language/hy/modules.json +++ b/public/language/hy/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Դուք չունեք որևէ ակտիվ չաթ", "chat.user_typing": "%1-ը գրում է...", "chat.user_has_messaged_you": "%1-ը ձեզ հաղորդագրություն է ուղարկել:", + "chat.replying-to": "Replying to %1", "chat.see_all": "Բոլոր չաթերը", "chat.mark_all_read": "Նշել բոլորը կարդացված", "chat.no-messages": "Խնդրում ենք ընտրել ստացող՝ զրույցի հաղորդագրության պատմությունը դիտելու համար", diff --git a/public/language/id/modules.json b/public/language/id/modules.json index 458c0d5c54..31b997c2bd 100644 --- a/public/language/id/modules.json +++ b/public/language/id/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Kamu tidak memiliki percakapan yang aktif.", "chat.user_typing": "%1 sedang menulis ...", "chat.user_has_messaged_you": "%1 telah mengirimkan pesan untukmu.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Mohon pilih satu penerima untuk melihat riwayat pesan percakapan", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 6bcf7cc1ad..567b9e501c 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Non hai chat attive.", "chat.user_typing": "%1 sta scrivendo...", "chat.user_has_messaged_you": "%1 ti ha scritto.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Tutte le chat", "chat.mark_all_read": "Segna tutto come letto", "chat.no-messages": "Si prega di selezionare un destinatario per vedere la cronologia dei messaggi", diff --git a/public/language/ja/modules.json b/public/language/ja/modules.json index a61995dc75..f4b834ebb0 100644 --- a/public/language/ja/modules.json +++ b/public/language/ja/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "チャットはありません。", "chat.user_typing": "%1 が入力中 ...", "chat.user_has_messaged_you": "%1さんからメッセージが届いています。", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "チャットメッセージの履歴を表示するには、受信者を選択してください", diff --git a/public/language/ko/modules.json b/public/language/ko/modules.json index c1250bdf0e..620530c29f 100644 --- a/public/language/ko/modules.json +++ b/public/language/ko/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "활성화된 채팅이 없습니다.", "chat.user_typing": "%1님이 입력 중...", "chat.user_has_messaged_you": "%1님이 메시지를 보냈습니다.", + "chat.replying-to": "Replying to %1", "chat.see_all": "모든 채팅", "chat.mark_all_read": "Mark all read", "chat.no-messages": "채팅 기록을 보려면 채팅 상대를 선택하세요.", diff --git a/public/language/lt/modules.json b/public/language/lt/modules.json index 9eb7a5582c..65598f594d 100644 --- a/public/language/lt/modules.json +++ b/public/language/lt/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Jūs neturite aktyvių susirašinėjimų.", "chat.user_typing": "%1 dabar rašo...", "chat.user_has_messaged_you": "%1 parašė jums.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Prašome pasirikti gavėją, norėdami peržiūrėti žinučių istoriją", diff --git a/public/language/lv/modules.json b/public/language/lv/modules.json index 1f38d20f22..8e02627ed8 100644 --- a/public/language/lv/modules.json +++ b/public/language/lv/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nav aktīvo sarunu.", "chat.user_typing": "%1 raksta...", "chat.user_has_messaged_you": "%1 ir sācis ar Tevi sarunāties", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Lūdzu, izvēlies adresātu, lai skatītu sarunu vēsturi", diff --git a/public/language/ms/modules.json b/public/language/ms/modules.json index 283a56131f..2de5959ea1 100644 --- a/public/language/ms/modules.json +++ b/public/language/ms/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Anda tiada pesanan yang aktif", "chat.user_typing": "%1 menaip", "chat.user_has_messaged_you": "%1 mesej anda.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Sila pilih penerima untuk lihat sejarah sembang", diff --git a/public/language/nb/modules.json b/public/language/nb/modules.json index 46cab144c6..5ecd45afe2 100644 --- a/public/language/nb/modules.json +++ b/public/language/nb/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du har ingen aktive chatter.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har sendt deg en melding", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alle chatter", "chat.mark_all_read": "Marker alle som lest", "chat.no-messages": "Vennligst velg en mottaker for å vise chatte-melding historikk", diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index f66aa4ecea..dfd2fd9879 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Er zijn geen actieve chats.", "chat.user_typing": "%1 is aan het typen ...", "chat.user_has_messaged_you": "%1 heeft een bericht gestuurd", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alle chats", "chat.mark_all_read": "Alles markeren als gelezen", "chat.no-messages": "Selecteer een ontvanger om de chatgeschiedenis in te zien", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 2c01303394..fec0d97f12 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Brak aktywnych czatów", "chat.user_typing": "%1 pisze...", "chat.user_has_messaged_you": "%1 napisał do Ciebie", + "chat.replying-to": "Replying to %1", "chat.see_all": "Wszystkie rozmowy", "chat.mark_all_read": "Zaznacz wszystkie jako przeczytane", "chat.no-messages": "Wybierz adresata, by wyświetlić historię czatów", diff --git a/public/language/pt-BR/modules.json b/public/language/pt-BR/modules.json index 3bc3d9ab68..7eff359ffc 100644 --- a/public/language/pt-BR/modules.json +++ b/public/language/pt-BR/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Você não tem chats ativos.", "chat.user_typing": "%1 está digitando ...", "chat.user_has_messaged_you": "%1 te enviou uma mensagem.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor, escolha um destinatário para visualizar o histórico de conversas", diff --git a/public/language/pt-PT/modules.json b/public/language/pt-PT/modules.json index cb139a7422..6476c0ae9f 100644 --- a/public/language/pt-PT/modules.json +++ b/public/language/pt-PT/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Não tens conversas ativas.", "chat.user_typing": "%1 está a escrever ...", "chat.user_has_messaged_you": "%1 enviou-te uma mensagem.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Por favor seleciona um destinatário para veres o histórico de mensagens", diff --git a/public/language/ro/modules.json b/public/language/ro/modules.json index 71bea16413..52887070c8 100644 --- a/public/language/ro/modules.json +++ b/public/language/ro/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nu ai nici o conversație activă", "chat.user_typing": "%1 scrie ...", "chat.user_has_messaged_you": "%1 ți-a trimis un mesaj.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Selectează un recipient pentru a vedea istoria mesajelor chat", diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index ff107d8c02..dbe91982a9 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "У вас нет активных чатов.", "chat.user_typing": "%1 пишет...", "chat.user_has_messaged_you": "Пользователь %1 отправил вам сообщение.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Все чаты", "chat.mark_all_read": "Пометить как прочитанное", "chat.no-messages": "Пожалуйста, выберите собеседника для просмотра истории сообщений", diff --git a/public/language/rw/modules.json b/public/language/rw/modules.json index a95079801a..e362fcb911 100644 --- a/public/language/rw/modules.json +++ b/public/language/rw/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nta biganiro byo mu gikari ufite. ", "chat.user_typing": "%1 ari kwandika ...", "chat.user_has_messaged_you": "%1 yagusigiye ubutumwa.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Hitamo umuntu ushaka kurebera ibyo mwandikiranye", diff --git a/public/language/sc/modules.json b/public/language/sc/modules.json index ffe8ad3a6b..cdf15aa3d9 100644 --- a/public/language/sc/modules.json +++ b/public/language/sc/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Non tenes tzarras ativas.", "chat.user_typing": "%1 is typing ...", "chat.user_has_messaged_you": "%1 has messaged you.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Please select a recipient to view chat message history", diff --git a/public/language/sk/modules.json b/public/language/sk/modules.json index 533a63ea17..e214558f6f 100644 --- a/public/language/sk/modules.json +++ b/public/language/sk/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Nemáte žiadne aktívne konverzácie.", "chat.user_typing": "%1 práve píše...", "chat.user_has_messaged_you": "%1 Vám poslal správu.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Prosím vyberte príjemcu, pre zobrazenie histórie správ v konverzácií", diff --git a/public/language/sl/modules.json b/public/language/sl/modules.json index 93020498f5..ae36dac325 100644 --- a/public/language/sl/modules.json +++ b/public/language/sl/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Ni aktivnih klepetov.", "chat.user_typing": "%1 piše sporočilo ...", "chat.user_has_messaged_you": "%1 ti je poslal/-a sporočilo.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Za pregled zgodovine klepeta izberi prejemnika.", diff --git a/public/language/sq-AL/modules.json b/public/language/sq-AL/modules.json index a9180aa6ff..ba73c8990f 100644 --- a/public/language/sq-AL/modules.json +++ b/public/language/sq-AL/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Ju nuk keni biseda aktive.", "chat.user_typing": "%1 është duke shkruajtur...", "chat.user_has_messaged_you": "%1 ju ka dërguar mesazh.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Ju lutemi zgjidhni një person për të parë historikun e mesazheve të bisedës", diff --git a/public/language/sr/modules.json b/public/language/sr/modules.json index b275dd2136..1bc9404283 100644 --- a/public/language/sr/modules.json +++ b/public/language/sr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Нема активних ћаскања.", "chat.user_typing": "%1 куца ...", "chat.user_has_messaged_you": "%1 вам је послао поруку.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Сва ћаскања", "chat.mark_all_read": "Означи све као прочитано", "chat.no-messages": "Изаберите примаоца да бисте видели историју ћаскања", diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index 20ffa27565..3ddf315fae 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Du har inte några aktiva chattar.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har skickat ett medelande till dig.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Alla chattar", "chat.mark_all_read": "Markera alla chattar som lästa", "chat.no-messages": "Välj mottagare för att visa historik för chattmeddelande", diff --git a/public/language/th/modules.json b/public/language/th/modules.json index 55690f2b3c..aac0f60788 100644 --- a/public/language/th/modules.json +++ b/public/language/th/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "คุณไม่มีแชทที่คุยอยู่", "chat.user_typing": "%1 กำลังพิมพ์อยู่ ...", "chat.user_has_messaged_you": "%1 ได้ส่งข้อความถึงคุณ", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "กรุณาเลือกผู้รับเพื่อดูประวัติข้อความ", diff --git a/public/language/tr/modules.json b/public/language/tr/modules.json index 660a37b410..bd7988f3db 100644 --- a/public/language/tr/modules.json +++ b/public/language/tr/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Aktif sohbet mevcut değil", "chat.user_typing": "%1 yazıyor ...", "chat.user_has_messaged_you": "%1 size bir mesaj gönderdi.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Bütün Sohbetler", "chat.mark_all_read": "Hepsini Okundu Olarak İşaretle", "chat.no-messages": "Lütfen sohbet geçmişini görüntülemek için bir alıcı seçin", diff --git a/public/language/uk/modules.json b/public/language/uk/modules.json index 1d56251f71..1ef15ebb33 100644 --- a/public/language/uk/modules.json +++ b/public/language/uk/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "У вас немає активних чатів.", "chat.user_typing": "%1 друкує...", "chat.user_has_messaged_you": "%1 написав вам.", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "Будь ласка, оберіть отримувача, щоб переглянути історію повідомлень", diff --git a/public/language/vi/modules.json b/public/language/vi/modules.json index 45edc6289b..c40cf10b7b 100644 --- a/public/language/vi/modules.json +++ b/public/language/vi/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "Bạn không có cuộc trò chuyện đang hoạt động nào.", "chat.user_typing": "%1 đang nhập...", "chat.user_has_messaged_you": "%1 đã nhắn tin cho bạn.", + "chat.replying-to": "Replying to %1", "chat.see_all": "Tất cả trò chuyện", "chat.mark_all_read": "Đánh dấu tất cả đã đọc", "chat.no-messages": "Vui lòng chọn người nhận để xem lịch sử tin nhắn trò chuyện", diff --git a/public/language/zh-CN/modules.json b/public/language/zh-CN/modules.json index aa264a32e3..78c10e8929 100644 --- a/public/language/zh-CN/modules.json +++ b/public/language/zh-CN/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "暂无聊天", "chat.user_typing": "%1 正在输入……", "chat.user_has_messaged_you": "%1 向您发送了消息。", + "chat.replying-to": "Replying to %1", "chat.see_all": "全部对话", "chat.mark_all_read": "标记全部已读", "chat.no-messages": "请选择接收人,以查看聊天消息历史", diff --git a/public/language/zh-TW/modules.json b/public/language/zh-TW/modules.json index 2245a72dcf..0f209c2cb1 100644 --- a/public/language/zh-TW/modules.json +++ b/public/language/zh-TW/modules.json @@ -10,6 +10,7 @@ "chat.no_active": "暫無聊天", "chat.user_typing": "%1 正在輸入……", "chat.user_has_messaged_you": "%1 向您發送了訊息。", + "chat.replying-to": "Replying to %1", "chat.see_all": "All chats", "chat.mark_all_read": "Mark all read", "chat.no-messages": "請選擇接收人,以查看聊天訊息紀錄", From 35c97bcb1af6366167a148ef8beacf97466dba78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 02:34:34 -0400 Subject: [PATCH 246/300] chore: up themes --- install/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/package.json b/install/package.json index 6eb49189f8..3587768617 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.26", + "nodebb-theme-harmony": "1.1.27", "nodebb-theme-lavender": "7.1.3", - "nodebb-theme-peace": "2.1.8", - "nodebb-theme-persona": "13.2.13", + "nodebb-theme-peace": "2.1.9", + "nodebb-theme-persona": "13.2.14", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", From a282f7017291b693213c17a88f3eccd1afa8e2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 02:56:50 -0400 Subject: [PATCH 247/300] chore: harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 3587768617..51e9f5a6e3 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.27", + "nodebb-theme-harmony": "1.1.28", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.9", "nodebb-theme-persona": "13.2.14", From 5f7fe9c6fc77b00a8a88f24a4d91c1903f518080 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 6 Aug 2023 09:18:35 +0000 Subject: [PATCH 248/300] Latest translations and fallbacks --- public/language/it/global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/language/it/global.json b/public/language/it/global.json index 2230002ab2..7c52a6c4a9 100644 --- a/public/language/it/global.json +++ b/public/language/it/global.json @@ -51,8 +51,8 @@ "nextpage": "Pagina Successiva", "alert.success": "Riuscito", "alert.error": "Errore", - "alert.warning": "Warning", - "alert.info": "Info", + "alert.warning": "Avvertimento", + "alert.info": "Informazioni", "alert.banned": "Bannato", "alert.banned.message": "Sei stato appena bannato, il tuo accesso è ora limitato.", "alert.unbanned": "Non bannato", From 9ba6dda8bf8afc8457e02d124b09ba8adcb44e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 10:13:33 -0400 Subject: [PATCH 249/300] handle delete/restore/edit messages --- public/src/client/chats/messages.js | 21 +++++++++++++++++++++ src/messaging/data.js | 6 +++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 724a23bbf0..3f961f8865 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -263,6 +263,12 @@ define('forum/chats/messages', [ const self = parseInt(message.fromuid, 10) === parseInt(app.user.uid, 10); message.self = self ? 1 : 0; messages.parseMessage(message, function (html) { + const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${message.mid}"]`); + if (parentEl.length) { + parentEl.find('[component="chat/message/parent/content"]').html( + html.find('[component="chat/message/body"]').html() + ); + } const msgEl = components.get('chat/message', message.mid); if (msgEl.length) { msgEl.replaceWith(html); @@ -274,21 +280,36 @@ define('forum/chats/messages', [ function onChatMessageDeleted(messageId) { const msgEl = components.get('chat/message', messageId); + const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${messageId}"]`); const isSelf = parseInt(msgEl.attr('data-uid'), 10) === app.user.uid; + const isParentSelf = parseInt(parentEl.attr('data-uid'), 10) === app.user.uid; msgEl.toggleClass('deleted', true); + parentEl.toggleClass('deleted', true); if (!isSelf) { msgEl.find('[component="chat/message/body"]') .translateHtml('

        [[modules:chat.message-deleted]]

        '); } + if (!isParentSelf) { + parentEl.find('[component="chat/message/parent/content"]') + .translateHtml('

        [[modules:chat.message-deleted]]

        '); + } } function onChatMessageRestored(message) { const msgEl = components.get('chat/message', message.messageId); + const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${message.messageId}"]`); const isSelf = parseInt(msgEl.attr('data-uid'), 10) === app.user.uid; + const isParentSelf = parseInt(parentEl.attr('data-uid'), 10) === app.user.uid; msgEl.toggleClass('deleted', false); + parentEl.toggleClass('deleted', false); + if (!isParentSelf) { + parentEl.find('[component="chat/message/parent/content"]') + .translateHtml(message.content); + } if (!isSelf) { msgEl.find('[component="chat/message/body"]') .translateHtml(message.content); + messages.onMessagesAddedToDom(components.get('chat/message', message.messageId)); } } diff --git a/src/messaging/data.js b/src/messaging/data.js index 81d41e047a..94d9c37e8c 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -133,7 +133,7 @@ module.exports = function (Messaging) { } parentMids = _.uniq(parentMids); const parentMessages = await Messaging.getMessagesFields(parentMids, [ - 'fromuid', 'content', 'timestamp', + 'fromuid', 'content', 'timestamp', 'deleted', ]); const parentUids = _.uniq(parentMessages.map(msg => msg && msg.fromuid)); const usersMap = _.zipObject( @@ -142,6 +142,10 @@ module.exports = function (Messaging) { ); await Promise.all(parentMessages.map(async (parentMsg) => { + if (parentMsg.deleted && parentMsg.fromuid !== parseInt(uid, 10)) { + parentMsg.content = `

        [[modules:chat.message-deleted]]

        `; + return; + } const foundMsg = messages.find(msg => parseInt(msg.mid, 10) === parseInt(parentMsg.mid, 10)); if (foundMsg) { parentMsg.content = foundMsg.content; From ec0747fd0de0d24658432f647d019e20dbdc8a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 10:36:57 -0400 Subject: [PATCH 250/300] fix parent updates --- install/package.json | 6 +++--- public/src/client/chats/messages.js | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/install/package.json b/install/package.json index 51e9f5a6e3..b37802df00 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.28", + "nodebb-theme-harmony": "1.1.29", "nodebb-theme-lavender": "7.1.3", - "nodebb-theme-peace": "2.1.9", - "nodebb-theme-persona": "13.2.14", + "nodebb-theme-peace": "2.1.10", + "nodebb-theme-persona": "13.2.15", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 3f961f8865..864b6e0604 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -263,16 +263,19 @@ define('forum/chats/messages', [ const self = parseInt(message.fromuid, 10) === parseInt(app.user.uid, 10); message.self = self ? 1 : 0; messages.parseMessage(message, function (html) { + const msgEl = components.get('chat/message', message.mid); + if (msgEl.length) { + msgEl.replaceWith(html); + messages.onMessagesAddedToDom(components.get('chat/message', message.mid)); + } const parentEl = $(`[component="chat/message/parent"][data-parent-mid="${message.mid}"]`); if (parentEl.length) { parentEl.find('[component="chat/message/parent/content"]').html( html.find('[component="chat/message/body"]').html() ); - } - const msgEl = components.get('chat/message', message.mid); - if (msgEl.length) { - msgEl.replaceWith(html); - messages.onMessagesAddedToDom(components.get('chat/message', message.mid)); + messages.onMessagesAddedToDom( + $(`[component="chat/message/parent"][data-parent-mid="${message.mid}"]`) + ); } }); }); @@ -302,15 +305,17 @@ define('forum/chats/messages', [ const isParentSelf = parseInt(parentEl.attr('data-uid'), 10) === app.user.uid; msgEl.toggleClass('deleted', false); parentEl.toggleClass('deleted', false); - if (!isParentSelf) { - parentEl.find('[component="chat/message/parent/content"]') - .translateHtml(message.content); - } if (!isSelf) { msgEl.find('[component="chat/message/body"]') .translateHtml(message.content); messages.onMessagesAddedToDom(components.get('chat/message', message.messageId)); } + + if (!isParentSelf && parentEl.length) { + parentEl.find('[component="chat/message/parent/content"]') + .translateHtml(message.content); + messages.onMessagesAddedToDom($(`[component="chat/message/parent"][data-parent-mid="${message.messageId}"]`)); + } } messages.delete = function (messageId, roomId) { From 8996804829307b01c06bd49b2531c7358cd037b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 10:41:16 -0400 Subject: [PATCH 251/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index b37802df00..4e60cd69ad 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.29", + "nodebb-theme-harmony": "1.1.30", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", "nodebb-theme-persona": "13.2.15", From 9349cb63cbcc7c77071a0d4c4b5cc3d1c9388687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 17:32:36 -0400 Subject: [PATCH 252/300] feat: #11881, limit room names --- install/data/defaults.json | 1 + .../language/en-GB/admin/settings/chat.json | 1 + public/language/en-GB/error.json | 2 +- public/src/client/chats.js | 53 +++++++++++-------- public/src/modules/chat.js | 15 ++++-- src/api/chats.js | 22 ++++---- src/messaging/index.js | 16 +++--- src/messaging/rooms.js | 28 ++++++---- src/views/admin/settings/chat.tpl | 5 ++ 9 files changed, 90 insertions(+), 53 deletions(-) diff --git a/install/data/defaults.json b/install/data/defaults.json index f5317337e3..12acc55fd6 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -64,6 +64,7 @@ "maximumAboutMeLength": 1000, "maximumUsersInChatRoom": 0, "maximumChatMessageLength": 1000, + "maximumChatRoomNameLength": 50, "maximumProfileImageSize": 256, "maximumCoverImageSize": 2048, "profileImageDimension": 200, diff --git a/public/language/en-GB/admin/settings/chat.json b/public/language/en-GB/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-GB/admin/settings/chat.json +++ b/public/language/en-GB/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index 06e49e4f12..a374787ea6 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -191,7 +191,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", diff --git a/public/src/client/chats.js b/public/src/client/chats.js index d92d27a532..c8743f9d80 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -396,29 +396,30 @@ define('forum/chats', [ }); }; - Chats.addRenameHandler = function (roomId, buttonEl, roomName) { - let modal; - - buttonEl.on('click', function () { - app.parseAndTranslate('modals/rename-room', { - name: roomName || ajaxify.data.roomName, - }, function (html) { - modal = bootbox.dialog({ - title: '[[modules:chat.rename-room]]', - message: html, - onEscape: true, - buttons: { - save: { - label: '[[global:save]]', - className: 'btn-primary', - callback: function () { - api.put(`/chats/${roomId}`, { - name: modal.find('#roomName').val(), - }).catch(alerts.error); - }, + Chats.addRenameHandler = function (roomId, buttonEl) { + buttonEl.on('click', async function () { + const { roomName } = await api.get(`/chats/${roomId}`); + const html = await app.parseAndTranslate('modals/rename-room', { + name: roomName, + }); + const modal = bootbox.dialog({ + title: '[[modules:chat.rename-room]]', + message: html, + onEscape: true, + buttons: { + save: { + label: '[[global:save]]', + className: 'btn-primary', + callback: function () { + api.put(`/chats/${roomId}`, { + name: modal.find('#roomName').val(), + }).then(() => { + modal.modal('hide'); + }).catch(alerts.error); + return false; }, }, - }); + }, }); }); }; @@ -586,7 +587,15 @@ define('forum/chats', [ if (roomEl.length) { const titleEl = roomEl.find('[component="chat/room/title"]'); ajaxify.data.roomName = data.newName; - titleEl.text(data.newName); + titleEl.translateText(data.newName ? data.newName : ajaxify.data.usernames); + } + const titleEl = $(`[component="chat/main-wrapper"][data-roomid="${data.roomId}"] [component="chat/header/title"]`); + if (titleEl.length) { + titleEl.html( + data.newName ? + ` ${data.newName}` : + ajaxify.data.chatWithMessage + ); } }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index a932943e0a..31f81927a0 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -232,9 +232,18 @@ define('chat', [ }; module.onRoomRename = function (data) { - const newTitle = $('
        ').html(data.newName).text(); const modal = module.getModal(data.roomId); - modal.find('[component="chat/room/name"]').text(newTitle); + const titleEl = modal.find('[component="chat/room/name"]'); + const icon = titleEl.attr('data-icon'); + if (titleEl.length) { + titleEl.html( + data.newName ? + ` ${data.newName}` : + data.chatWithMessage + ); + } + + const newTitle = $('
        ').html(data.newName).text(); taskbar.update('chat', modal.attr('data-uuid'), { title: newTitle, }); @@ -347,7 +356,7 @@ define('chat', [ }); Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), roomId); - Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]'), data.roomName); + Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]')); Chats.addLeaveHandler(roomId, chatModal.find('[data-action="leave"]')); Chats.addDeleteHandler(roomId, chatModal.find('[data-action="delete"]')); Chats.addSendHandlers(roomId, chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); diff --git a/src/api/chats.js b/src/api/chats.js index dc46ec522d..cf7bc6c7ee 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -103,17 +103,10 @@ chatsAPI.update = async (caller, data) => { } if (data.hasOwnProperty('name')) { - if (!data.name) { + if (!data.name && data.name !== '') { throw new Error('[[error:invalid-data]]'); } await messaging.renameRoom(caller.uid, data.roomId, data.name); - const ioRoom = require('../socket.io').in(`chat_room_${data.roomId}`); - if (ioRoom) { - ioRoom.emit('event:chats.roomRename', { - roomId: data.roomId, - newName: validator.escape(String(data.name)), - }); - } } const [roomData, isAdmin] = await Promise.all([ messaging.getRoomData(data.roomId), @@ -130,9 +123,20 @@ chatsAPI.update = async (caller, data) => { if (data.hasOwnProperty('notificationSetting') && isAdmin) { await db.setObjectField(`chat:room:${data.roomId}`, 'notificationSetting', data.notificationSetting); } - return messaging.loadRoom(caller.uid, { + const loadedRoom = await messaging.loadRoom(caller.uid, { roomId: data.roomId, }); + if (data.hasOwnProperty('name')) { + const ioRoom = require('../socket.io').in(`chat_room_${data.roomId}`); + if (ioRoom) { + ioRoom.emit('event:chats.roomRename', { + roomId: data.roomId, + newName: validator.escape(String(data.name)), + chatWithMessage: loadedRoom.chatWithMessage, + }); + } + } + return loadedRoom; }; chatsAPI.rename = async (caller, data) => { diff --git a/src/messaging/index.js b/src/messaging/index.js index 42cf331278..5199345720 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -213,8 +213,8 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { }); room.users = room.users.filter(user => user && parseInt(user.uid, 10)); room.lastUser = room.users[0]; - room.usernames = Messaging.generateUsernames(room.users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(room.users, uid, results.settings.userLang); + room.usernames = Messaging.generateUsernames(room, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room, uid, results.settings.userLang); } })); @@ -228,21 +228,21 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { }); }; -Messaging.generateUsernames = function (users, excludeUid) { - users = users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); +Messaging.generateUsernames = function (room, excludeUid) { + const users = room.users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); const usernames = users.map(u => u.username); if (users.length > 3) { return translator.compile( 'modules:chat.usernames-and-x-others', usernames.slice(0, 2).join(', '), - usernames.length - 2 + room.userCount - 2 ); } return usernames.join(', '); }; -Messaging.generateChatWithMessage = async function (users, callerUid, userLang) { - users = users.filter(u => u && parseInt(u.uid, 10) !== callerUid); +Messaging.generateChatWithMessage = async function (room, callerUid, userLang) { + const users = room.users.filter(u => u && parseInt(u.uid, 10) !== callerUid); const usernames = users.map(u => `${u.username}`); let compiled = ''; if (!users.length) { @@ -252,7 +252,7 @@ Messaging.generateChatWithMessage = async function (users, callerUid, userLang) compiled = translator.compile( 'modules:chat.chat-with-usernames-and-x-others', usernames.slice(0, 2).join(', '), - usernames.length - 2 + room.userCount - 2 ); } else { compiled = translator.compile( diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 51c76c6ce9..5428489f42 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -78,6 +78,10 @@ module.exports = function (Messaging) { if (Array.isArray(data)) { // old usage second param used to be toUids data = { uids: data }; } + if (data.hasOwnProperty('roomName')) { + checkRoomName(data.roomName); + } + const now = Date.now(); const roomId = await db.incrObjectField('global', 'nextChatRoomId'); const room = { @@ -87,7 +91,7 @@ module.exports = function (Messaging) { }; if (data.hasOwnProperty('roomName') && data.roomName) { - room.roomName = String(data.roomName); + room.roomName = String(data.roomName).trim(); } if (Array.isArray(data.groups) && data.groups.length) { room.groups = JSON.stringify(data.groups); @@ -397,13 +401,8 @@ module.exports = function (Messaging) { }; Messaging.renameRoom = async function (uid, roomId, newName) { - if (!newName) { - throw new Error('[[error:invalid-data]]'); - } - newName = newName.trim(); - if (newName.length > 75) { - throw new Error('[[error:chat-room-name-too-long]]'); - } + newName = String(newName).trim(); + checkRoomName(newName); const payload = await plugins.hooks.fire('filter:chat.renameRoom', { uid: uid, @@ -424,6 +423,15 @@ module.exports = function (Messaging) { }); }; + function checkRoomName(roomName) { + if (!roomName && roomName !== '') { + throw new Error('[[error:invalid-room-name]]'); + } + if (roomName.length > meta.config.maximumChatRoomNameLength) { + throw new Error(`[[error:chat-room-name-too-long, ${meta.config.maximumChatRoomNameLength}]]`); + } + } + Messaging.canReply = async (roomId, uid) => { const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid); const data = await plugins.hooks.fire('filter:messaging.canReply', { uid: uid, roomId: roomId, inRoom: inRoom, canReply: inRoom }); @@ -517,8 +525,8 @@ module.exports = function (Messaging) { room.canReply = canReply; room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : users.length > 2; room.icon = Messaging.getRoomIcon(room); - room.usernames = Messaging.generateUsernames(users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(users, uid, settings.userLang); + room.usernames = Messaging.generateUsernames(room, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room, uid, settings.userLang); room.maximumUsersInChatRoom = meta.config.maximumUsersInChatRoom; room.maximumChatMessageLength = meta.config.maximumChatMessageLength; room.showUserInput = !room.maximumUsersInChatRoom || room.maximumUsersInChatRoom > 2; diff --git a/src/views/admin/settings/chat.tpl b/src/views/admin/settings/chat.tpl index 59a32445bd..62fbd3c199 100644 --- a/src/views/admin/settings/chat.tpl +++ b/src/views/admin/settings/chat.tpl @@ -31,6 +31,11 @@
        +
        + + +
        +
        From e27d174311a30fdbae458787f7f6abb0a6538fb9 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 6 Aug 2023 21:33:17 +0000 Subject: [PATCH 253/300] chore(i18n): fallback strings for new resources: nodebb.admin-settings-chat, nodebb.error --- public/language/ar/admin/settings/chat.json | 1 + public/language/ar/error.json | 2 +- public/language/bg/admin/settings/chat.json | 1 + public/language/bg/error.json | 2 +- public/language/bn/admin/settings/chat.json | 1 + public/language/bn/error.json | 2 +- public/language/cs/admin/settings/chat.json | 1 + public/language/cs/error.json | 2 +- public/language/da/admin/settings/chat.json | 1 + public/language/da/error.json | 2 +- public/language/de/admin/settings/chat.json | 1 + public/language/de/error.json | 2 +- public/language/el/admin/settings/chat.json | 1 + public/language/el/error.json | 2 +- public/language/en-US/admin/settings/chat.json | 1 + public/language/en-US/error.json | 2 +- public/language/en-x-pirate/admin/settings/chat.json | 1 + public/language/en-x-pirate/error.json | 2 +- public/language/es/admin/settings/chat.json | 1 + public/language/es/error.json | 2 +- public/language/et/admin/settings/chat.json | 1 + public/language/et/error.json | 2 +- public/language/fa-IR/admin/settings/chat.json | 1 + public/language/fa-IR/error.json | 2 +- public/language/fi/admin/settings/chat.json | 1 + public/language/fi/error.json | 2 +- public/language/fr/admin/settings/chat.json | 1 + public/language/fr/error.json | 2 +- public/language/gl/admin/settings/chat.json | 1 + public/language/gl/error.json | 2 +- public/language/he/admin/settings/chat.json | 1 + public/language/he/error.json | 2 +- public/language/hr/admin/settings/chat.json | 1 + public/language/hr/error.json | 2 +- public/language/hu/admin/settings/chat.json | 1 + public/language/hu/error.json | 2 +- public/language/hy/admin/settings/chat.json | 1 + public/language/hy/error.json | 2 +- public/language/id/admin/settings/chat.json | 1 + public/language/id/error.json | 2 +- public/language/it/admin/settings/chat.json | 1 + public/language/it/error.json | 2 +- public/language/ja/admin/settings/chat.json | 1 + public/language/ja/error.json | 2 +- public/language/ko/admin/settings/chat.json | 1 + public/language/ko/error.json | 2 +- public/language/lt/admin/settings/chat.json | 1 + public/language/lt/error.json | 2 +- public/language/lv/admin/settings/chat.json | 1 + public/language/lv/error.json | 2 +- public/language/ms/admin/settings/chat.json | 1 + public/language/ms/error.json | 2 +- public/language/nb/admin/settings/chat.json | 1 + public/language/nb/error.json | 2 +- public/language/nl/admin/settings/chat.json | 1 + public/language/nl/error.json | 2 +- public/language/pl/admin/settings/chat.json | 1 + public/language/pl/error.json | 2 +- public/language/pt-BR/admin/settings/chat.json | 1 + public/language/pt-BR/error.json | 2 +- public/language/pt-PT/admin/settings/chat.json | 1 + public/language/pt-PT/error.json | 2 +- public/language/ro/admin/settings/chat.json | 1 + public/language/ro/error.json | 2 +- public/language/ru/admin/settings/chat.json | 1 + public/language/ru/error.json | 2 +- public/language/rw/admin/settings/chat.json | 1 + public/language/rw/error.json | 2 +- public/language/sc/admin/settings/chat.json | 1 + public/language/sc/error.json | 2 +- public/language/sk/admin/settings/chat.json | 1 + public/language/sk/error.json | 2 +- public/language/sl/admin/settings/chat.json | 1 + public/language/sl/error.json | 2 +- public/language/sq-AL/admin/settings/chat.json | 1 + public/language/sq-AL/error.json | 2 +- public/language/sr/admin/settings/chat.json | 1 + public/language/sr/error.json | 2 +- public/language/sv/admin/settings/chat.json | 1 + public/language/sv/error.json | 2 +- public/language/th/admin/settings/chat.json | 1 + public/language/th/error.json | 2 +- public/language/tr/admin/settings/chat.json | 1 + public/language/tr/error.json | 2 +- public/language/uk/admin/settings/chat.json | 1 + public/language/uk/error.json | 2 +- public/language/vi/admin/settings/chat.json | 1 + public/language/vi/error.json | 2 +- public/language/zh-CN/admin/settings/chat.json | 1 + public/language/zh-CN/error.json | 2 +- public/language/zh-TW/admin/settings/chat.json | 1 + public/language/zh-TW/error.json | 2 +- 92 files changed, 92 insertions(+), 46 deletions(-) diff --git a/public/language/ar/admin/settings/chat.json b/public/language/ar/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/ar/admin/settings/chat.json +++ b/public/language/ar/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ar/error.json b/public/language/ar/error.json index ca231a9831..f5fee4def9 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "لقد شاركت بالتصويت ، ألا تذكر؟", "reputation-system-disabled": "نظام السمعة معطل", "downvoting-disabled": "التصويتات السلبية معطلة", diff --git a/public/language/bg/admin/settings/chat.json b/public/language/bg/admin/settings/chat.json index 6f4e7627e9..b9f00646c8 100644 --- a/public/language/bg/admin/settings/chat.json +++ b/public/language/bg/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Изключване на редактирането и изтриването на съобщения в разговорите", "disable-editing-help": "Това ограничение не засяга администраторите и глобалните модератори", "max-length": "Максимална дължина на съобщенията в разговорите", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Максимален брой потребители в стая за разговор", "delay": "Време между съобщенията в разговорите (в милисекунди)", "notification-delay": "Забавяне преди известяване за съобщения в разговорите. (0 – без забавяне)", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index 4066f46ba3..94296820d4 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Стаята за разговори не съществува.", "cant-add-users-to-chat-room": "Към стаята за разговори не могат да бъдат добавяни потребители.", "cant-remove-users-from-chat-room": "От стаята за разговори не могат да бъдат премахвани потребители.", - "chat-room-name-too-long": "Името на стаята за разговори е твърде дълго.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Вече сте дали глас за тази публикация.", "reputation-system-disabled": "Системата за репутация е изключена.", "downvoting-disabled": "Отрицателното гласуване е изключено", diff --git a/public/language/bn/admin/settings/chat.json b/public/language/bn/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/bn/admin/settings/chat.json +++ b/public/language/bn/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/bn/error.json b/public/language/bn/error.json index 4cafce66f9..44f4bdd2b2 100644 --- a/public/language/bn/error.json +++ b/public/language/bn/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "সম্মাননা ব্যাবস্থা নিস্ক্রীয় রাখা হয়েছে", "downvoting-disabled": "ঋণাত্মক ভোট নিস্ক্রীয় রাখা হয়েছে।", diff --git a/public/language/cs/admin/settings/chat.json b/public/language/cs/admin/settings/chat.json index 7421f4bd3a..d2873a58db 100644 --- a/public/language/cs/admin/settings/chat.json +++ b/public/language/cs/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Zakázat upravení/odstranění konverzační zprávy", "disable-editing-help": "Správci a globální moderátoři jsou vyjmuti z tohoto omezení", "max-length": "Maximální délka konverzační zprávy", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximální počet uživatelů v konverzační místnosti", "delay": "Čas mezi konverzačními zprávami v milisekundách", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 19ad7ca204..e0fefa01b8 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Již jste v tomto příspěvku hlasoval.", "reputation-system-disabled": "Systém reputací je zakázán.", "downvoting-disabled": "Systém nesouhlasu je zakázán", diff --git a/public/language/da/admin/settings/chat.json b/public/language/da/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/da/admin/settings/chat.json +++ b/public/language/da/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/da/error.json b/public/language/da/error.json index 79eae9020c..a78dffdf52 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Vurderingssystem er slået fra.", "downvoting-disabled": "Nedvurdering er slået fra", diff --git a/public/language/de/admin/settings/chat.json b/public/language/de/admin/settings/chat.json index d97665c221..17ae89bc7a 100644 --- a/public/language/de/admin/settings/chat.json +++ b/public/language/de/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Chatnachrichtenbearbeitung/löschung deaktivieren", "disable-editing-help": "Administratoren und globale Moderatoren sind von dieser Einschränkung ausgenommen", "max-length": "Maximale Länge von Chatnachrichten", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximale Anzahl von Benutzern in Chatrooms", "delay": "Zeit zwischen Chatnachrichten in Millisekunden", "notification-delay": "Benachrichtigungsverzögerung für Chatnachrichten. (0 für keine Verzögerung)", diff --git a/public/language/de/error.json b/public/language/de/error.json index 6a59ebae22..010103fa7b 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Der Chatroom existiert nicht.", "cant-add-users-to-chat-room": "Kann Benutzer nicht zu Chatroom hinzufügen", "cant-remove-users-from-chat-room": "Kann Benutzer nicht aus Chatroom entfernen.", - "chat-room-name-too-long": "Name des Chatrooms zu lang.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Du hast diesen Beitrag bereits bewertet.", "reputation-system-disabled": "Das Reputationssystem ist deaktiviert.", "downvoting-disabled": "Downvotes sind deaktiviert.", diff --git a/public/language/el/admin/settings/chat.json b/public/language/el/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/el/admin/settings/chat.json +++ b/public/language/el/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/el/error.json b/public/language/el/error.json index 6ec0685995..f329ff5f2e 100644 --- a/public/language/el/error.json +++ b/public/language/el/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Το σύστημα φήμης έχει απενεργοποιηθεί.", "downvoting-disabled": "Η καταψήφιση έχει απενεργοποιηθεί", diff --git a/public/language/en-US/admin/settings/chat.json b/public/language/en-US/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-US/admin/settings/chat.json +++ b/public/language/en-US/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-US/error.json b/public/language/en-US/error.json index 680629452b..9ec0963641 100644 --- a/public/language/en-US/error.json +++ b/public/language/en-US/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", diff --git a/public/language/en-x-pirate/admin/settings/chat.json b/public/language/en-x-pirate/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-x-pirate/admin/settings/chat.json +++ b/public/language/en-x-pirate/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-x-pirate/error.json b/public/language/en-x-pirate/error.json index 680629452b..9ec0963641 100644 --- a/public/language/en-x-pirate/error.json +++ b/public/language/en-x-pirate/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", diff --git a/public/language/es/admin/settings/chat.json b/public/language/es/admin/settings/chat.json index dbdf26b7c5..7afc3f0342 100644 --- a/public/language/es/admin/settings/chat.json +++ b/public/language/es/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Deshabilitar edición y borrado de mensajes de chat", "disable-editing-help": "Los administradores y los moderadores globales están exentos de esta restricción", "max-length": "Maxima longitud de mensajes de chat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Máximo numero de usuarios en las salas de chat", "delay": "Tiempo entre envío de mensajes de chat en milisegundos", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/es/error.json b/public/language/es/error.json index f50a0cad94..d5313d6d70 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Ya has votado a este mensaje.", "reputation-system-disabled": "El sistema de reputación está deshabilitado.", "downvoting-disabled": "La votación negativa está deshabilitada.", diff --git a/public/language/et/admin/settings/chat.json b/public/language/et/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/et/admin/settings/chat.json +++ b/public/language/et/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/et/error.json b/public/language/et/error.json index 6c3d5d49d1..11a4fc8249 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Sa oled juba hääletanud sellel postitusel.", "reputation-system-disabled": "Reputatsiooni süsteem ei ole aktiveeritud", "downvoting-disabled": "Negatiivsete häälte andmine ei ole võimaldatud", diff --git a/public/language/fa-IR/admin/settings/chat.json b/public/language/fa-IR/admin/settings/chat.json index 0d10f1cb68..a5544ca116 100644 --- a/public/language/fa-IR/admin/settings/chat.json +++ b/public/language/fa-IR/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "بیشترین طول پیام‌های چت ", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "بیشترین تعداد کاربران در چت‌روم ", "delay": "زمان بین پیام های چت به میلی ثانیه", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/fa-IR/error.json b/public/language/fa-IR/error.json index 35a8426964..a0a901833f 100644 --- a/public/language/fa-IR/error.json +++ b/public/language/fa-IR/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "چت روم وجود ندارد", "cant-add-users-to-chat-room": "نمی‌توانید کاربری به چت‌روم اضافه کنید ", "cant-remove-users-from-chat-room": "نمی‌توانید کاربران را از چت‌روم حذف کنید ", - "chat-room-name-too-long": "نام چت‌روم خیلی طولانی است ", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "شما قبلا به این پست رای داده اید.", "reputation-system-disabled": "سیستم اعتبار غیر فعال شده است", "downvoting-disabled": "رأی منفی غیر فعال شده است", diff --git a/public/language/fi/admin/settings/chat.json b/public/language/fi/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/fi/admin/settings/chat.json +++ b/public/language/fi/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 414f249c85..e701f5d6d1 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", diff --git a/public/language/fr/admin/settings/chat.json b/public/language/fr/admin/settings/chat.json index 7efc130f0e..dc25273c0e 100644 --- a/public/language/fr/admin/settings/chat.json +++ b/public/language/fr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Désactiver l'édition/la suppression des messages des discussions", "disable-editing-help": "Les administrateurs et modérateurs globaux sont dispensés de cette restriction", "max-length": "Longueur maximales des messages de discussion", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Nombre maximum d'utilisateurs dans une même discussion", "delay": "Temps entre chaque message de discussion (en millisecondes)", "notification-delay": "Délai de notification pour les messages de chat. (0 pour aucun délai)", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index 5386a887f7..e42b5182bf 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Le salon de discussion n'existe pas.", "cant-add-users-to-chat-room": "Impossible d'ajouter des utilisateurs au salon.", "cant-remove-users-from-chat-room": "Impossible de supprimer des utilisateurs du salon.", - "chat-room-name-too-long": "Nom de salon trop long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Vous avez déjà voté pour ce message.", "reputation-system-disabled": "Le système de réputation est désactivé", "downvoting-disabled": "Les votes négatifs ne sont pas autorisés", diff --git a/public/language/gl/admin/settings/chat.json b/public/language/gl/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/gl/admin/settings/chat.json +++ b/public/language/gl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/gl/error.json b/public/language/gl/error.json index 55fb663ba4..aae9e55d49 100644 --- a/public/language/gl/error.json +++ b/public/language/gl/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Xa votache esta mensaxe.", "reputation-system-disabled": "O sistema de reputación está deshabilitado", "downvoting-disabled": "Os votos negativos están deshabilitados", diff --git a/public/language/he/admin/settings/chat.json b/public/language/he/admin/settings/chat.json index 389ff33dca..c7a3bdf478 100644 --- a/public/language/he/admin/settings/chat.json +++ b/public/language/he/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "השבת עריכה/מחיקה של הודעות צ'אט", "disable-editing-help": "מנהלי מערכת ומנחים גלובליים פטורים מהגבלה זו", "max-length": "אורך מקסימלי של הודעת צ'אט", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "מספר המשתמשים המרבי בחדרי צ'אט", "delay": "זמן המתנה בין הודעות צ'אט - באלפיות שניה", "notification-delay": "עיכוב התראות להודעות צ'אט. (0 ללא עיכוב)", diff --git a/public/language/he/error.json b/public/language/he/error.json index 33c61119ab..c959a0e711 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "חדר צ'אט אינו קיים.", "cant-add-users-to-chat-room": "לא ניתן להוסיף משתמשים לחדר הצ'אט.", "cant-remove-users-from-chat-room": "לא ניתן להסיר משתמשים מחדר הצ'אט.", - "chat-room-name-too-long": "שם חדר הצ'אט ארוך מדי.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "הצבעתם כבר בנושא זה.", "reputation-system-disabled": "מערכת המוניטין לא פעילה.", "downvoting-disabled": "היכולת להצביע נגד מושבתת", diff --git a/public/language/hr/admin/settings/chat.json b/public/language/hr/admin/settings/chat.json index 92c8248d74..225b829618 100644 --- a/public/language/hr/admin/settings/chat.json +++ b/public/language/hr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Onemogući uređivanje/brisanje poruka razgovora", "disable-editing-help": "Administratori i moderatori su izuzeti od ovih restrikcija", "max-length": "Maksimalna dužina poruka u razgovoru", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maksimalan broj korisnika u sobama za razgovor", "delay": "Vrijeme između poruka razgovora u milisekundama", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/hr/error.json b/public/language/hr/error.json index e4e616ba7e..77ca94bc2f 100644 --- a/public/language/hr/error.json +++ b/public/language/hr/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Već ste glasali za ovu objavu", "reputation-system-disabled": "Sistem reputacije onemogućen.", "downvoting-disabled": "Oduzimanje glasova je onemogućeno", diff --git a/public/language/hu/admin/settings/chat.json b/public/language/hu/admin/settings/chat.json index 7565f0dd5a..445944237c 100644 --- a/public/language/hu/admin/settings/chat.json +++ b/public/language/hu/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Csevegési üzenetek szerkesztésének/törlésének letiltása", "disable-editing-help": "Az adminisztrátorok és globális moderátorok kivételnek számítanak ezen korlátozás alól", "max-length": "Csevegési üzenetek maximális hossza", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "A csevegési szobákban lévő felhasználók maximális száma", "delay": "Csevegési üzenetek közötti idő ezredmásodpercben", "notification-delay": "Értesítési késleltetés csevegési üzenetekhez. (0: nincs késleltetés)", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index a8c9049ed3..c0c0fe9794 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Csevegő szoba nem létezik.", "cant-add-users-to-chat-room": "Nem lehet felhasználókat hozzáadni a csevegőszobához.", "cant-remove-users-from-chat-room": "A felhasználókat nem lehet eltávolítani a csevegőszobából.", - "chat-room-name-too-long": "A csevegőszoba neve túl hosszú.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Már szavaztál erre a hozzászólásra.", "reputation-system-disabled": "Hírnév funkció kikapcsolva.", "downvoting-disabled": "Leszavazás funkció kikapcsolva", diff --git a/public/language/hy/admin/settings/chat.json b/public/language/hy/admin/settings/chat.json index 517f702a81..67178e5984 100644 --- a/public/language/hy/admin/settings/chat.json +++ b/public/language/hy/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Անջատել զրույցի հաղորդագրությունների խմբագրումը/ջնջումը", "disable-editing-help": "Ադմինիստրատորները և ամընդհանուր մոդերատորները ազատված են այս սահմանափակումից", "max-length": "Զրույցի հաղորդագրությունների առավելագույն երկարությունը", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Զրուցարաններում օգտատերերի առավելագույն քանակը", "delay": "Զրույցի հաղորդագրությունների միջև ընկած ժամանակը միլիվայրկյաններով", "notification-delay": "Զրույցի հաղորդագրությունների ծանուցման հետաձգում: (0 առանց ուշացման)", diff --git a/public/language/hy/error.json b/public/language/hy/error.json index fd3b015fc3..e0a48e0a41 100644 --- a/public/language/hy/error.json +++ b/public/language/hy/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Այս զրուցարանը գոյություն չունի:", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Դուք արդեն քվեարկել եք այս գրառման օգտին:", "reputation-system-disabled": "Վարկանիշի համակարգը անջատված է:", "downvoting-disabled": "Դեմ քվեարկությունն անջատված է", diff --git a/public/language/id/admin/settings/chat.json b/public/language/id/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/id/admin/settings/chat.json +++ b/public/language/id/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/id/error.json b/public/language/id/error.json index f55f9f450f..db141c8765 100644 --- a/public/language/id/error.json +++ b/public/language/id/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Sistem reputasi ditiadakan.", "downvoting-disabled": "Downvoting ditiadakan", diff --git a/public/language/it/admin/settings/chat.json b/public/language/it/admin/settings/chat.json index 0faf77ab75..d4ab3ac1d2 100644 --- a/public/language/it/admin/settings/chat.json +++ b/public/language/it/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disabilita modifica/cancellazione messaggio chat", "disable-editing-help": "Gli amministratori e i moderatori globali sono esenti da questa restrizione.", "max-length": "Lunghezza massima dei messaggi della chat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Numero massimo di utenti nelle stanza chat", "delay": "Tempo tra i messaggi della chat in millisecondi", "notification-delay": "Ritardo di notifica per i messaggi di chat. (0 per nessun ritardo)", diff --git a/public/language/it/error.json b/public/language/it/error.json index 7808e7d256..bfb77f7570 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "La stanza chat non esiste.", "cant-add-users-to-chat-room": "Impossibile aggiungere utenti alla stanza chat.", "cant-remove-users-from-chat-room": "Impossibile rimuovere gli utenti dalla stanza chat.", - "chat-room-name-too-long": "Nome della stanza chat troppo lungo.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Hai già votato per questo post", "reputation-system-disabled": "Il sistema di reputazione è disabilitato.", "downvoting-disabled": "Votata negativamente è disabilitato", diff --git a/public/language/ja/admin/settings/chat.json b/public/language/ja/admin/settings/chat.json index a0551c713f..fb7bb73e23 100644 --- a/public/language/ja/admin/settings/chat.json +++ b/public/language/ja/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "チャットメッセージの編集/削除を無効にする", "disable-editing-help": "管理者およびグローバルモデレーターはこの制限を免除されます", "max-length": "チャットメッセージの最大の長さ", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "チャットルームの最大ユーザー数", "delay": "ミリ秒単位のチャットメッセージ間の時間", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index 9fba1c6fa0..6a721ff75e 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "あなたはすでにこの投稿を評価しました。", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", diff --git a/public/language/ko/admin/settings/chat.json b/public/language/ko/admin/settings/chat.json index 979cd5c488..169e6381a5 100644 --- a/public/language/ko/admin/settings/chat.json +++ b/public/language/ko/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "채팅 메시지 수정/삭제 비활성화", "disable-editing-help": "관리자와 조정자는 제한되지 않습니다.", "max-length": "채팅 메시지의 최대 길이", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "채팅방 최대 인원", "delay": "채팅 메시지 발송 지연 (단위: 1/1000초)", "notification-delay": "채팅 메시지 알림 지연 (0으로 놔둘 경우 지연 없음)", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index d5c025055c..13e9594b15 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "채팅이 존재하지 않습니다.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "이미 이 포스트에 투표하셨습니다.", "reputation-system-disabled": "인지도 시스템이 비활성화되어있습니다.", "downvoting-disabled": "비추천 기능이 비활성 상태입니다.", diff --git a/public/language/lt/admin/settings/chat.json b/public/language/lt/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/lt/admin/settings/chat.json +++ b/public/language/lt/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 07ead84ed3..53f5e2743f 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Jūs jau balsavote už šį pranešimą.", "reputation-system-disabled": "Reputacijos sistema išjungta.", "downvoting-disabled": "Downvoting yra išjungtas", diff --git a/public/language/lv/admin/settings/chat.json b/public/language/lv/admin/settings/chat.json index 9a6a3540f1..7b3e7969ae 100644 --- a/public/language/lv/admin/settings/chat.json +++ b/public/language/lv/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Atspējot sarunu rediģēšanu/izdzēšanu", "disable-editing-help": "Administratori un globālie moderatori ir atbrīvoti no šī ierobežojuma", "max-length": "Sarunu lielākais garums", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maksimālais lietotāju skaits tērzētavā", "delay": "Laiks starp sarunām milisekundēs", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/lv/error.json b/public/language/lv/error.json index 391d1c2e4c..cb0695ec6f 100644 --- a/public/language/lv/error.json +++ b/public/language/lv/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Tu jau balsoji par šo rakstu.", "reputation-system-disabled": "Ranga punktu sistēma ir atspējota.", "downvoting-disabled": "Balsošana \"pret\" ir atspējota", diff --git a/public/language/ms/admin/settings/chat.json b/public/language/ms/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/ms/admin/settings/chat.json +++ b/public/language/ms/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 7cc2474d25..ae3c3c686f 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Sistem reputasi dilumpuhkan.", "downvoting-disabled": "Undi turun dilumpuhkan", diff --git a/public/language/nb/admin/settings/chat.json b/public/language/nb/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/nb/admin/settings/chat.json +++ b/public/language/nb/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index 79973a3bee..304381b1b2 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Dette chatterommet finnes ikke.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Du har allerede stemt på dette innlegget", "reputation-system-disabled": "Omdømmesystemet er deaktivert.", "downvoting-disabled": "Nedstemming er deaktivert", diff --git a/public/language/nl/admin/settings/chat.json b/public/language/nl/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/nl/admin/settings/chat.json +++ b/public/language/nl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 6a21fcb691..19ec2babfc 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Je hebt al gestemd voor deze post.", "reputation-system-disabled": "Reputatie systeem is uitgeschakeld.", "downvoting-disabled": "Negatief stemmen is uitgeschakeld", diff --git a/public/language/pl/admin/settings/chat.json b/public/language/pl/admin/settings/chat.json index 7b0b5f2be6..a1223eca38 100644 --- a/public/language/pl/admin/settings/chat.json +++ b/public/language/pl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Wyłącz edycję/usuwanie wiadomości czat", "disable-editing-help": "Ograniczenie to nie dotyczy administratorów i moderatorów globalnych", "max-length": "Maksymalna długość wiadomości czat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maksymalna liczba użytkowników w pokojach czatu", "delay": "Czas pomiędzy wiadomościami czat (w milisekundach)", "notification-delay": "Opóźnienie powiadomienia o wiadomościach na czacie. (0 bez opóźnienia)", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index fd28f9721f..d817abed20 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Już zagłosowałeś na ten post", "reputation-system-disabled": "System reputacji jest wyłączony.", "downvoting-disabled": "Negatywna ocena postów jest wyłączona", diff --git a/public/language/pt-BR/admin/settings/chat.json b/public/language/pt-BR/admin/settings/chat.json index 710c1e29c4..29029d74ea 100644 --- a/public/language/pt-BR/admin/settings/chat.json +++ b/public/language/pt-BR/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Desabilitar editar/apagar mensagem ", "disable-editing-help": "Administradores e moderadores globais não sofrem esta restrição", "max-length": "Tamanho máximo das mensagens de chat", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Número máximo de usuários nas salas de chat", "delay": "Tempo entre mensagens de chat em milisegundos", "notification-delay": "Tempo de espera para notificação de mensagens de bate-papo. (0 para não esperar)", diff --git a/public/language/pt-BR/error.json b/public/language/pt-BR/error.json index c4ea6f7e56..9fe4d4e34f 100644 --- a/public/language/pt-BR/error.json +++ b/public/language/pt-BR/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "A sala de chat não existe.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Você já votou neste post.", "reputation-system-disabled": "O sistema de reputação está desabilitado.", "downvoting-disabled": "Negativação está desabilitada", diff --git a/public/language/pt-PT/admin/settings/chat.json b/public/language/pt-PT/admin/settings/chat.json index b68f84b072..e49504694e 100644 --- a/public/language/pt-PT/admin/settings/chat.json +++ b/public/language/pt-PT/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Desativar edtitar/apagar mensagens das conversas", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Comprimento máximo das mensagens nas conversas", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Número máximo de utilizadores nas salas de conversa", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/pt-PT/error.json b/public/language/pt-PT/error.json index 2cd0fc7888..7fb7c37596 100644 --- a/public/language/pt-PT/error.json +++ b/public/language/pt-PT/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Já votaste nesta publicação.", "reputation-system-disabled": "O sistema de reputação está desativado.", "downvoting-disabled": "Os votos negativos estão desativados", diff --git a/public/language/ro/admin/settings/chat.json b/public/language/ro/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/ro/admin/settings/chat.json +++ b/public/language/ro/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index f29ad138f0..10ad1827b2 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Sistemul de reputație este dezactivat.", "downvoting-disabled": "Votarea negativă este dezactivată", diff --git a/public/language/ru/admin/settings/chat.json b/public/language/ru/admin/settings/chat.json index d34673dfcc..5e9f017bb3 100644 --- a/public/language/ru/admin/settings/chat.json +++ b/public/language/ru/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Отключить редактирование и удаление сообщений чата", "disable-editing-help": "Администраторы и общие модераторы освобождены от этого ограничения.", "max-length": "Максимальная длина сообщений в чате", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Максимальное кол-во пользователей в чат-комнатах", "delay": "Пауза между сообщениями (в миллисекундах)", "notification-delay": "Задержка уведомления для сообщений чата. (0 без задержки)", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index da63e6b41c..f21a9bcf0a 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Комната чата не существует.", "cant-add-users-to-chat-room": "Нельзя добавить пользователей в комнату.", "cant-remove-users-from-chat-room": "Нельзя удалять пользователей из комнаты.", - "chat-room-name-too-long": "Название чат комнаты слишком длинное, пожалуйста, сократите его.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Вы уже проголосовали за это сообщение.", "reputation-system-disabled": "Система репутации отключена.", "downvoting-disabled": "Понижение рейтинга отключено", diff --git a/public/language/rw/admin/settings/chat.json b/public/language/rw/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/rw/admin/settings/chat.json +++ b/public/language/rw/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/rw/error.json b/public/language/rw/error.json index 872672220a..c71287e9e8 100644 --- a/public/language/rw/error.json +++ b/public/language/rw/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Ibijyanye n'itangwa ry'amanota ntibyemerewe. ", "downvoting-disabled": "Kwambura amanota ntibyemerewe", diff --git a/public/language/sc/admin/settings/chat.json b/public/language/sc/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sc/admin/settings/chat.json +++ b/public/language/sc/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index 680629452b..9ec0963641 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", "downvoting-disabled": "Downvoting is disabled", diff --git a/public/language/sk/admin/settings/chat.json b/public/language/sk/admin/settings/chat.json index d6ccdb4f2d..4ba4b96ed5 100644 --- a/public/language/sk/admin/settings/chat.json +++ b/public/language/sk/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Zakázať upravenie/odstránenie konverzačnej správy", "disable-editing-help": "Správcovia a globálny moderátori sú vyňatí z tohto obmedzenia", "max-length": "Maximálna dĺžka konverzačnej správy", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximálny počet používateľov v konverzačnej miestnosti", "delay": "Čas medzi konverzačnými správami v milisekundách", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index a105272f4f..647f3d03d2 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Za tento príspevok ste už hlasovali.", "reputation-system-disabled": "Systém reputácie je zablokovaný.", "downvoting-disabled": "Hlasovanie proti je zablokované", diff --git a/public/language/sl/admin/settings/chat.json b/public/language/sl/admin/settings/chat.json index 95d7342274..1cf30fe6bd 100644 --- a/public/language/sl/admin/settings/chat.json +++ b/public/language/sl/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Onemogoči urejanje/brisanje sporočila klepeta", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Največja dolžina sporočila klepeta", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sl/error.json b/public/language/sl/error.json index 3abaaafbb7..8841ddfcae 100644 --- a/public/language/sl/error.json +++ b/public/language/sl/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Za to objavo ste že glasovali.", "reputation-system-disabled": "Sistem za ugled je onemogočen.", "downvoting-disabled": "Negativno glasovanje je onemogočeno.", diff --git a/public/language/sq-AL/admin/settings/chat.json b/public/language/sq-AL/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sq-AL/admin/settings/chat.json +++ b/public/language/sq-AL/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sq-AL/error.json b/public/language/sq-AL/error.json index f71bb0d605..757a28b5a1 100644 --- a/public/language/sq-AL/error.json +++ b/public/language/sq-AL/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Kjo dhomë bisede nuk ekziston.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Ju keni votuar tashmë për këtë postim.", "reputation-system-disabled": "Sistemi i reputacionit është i çaktivizuar.", "downvoting-disabled": "Votimi kundër është i çaktivizuar", diff --git a/public/language/sr/admin/settings/chat.json b/public/language/sr/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sr/admin/settings/chat.json +++ b/public/language/sr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index 4d50051750..6e39994dec 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Соба за ћаскање не постоји.", "cant-add-users-to-chat-room": "Не могу се додати корисници у собу за ћаскање.", "cant-remove-users-from-chat-room": "Не могу се уклонити корисници из собе за ћаскање.", - "chat-room-name-too-long": "Име собе за ћаскање је предугачко.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Већ сте гласали за ову поруку.", "reputation-system-disabled": "Угледи су онемогућени.", "downvoting-disabled": "Негативно гласање је онемогућено", diff --git a/public/language/sv/admin/settings/chat.json b/public/language/sv/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/sv/admin/settings/chat.json +++ b/public/language/sv/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index 39ece78129..713e3c1c3b 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Du har redan röstat på det här inlägget.", "reputation-system-disabled": "Ryktessystemet är inaktiverat.", "downvoting-disabled": "Nedröstning är inaktiverat", diff --git a/public/language/th/admin/settings/chat.json b/public/language/th/admin/settings/chat.json index e8f7c02f6a..21e4c4c0a1 100644 --- a/public/language/th/admin/settings/chat.json +++ b/public/language/th/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "ปิดการแก้ไข และการลบแชท", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "จำนวนอักขระมากที่มากที่สุดต่อแชท", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "จำนวนผู้ใช้ในห้องแชทมากที่สุด", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/th/error.json b/public/language/th/error.json index ba1510444e..7e396d380f 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "คุณได้โหวตโพสต์นี้แล้ว", "reputation-system-disabled": "ระบบชื่อเสียงถูกปิดใช้งาน", "downvoting-disabled": "\"การโหวตลง\" ถูกปิดใช้งาน", diff --git a/public/language/tr/admin/settings/chat.json b/public/language/tr/admin/settings/chat.json index ac06420c4d..09719c318a 100644 --- a/public/language/tr/admin/settings/chat.json +++ b/public/language/tr/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Sohbet mesajlarını düzenlemeyi/silmeyi kapat", "disable-editing-help": "Yöneticiler ve global moderatörler bu kısıtlamadan muaftır", "max-length": "Maksimum sohbet mesajı uzunluğu", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Sohbet odalarındaki maksimum kullanıcı sayısı", "delay": "Sohbet mesajları arasındaki süre (milisaniye)", "notification-delay": "Sohbet mesajları için bildirim gecikme süresi (gecikme olmaması için 0 yazın)", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index e1c5483f21..761441ed6b 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Sohbet Odası Mevcut Değil", "cant-add-users-to-chat-room": "Kullanıcıları sohbet odasına ekleyemezsiniz!", "cant-remove-users-from-chat-room": "Kullanıcıları sohbet odasından çıkaramazsınız!", - "chat-room-name-too-long": "Sohbet odasının ismi çok uzun!", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Bu gönderi için zaten oy verdin.", "reputation-system-disabled": "İtibar sistemi devre dışı.", "downvoting-disabled": "Eksi oylama devre dışı bırakılmış. ", diff --git a/public/language/uk/admin/settings/chat.json b/public/language/uk/admin/settings/chat.json index af017b5541..45d3d9af6a 100644 --- a/public/language/uk/admin/settings/chat.json +++ b/public/language/uk/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Вимкнути редагування/видалення повідомлень чату", "disable-editing-help": "Адміністратори на модератори звільнені від цього обмеження", "max-length": "Максимальна довжина повідомлення", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Максимальна кількість людей у кімнаті", "delay": "Час між повідомленнями в мілісекундах", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/uk/error.json b/public/language/uk/error.json index 7bd2dc97e3..664c7cc75e 100644 --- a/public/language/uk/error.json +++ b/public/language/uk/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Ви вже проголосували за цей пост.", "reputation-system-disabled": "Система репутацій вимкнена.", "downvoting-disabled": "Голосування проти вимкнено", diff --git a/public/language/vi/admin/settings/chat.json b/public/language/vi/admin/settings/chat.json index 12397eecf9..bb5cefc672 100644 --- a/public/language/vi/admin/settings/chat.json +++ b/public/language/vi/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Tắt chỉnh sửa / xóa tin nhắn trò chuyện", "disable-editing-help": "Quản trị viên và người kiểm duyệt toàn quyền được miễn hạn chế này", "max-length": "Độ dài tối đa của tin nhắn trò chuyện", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Số lượng người dùng tối đa trong phòng trò chuyện", "delay": "Thời gian giữa các tin nhắn trò chuyện tính bằng mili giây", "notification-delay": "Độ trễ thông báo cho tin nhắn trò chuyện. (0 để không bị chậm trễ)", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 7db2610e9b..ae643c3466 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Phòng trò chuyện không tồn tại.", "cant-add-users-to-chat-room": "Không thể thêm người dùng vào phòng trò chuyện.", "cant-remove-users-from-chat-room": "Không thể xóa người dùng khỏi phòng trò chuyện.", - "chat-room-name-too-long": "Tên phòng trò chuyện quá dài.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "Bạn đã bỏ phiếu cho bài viết này", "reputation-system-disabled": "Hệ thống đánh giá uy tính đã bị vô hiệu hóa.", "downvoting-disabled": "Phản đối đã bị tắt", diff --git a/public/language/zh-CN/admin/settings/chat.json b/public/language/zh-CN/admin/settings/chat.json index eb38710164..85fc21ca23 100644 --- a/public/language/zh-CN/admin/settings/chat.json +++ b/public/language/zh-CN/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "禁止编辑/删除聊天消息", "disable-editing-help": "管理员和超级管理员不受此限制", "max-length": "聊天信息的最大长度", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "聊天室的最多用户数", "delay": "聊天信息间的毫秒数", "notification-delay": "聊天信息的通知延迟(0 为即时)", diff --git a/public/language/zh-CN/error.json b/public/language/zh-CN/error.json index 0a9f1e4855..81a756b102 100644 --- a/public/language/zh-CN/error.json +++ b/public/language/zh-CN/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "聊天室不存在。", "cant-add-users-to-chat-room": "无法添加用户到聊天室。", "cant-remove-users-from-chat-room": "无法从聊天室删除用户。", - "chat-room-name-too-long": "聊天室名过长。", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "您已为此帖回复投过票了。", "reputation-system-disabled": "声望系统已禁用。", "downvoting-disabled": "踩已被禁用", diff --git a/public/language/zh-TW/admin/settings/chat.json b/public/language/zh-TW/admin/settings/chat.json index a98f078d7d..b6b7b88f63 100644 --- a/public/language/zh-TW/admin/settings/chat.json +++ b/public/language/zh-TW/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "禁止編輯/刪除聊天消息", "disable-editing-help": "管理員和超級版主不受此限制", "max-length": "聊天訊息的最大長度", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "聊天室的最多使用者數", "delay": "聊天訊息間的毫秒數", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/zh-TW/error.json b/public/language/zh-TW/error.json index 4121b2837b..3dec8cadab 100644 --- a/public/language/zh-TW/error.json +++ b/public/language/zh-TW/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "您已讚過此貼文回覆了。", "reputation-system-disabled": "聲望系統已停用。", "downvoting-disabled": "倒讚已被停用", From 9501d85559d61013dda50727a1576c22ca924106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Aug 2023 17:39:13 -0400 Subject: [PATCH 254/300] chore: up themes --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index 4e60cd69ad..752dc69074 100644 --- a/install/package.json +++ b/install/package.json @@ -101,10 +101,10 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.30", + "nodebb-theme-harmony": "1.1.31", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", - "nodebb-theme-persona": "13.2.15", + "nodebb-theme-persona": "13.2.16", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", From d7287b37fbb7a3b21ab47b1e1838ae1403a9892d Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 7 Aug 2023 09:18:47 +0000 Subject: [PATCH 255/300] Latest translations and fallbacks --- public/language/bg/admin/settings/chat.json | 2 +- public/language/bg/error.json | 2 +- public/language/bg/modules.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/bg/admin/settings/chat.json b/public/language/bg/admin/settings/chat.json index b9f00646c8..0c87d9d35d 100644 --- a/public/language/bg/admin/settings/chat.json +++ b/public/language/bg/admin/settings/chat.json @@ -4,7 +4,7 @@ "disable-editing": "Изключване на редактирането и изтриването на съобщения в разговорите", "disable-editing-help": "Това ограничение не засяга администраторите и глобалните модератори", "max-length": "Максимална дължина на съобщенията в разговорите", - "max-chat-room-name-length": "Maximum length of chat room names", + "max-chat-room-name-length": "Максимална дължина на имената на стаи за разговори", "max-room-size": "Максимален брой потребители в стая за разговор", "delay": "Време между съобщенията в разговорите (в милисекунди)", "notification-delay": "Забавяне преди известяване за съобщения в разговорите. (0 – без забавяне)", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index 94296820d4..82bc0a5d3a 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Стаята за разговори не съществува.", "cant-add-users-to-chat-room": "Към стаята за разговори не могат да бъдат добавяни потребители.", "cant-remove-users-from-chat-room": "От стаята за разговори не могат да бъдат премахвани потребители.", - "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", + "chat-room-name-too-long": "Името на стаята е твърде дълго. Имената не може да са по-дълги от %1 знака.", "already-voting-for-this-post": "Вече сте дали глас за тази публикация.", "reputation-system-disabled": "Системата за репутация е изключена.", "downvoting-disabled": "Отрицателното гласуване е изключено", diff --git a/public/language/bg/modules.json b/public/language/bg/modules.json index 9fee3beb51..72be8a42bb 100644 --- a/public/language/bg/modules.json +++ b/public/language/bg/modules.json @@ -10,7 +10,7 @@ "chat.no_active": "Нямате текущи разговори.", "chat.user_typing": "%1 пише...", "chat.user_has_messaged_you": "%1 Ви написа съобщение.", - "chat.replying-to": "Replying to %1", + "chat.replying-to": "Отговор до %1", "chat.see_all": "Всички разговори", "chat.mark_all_read": "Отбелязване на всички като прочетени", "chat.no-messages": "Моля, изберете получател, за да видите историята на съобщенията", From 2c8fd3b898858d891746daa13711ed04640b1877 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 00:02:03 -0400 Subject: [PATCH 256/300] fix(deps): update dependency esbuild to v0.18.19 (#11882) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 752dc69074..e0ee8c973d 100644 --- a/install/package.json +++ b/install/package.json @@ -63,7 +63,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.18", + "esbuild": "0.18.19", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 4cb0b73868436dae63eeeddab9f82a96962eccef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 00:02:23 -0400 Subject: [PATCH 257/300] fix(deps): update fontsource monorepo to v5.0.8 (#11880) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index e0ee8c973d..23a408470c 100644 --- a/install/package.json +++ b/install/package.json @@ -29,8 +29,8 @@ }, "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", - "@fontsource/inter": "5.0.7", - "@fontsource/poppins": "5.0.7", + "@fontsource/inter": "5.0.8", + "@fontsource/poppins": "5.0.8", "@fortawesome/fontawesome-free": "6.4.2", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", From f51af5e15e4c026feb92bb2a4f20f4fa7ec83e3f Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Tue, 8 Aug 2023 09:19:04 +0000 Subject: [PATCH 258/300] Latest translations and fallbacks --- public/language/it/admin/settings/chat.json | 2 +- public/language/it/error.json | 2 +- public/language/it/modules.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/language/it/admin/settings/chat.json b/public/language/it/admin/settings/chat.json index d4ab3ac1d2..0a38dbb9a9 100644 --- a/public/language/it/admin/settings/chat.json +++ b/public/language/it/admin/settings/chat.json @@ -4,7 +4,7 @@ "disable-editing": "Disabilita modifica/cancellazione messaggio chat", "disable-editing-help": "Gli amministratori e i moderatori globali sono esenti da questa restrizione.", "max-length": "Lunghezza massima dei messaggi della chat", - "max-chat-room-name-length": "Maximum length of chat room names", + "max-chat-room-name-length": "Lunghezza massima dei nomi delle stanze chat", "max-room-size": "Numero massimo di utenti nelle stanza chat", "delay": "Tempo tra i messaggi della chat in millisecondi", "notification-delay": "Ritardo di notifica per i messaggi di chat. (0 per nessun ritardo)", diff --git a/public/language/it/error.json b/public/language/it/error.json index bfb77f7570..ed1384580e 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "La stanza chat non esiste.", "cant-add-users-to-chat-room": "Impossibile aggiungere utenti alla stanza chat.", "cant-remove-users-from-chat-room": "Impossibile rimuovere gli utenti dalla stanza chat.", - "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", + "chat-room-name-too-long": "Nome della stanza chat troppo lungo. I nomi non possono essere più lunghi di %1 caratteri.", "already-voting-for-this-post": "Hai già votato per questo post", "reputation-system-disabled": "Il sistema di reputazione è disabilitato.", "downvoting-disabled": "Votata negativamente è disabilitato", diff --git a/public/language/it/modules.json b/public/language/it/modules.json index 567b9e501c..3f888dbbe6 100644 --- a/public/language/it/modules.json +++ b/public/language/it/modules.json @@ -10,7 +10,7 @@ "chat.no_active": "Non hai chat attive.", "chat.user_typing": "%1 sta scrivendo...", "chat.user_has_messaged_you": "%1 ti ha scritto.", - "chat.replying-to": "Replying to %1", + "chat.replying-to": "Risposta a %1", "chat.see_all": "Tutte le chat", "chat.mark_all_read": "Segna tutto come letto", "chat.no-messages": "Si prega di selezionare un destinatario per vedere la cronologia dei messaggi", From dfc155e4f63628ea9cc431e024d8df645b56da19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 8 Aug 2023 09:47:31 -0400 Subject: [PATCH 259/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 23a408470c..9f14c08b18 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.31", + "nodebb-theme-harmony": "1.1.32", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", "nodebb-theme-persona": "13.2.16", From 850cfb33f57d99127bdf73edaf4c9e55afa3ac4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 8 Aug 2023 14:10:18 -0400 Subject: [PATCH 260/300] fix: use config.undoTimeout instead of hardcoded value if user is in the target topic and they only moved 1 post show that post after moving update target tid as user navigates different topics --- public/src/client/topic/move-post.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/public/src/client/topic/move-post.js b/public/src/client/topic/move-post.js index 5d02be63ee..490c0cefec 100644 --- a/public/src/client/topic/move-post.js +++ b/public/src/client/topic/move-post.js @@ -50,7 +50,7 @@ define('forum/topic/move-post', [ title: '[[topic:thread_tools.move-posts]]', message: '[[topic:topic_move_posts_success]]', type: 'success', - timeout: 10000, + timeout: config.undoTimeout, timeoutfn: function () { movePosts(data); }, @@ -78,7 +78,7 @@ define('forum/topic/move-post', [ ) { targetTid = ajaxify.data.tid; } - if (targetTid && !tidInput.val()) { + if (targetTid) { tidInput.val(targetTid); } checkMoveButtonEnable(); @@ -149,7 +149,10 @@ define('forum/topic/move-post', [ $(this).remove(); }); }); - + if (data.pids.length === 1 && ajaxify.data.template.topic && + parseInt(data.tid, 10) === parseInt(ajaxify.data.tid, 10)) { + ajaxify.go(`/post/${data.pids[0]}`); + } closeMoveModal(); }).catch(alerts.error); } From 31ed1a40b8d3a7bae6d0b4d2270ea52d6c00f018 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:01:31 -0400 Subject: [PATCH 261/300] fix(deps): update dependency nodebb-theme-harmony to v1.1.33 (#11887) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 9f14c08b18..fe845fbab5 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.2.5", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.32", + "nodebb-theme-harmony": "1.1.33", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", "nodebb-theme-persona": "13.2.16", From 70f830757993366ee2e273833694494f5fda62ac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:01:37 -0400 Subject: [PATCH 262/300] fix(deps): update dependency nodebb-theme-persona to v13.2.17 (#11888) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index fe845fbab5..327c28b722 100644 --- a/install/package.json +++ b/install/package.json @@ -104,7 +104,7 @@ "nodebb-theme-harmony": "1.1.33", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", - "nodebb-theme-persona": "13.2.16", + "nodebb-theme-persona": "13.2.17", "nodebb-widget-essentials": "7.0.13", "nodemailer": "6.9.4", "nprogress": "0.2.0", From 454a968e87c0864b951ce96a3bf5f16c388e13aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:02:25 -0400 Subject: [PATCH 263/300] fix(deps): update dependency esbuild to v0.19.0 (#11884) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 327c28b722..872abfba1a 100644 --- a/install/package.json +++ b/install/package.json @@ -63,7 +63,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.18.19", + "esbuild": "0.19.0", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From 53006408a3b288b0d609f14a62d504d208cec694 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:02:42 -0400 Subject: [PATCH 264/300] fix(deps): update dependency nodebb-plugin-ntfy to v1.3.0 (#11889) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 872abfba1a..6ba05e6683 100644 --- a/install/package.json +++ b/install/package.json @@ -98,7 +98,7 @@ "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", "nodebb-plugin-mentions": "4.3.4", - "nodebb-plugin-ntfy": "1.2.5", + "nodebb-plugin-ntfy": "1.3.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.1.33", From 9608b124a2718883ab2b303f2781e721a285d05b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:02:51 -0400 Subject: [PATCH 265/300] fix(deps): update dependency compare-versions to v6.1.0 (#11883) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 6ba05e6683..d9df71c614 100644 --- a/install/package.json +++ b/install/package.json @@ -50,7 +50,7 @@ "clipboard": "2.0.11", "colors": "1.4.0", "commander": "11.0.0", - "compare-versions": "6.0.0", + "compare-versions": "6.1.0", "compression": "1.7.4", "connect-flash": "0.1.1", "connect-mongo": "5.0.0", From ac4623ee6d36320147484f380c4486facfd34a7f Mon Sep 17 00:00:00 2001 From: Opliko Date: Wed, 9 Aug 2023 01:41:04 +0200 Subject: [PATCH 266/300] fix: copy FA fonts to build directory instead of serving them directly (#11891) resolves issues when proxies don't fall back to NodeBB for assets --- public/scss/fontawesome/loader.scss | 2 +- src/meta/css.js | 18 +++++++++++++++++- src/routes/index.js | 2 -- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/public/scss/fontawesome/loader.scss b/public/scss/fontawesome/loader.scss index ceeca56340..81700f154d 100644 --- a/public/scss/fontawesome/loader.scss +++ b/public/scss/fontawesome/loader.scss @@ -1,4 +1,4 @@ -$fa-font-path: "./vendor/fontawesome/webfonts"; +$fa-font-path: "./fontawesome/webfonts"; @import "fontawesome"; @import "v4-shims"; @import "nodebb-shims"; \ No newline at end of file diff --git a/src/meta/css.js b/src/meta/css.js index 490ac8c215..5b665f6d43 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -5,6 +5,7 @@ const winston = require('winston'); const nconf = require('nconf'); const fs = require('fs'); const path = require('path'); +const { mkdirp } = require('mkdirp'); const plugins = require('../plugins'); const db = require('../database'); @@ -139,6 +140,20 @@ function getFontawesomeStyle() { return styles.map(style => `@import "fontawesome/style-${style}";`).join('\n'); } +async function copyFontAwesomeFiles() { + await mkdirp(path.join(__dirname, '../../build/public/fontawesome/webfonts')); + const fonts = await fs.promises.opendir(path.join(utils.getFontawesomePath(), '/webfonts')); + const copyOperations = []; + for await (const file of fonts) { + if (file.isFile() && file.name.match(/\.(woff2|ttf|eot)?$/)) { // there shouldn't be any legacy eot files, but just in case we'll allow it + copyOperations.push( + fs.promises.copyFile(path.join(fonts.path, file.name), path.join(__dirname, '../../build/public/fontawesome/webfonts/', file.name)) + ); + } + } + await Promise.all(copyOperations); +} + async function filterMissingFiles(filepaths) { const exists = await Promise.all( filepaths.map(async (filepath) => { @@ -186,7 +201,7 @@ async function getBundleMetadata(target) { const paths = [ path.join(__dirname, '../../node_modules'), path.join(__dirname, '../../public/scss'), - path.join(__dirname, '../../public/vendor/fontawesome/scss'), + path.join(__dirname, '../../public/fontawesome/scss'), path.join(utils.getFontawesomePath(), 'scss'), ]; @@ -324,6 +339,7 @@ CSS.buildBundle = async function (target, fork) { await Promise.all([ fs.promises.writeFile(path.join(__dirname, '../../build/public', `${target}.css`), ltr.code), fs.promises.writeFile(path.join(__dirname, '../../build/public', `${target}-rtl.css`), rtl.code), + copyFontAwesomeFiles(), ]); return [ltr.code, rtl.code]; }; diff --git a/src/routes/index.js b/src/routes/index.js index 97fa857a1a..4008f1565a 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -9,7 +9,6 @@ const meta = require('../meta'); const controllers = require('../controllers'); const controllerHelpers = require('../controllers/helpers'); const plugins = require('../plugins'); -const utils = require('../utils'); const authRoutes = require('./authentication'); const writeRoutes = require('./write'); @@ -173,7 +172,6 @@ function addCoreRoutes(app, router, middleware, mounts) { const statics = [ { route: '/assets', path: path.join(__dirname, '../../build/public') }, { route: '/assets', path: path.join(__dirname, '../../public') }, - { route: '/assets/vendor/fontawesome/webfonts', path: path.join(utils.getFontawesomePath(), 'webfonts') }, ]; const staticOptions = { maxAge: app.enabled('cache') ? 5184000000 : 0, From 514af5d657fda68c692b2b1fd1247e0a88b59f88 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 9 Aug 2023 14:24:21 -0400 Subject: [PATCH 267/300] fix: clicking on email consent form label checks the wrong box --- src/views/partials/gdpr_consent.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/partials/gdpr_consent.tpl b/src/views/partials/gdpr_consent.tpl index be376b554d..f127f00260 100644 --- a/src/views/partials/gdpr_consent.tpl +++ b/src/views/partials/gdpr_consent.tpl @@ -17,6 +17,6 @@
        - +
        \ No newline at end of file From 2fe933614ab3f75ddf39dc03cbb9de36ec58dccd Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 9 Aug 2023 14:24:21 -0400 Subject: [PATCH 268/300] fix: clicking on email consent form label checks the wrong box --- src/views/partials/gdpr_consent.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/partials/gdpr_consent.tpl b/src/views/partials/gdpr_consent.tpl index be376b554d..f127f00260 100644 --- a/src/views/partials/gdpr_consent.tpl +++ b/src/views/partials/gdpr_consent.tpl @@ -17,6 +17,6 @@
        - +
        \ No newline at end of file From d1d3809727b56bdeec9e6c9fadbf4b84ebd6b84c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:17:10 -0400 Subject: [PATCH 269/300] chore(deps): update commitlint monorepo to v17.7.0 (#11892) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index d9df71c614..48a47d13e8 100644 --- a/install/package.json +++ b/install/package.json @@ -152,8 +152,8 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", - "@commitlint/cli": "17.6.7", - "@commitlint/config-angular": "17.6.7", + "@commitlint/cli": "17.7.0", + "@commitlint/config-angular": "17.7.0", "coveralls": "3.1.1", "eslint": "8.46.0", "eslint-config-nodebb": "0.2.1", From 8f6feb0b4e5ecb8206bc51d6e4adb5318fd6fd3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:18:12 -0400 Subject: [PATCH 270/300] fix(deps): update dependency ace-builds to v1.24.0 (#11893) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 48a47d13e8..4fefd115fb 100644 --- a/install/package.json +++ b/install/package.json @@ -34,7 +34,7 @@ "@fortawesome/fontawesome-free": "6.4.2", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", - "ace-builds": "1.23.4", + "ace-builds": "1.24.0", "archiver": "5.3.1", "async": "3.2.4", "autoprefixer": "10.4.14", From 223c85e44e29b17ecace2508fb9b42f1894e709e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 10 Aug 2023 11:44:30 -0400 Subject: [PATCH 271/300] fix: if you send message scrollToBottom --- public/src/client/chats/messages.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index 864b6e0604..fc875fea04 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -85,16 +85,16 @@ define('forum/chats/messages', [ } messages.parseMessage(data, function (html) { - onMessagesParsed(chatContentEl, html); + onMessagesParsed(chatContentEl, html, data); }); }; - function onMessagesParsed(chatContentEl, html) { + function onMessagesParsed(chatContentEl, html, msgData) { const newMessage = $(html); const isAtBottom = messages.isAtBottom(chatContentEl); newMessage.appendTo(chatContentEl); messages.onMessagesAddedToDom(newMessage); - if (isAtBottom) { + if (isAtBottom || msgData.self) { messages.scrollToBottom(chatContentEl); // remove some message elements if there are too many const chatMsgEls = chatContentEl.find('[data-mid]'); From 4b04b41ec7cc6f7f34338e85c46315a7acf5f724 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Aug 2023 13:09:51 -0400 Subject: [PATCH 272/300] fix(deps): update dependency sass to v1.65.1 (#11895) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 4fefd115fb..fe4ba36123 100644 --- a/install/package.json +++ b/install/package.json @@ -124,7 +124,7 @@ "rss": "1.2.2", "rtlcss": "4.1.0", "sanitize-html": "2.11.0", - "sass": "1.64.2", + "sass": "1.65.1", "semver": "7.5.4", "serve-favicon": "2.5.0", "sharp": "0.32.4", From 1d44b004abf6e0ddf1e7ee1825123c182aa2d73d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Aug 2023 13:39:52 -0400 Subject: [PATCH 273/300] chore(deps): update dependency @commitlint/cli to v17.7.1 (#11896) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index fe4ba36123..059db6494a 100644 --- a/install/package.json +++ b/install/package.json @@ -152,7 +152,7 @@ }, "devDependencies": { "@apidevtools/swagger-parser": "10.1.0", - "@commitlint/cli": "17.7.0", + "@commitlint/cli": "17.7.1", "@commitlint/config-angular": "17.7.0", "coveralls": "3.1.1", "eslint": "8.46.0", From 76fde8efd71d066cdb4f6f73555a361ae77dda54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 10 Aug 2023 14:06:00 -0400 Subject: [PATCH 274/300] feat: #11897, show guest handles in post queue and after using POST /compose --- src/controllers/composer.js | 1 + src/posts/queue.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/controllers/composer.js b/src/controllers/composer.js index 9475fbdba5..bc1e4283c3 100644 --- a/src/controllers/composer.js +++ b/src/controllers/composer.js @@ -46,6 +46,7 @@ exports.post = async function (req, res) { req: req, timestamp: Date.now(), content: body.content, + handle: body.handle, fromQueue: false, }; req.body.noscript = 'true'; diff --git a/src/posts/queue.js b/src/posts/queue.js index 7cfdb462d8..2c485fb11e 100644 --- a/src/posts/queue.js +++ b/src/posts/queue.js @@ -38,6 +38,11 @@ module.exports = function (Posts) { postData.forEach((postData, index) => { if (postData) { postData.user = userData[index]; + if (postData.user.uid === 0 && postData.data.handle) { + postData.user.username = validator.escape(String(postData.data.handle)); + postData.user.displayname = postData.user.username; + postData.user.fullname = postData.user.username; + } postData.data.rawContent = validator.escape(String(postData.data.content)); postData.data.title = validator.escape(String(postData.data.title || '')); } From 8d2ac65872940808407bf16a74af4c9060d3cd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 11 Aug 2023 10:25:20 -0400 Subject: [PATCH 275/300] chore: up composer-default --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 059db6494a..f0fc166537 100644 --- a/install/package.json +++ b/install/package.json @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.1.3", - "nodebb-plugin-composer-default": "10.2.7", + "nodebb-plugin-composer-default": "10.2.8", "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", From e151ec86cca144a3cdfba57c0bf1b132c5da7a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 11 Aug 2023 10:54:39 -0400 Subject: [PATCH 276/300] chore: up composer --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f0fc166537..0a8975fd2b 100644 --- a/install/package.json +++ b/install/package.json @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.1.3", - "nodebb-plugin-composer-default": "10.2.8", + "nodebb-plugin-composer-default": "10.2.9", "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", From 7a79fed828c73b61d3e8c5504773e79fe231c063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 11 Aug 2023 20:43:56 -0400 Subject: [PATCH 277/300] feat: closes #11902, ability to clear search history --- public/language/en-GB/admin/dashboard.json | 4 ++- public/src/admin/dashboard/searches.js | 22 +++++++++++++++ src/database/redis/main.js | 2 +- src/socket.io/admin.js | 9 +++++++ src/views/admin/dashboard/searches.tpl | 31 +++++++++++----------- 5 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 public/src/admin/dashboard/searches.js diff --git a/public/language/en-GB/admin/dashboard.json b/public/language/en-GB/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/en-GB/admin/dashboard.json +++ b/public/language/en-GB/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/src/admin/dashboard/searches.js b/public/src/admin/dashboard/searches.js new file mode 100644 index 0000000000..8e53847b64 --- /dev/null +++ b/public/src/admin/dashboard/searches.js @@ -0,0 +1,22 @@ +'use strict'; + +define('admin/dashboard/searches', ['alerts', 'bootbox'], (alerts, bootbox) => { + const ACP = {}; + + ACP.init = () => { + $('#clear-search-history').on('click', () => { + bootbox.confirm('[[admin/dashboard:clear-search-history-confirm]]', function (ok) { + if (ok) { + socket.emit('admin.clearSearchHistory', function (err) { + if (err) { + return alerts.error(err); + } + ajaxify.refresh(); + }); + } + }); + }); + }; + + return ACP; +}); diff --git a/src/database/redis/main.js b/src/database/redis/main.js index c2e030b42c..8b79afb07c 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -26,7 +26,7 @@ module.exports = function (module) { module.scan = async function (params) { let cursor = '0'; let returnData = []; - const seen = {}; + const seen = Object.create(null); do { /* eslint-disable no-await-in-loop */ const res = await module.client.scan(cursor, 'MATCH', params.match, 'COUNT', 10000); diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 21165713db..e5efe90482 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -8,6 +8,7 @@ const events = require('../events'); const db = require('../database'); const privileges = require('../privileges'); const websockets = require('./index'); +const batch = require('../batch'); const index = require('./index'); const getAdminSearchDict = require('../admin/search').getDictionary; @@ -117,4 +118,12 @@ SocketAdmin.getServerTime = function (socket, data, callback) { }); }; +SocketAdmin.clearSearchHistory = async function () { + const keys = await db.scan({ match: 'searches:*' }); + await batch.processArray(keys, db.deleteAll, { + batch: 500, + interval: 0, + }); +}; + require('../promisify')(SocketAdmin); diff --git a/src/views/admin/dashboard/searches.tpl b/src/views/admin/dashboard/searches.tpl index 27bf1ca11d..c669c4eda4 100644 --- a/src/views/admin/dashboard/searches.tpl +++ b/src/views/admin/dashboard/searches.tpl @@ -1,20 +1,21 @@
        - -
        -
        - - -
        -
        - - -
        -
        - -
        -
        - +
        +
        +
        + + +
        +
        + + +
        +
        + +
        +
        + +
        From 80ea4eb071d234fa1c5ce8e64ad979d0e727fcef Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sat, 12 Aug 2023 00:44:22 +0000 Subject: [PATCH 278/300] chore(i18n): fallback strings for new resources: nodebb.admin-dashboard --- public/language/ar/admin/dashboard.json | 4 +++- public/language/bg/admin/dashboard.json | 4 +++- public/language/bn/admin/dashboard.json | 4 +++- public/language/cs/admin/dashboard.json | 4 +++- public/language/da/admin/dashboard.json | 4 +++- public/language/de/admin/dashboard.json | 4 +++- public/language/el/admin/dashboard.json | 4 +++- public/language/en-US/admin/dashboard.json | 4 +++- public/language/en-x-pirate/admin/dashboard.json | 4 +++- public/language/es/admin/dashboard.json | 4 +++- public/language/et/admin/dashboard.json | 4 +++- public/language/fa-IR/admin/dashboard.json | 4 +++- public/language/fi/admin/dashboard.json | 4 +++- public/language/fr/admin/dashboard.json | 4 +++- public/language/gl/admin/dashboard.json | 4 +++- public/language/he/admin/dashboard.json | 4 +++- public/language/hr/admin/dashboard.json | 4 +++- public/language/hu/admin/dashboard.json | 4 +++- public/language/hy/admin/dashboard.json | 4 +++- public/language/id/admin/dashboard.json | 4 +++- public/language/it/admin/dashboard.json | 4 +++- public/language/ja/admin/dashboard.json | 4 +++- public/language/ko/admin/dashboard.json | 4 +++- public/language/lt/admin/dashboard.json | 4 +++- public/language/lv/admin/dashboard.json | 4 +++- public/language/ms/admin/dashboard.json | 4 +++- public/language/nb/admin/dashboard.json | 4 +++- public/language/nl/admin/dashboard.json | 4 +++- public/language/pl/admin/dashboard.json | 4 +++- public/language/pt-BR/admin/dashboard.json | 4 +++- public/language/pt-PT/admin/dashboard.json | 4 +++- public/language/ro/admin/dashboard.json | 4 +++- public/language/ru/admin/dashboard.json | 4 +++- public/language/rw/admin/dashboard.json | 4 +++- public/language/sc/admin/dashboard.json | 4 +++- public/language/sk/admin/dashboard.json | 4 +++- public/language/sl/admin/dashboard.json | 4 +++- public/language/sq-AL/admin/dashboard.json | 4 +++- public/language/sr/admin/dashboard.json | 4 +++- public/language/sv/admin/dashboard.json | 4 +++- public/language/th/admin/dashboard.json | 4 +++- public/language/tr/admin/dashboard.json | 4 +++- public/language/uk/admin/dashboard.json | 4 +++- public/language/vi/admin/dashboard.json | 4 +++- public/language/zh-CN/admin/dashboard.json | 4 +++- public/language/zh-TW/admin/dashboard.json | 4 +++- 46 files changed, 138 insertions(+), 46 deletions(-) diff --git a/public/language/ar/admin/dashboard.json b/public/language/ar/admin/dashboard.json index e4ef65dfe2..584e28374b 100644 --- a/public/language/ar/admin/dashboard.json +++ b/public/language/ar/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "إنهاء", "filter": "تصفية", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/bg/admin/dashboard.json b/public/language/bg/admin/dashboard.json index 36df5fe2be..e5566620d1 100644 --- a/public/language/bg/admin/dashboard.json +++ b/public/language/bg/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Край", "filter": "Филтриране", "view-as-json": "Преглед като JSON", - "expand-analytics": "Разгъване на данните за анализ" + "expand-analytics": "Разгъване на данните за анализ", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/bn/admin/dashboard.json b/public/language/bn/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/bn/admin/dashboard.json +++ b/public/language/bn/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/cs/admin/dashboard.json b/public/language/cs/admin/dashboard.json index 5e23b55a70..8d7013572b 100644 --- a/public/language/cs/admin/dashboard.json +++ b/public/language/cs/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/da/admin/dashboard.json b/public/language/da/admin/dashboard.json index c68d7546bb..a3436a43f7 100644 --- a/public/language/da/admin/dashboard.json +++ b/public/language/da/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/de/admin/dashboard.json b/public/language/de/admin/dashboard.json index f3a2ba7d02..6e3fe813fc 100644 --- a/public/language/de/admin/dashboard.json +++ b/public/language/de/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Ende", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/el/admin/dashboard.json b/public/language/el/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/el/admin/dashboard.json +++ b/public/language/el/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/en-US/admin/dashboard.json b/public/language/en-US/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/en-US/admin/dashboard.json +++ b/public/language/en-US/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/en-x-pirate/admin/dashboard.json b/public/language/en-x-pirate/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/en-x-pirate/admin/dashboard.json +++ b/public/language/en-x-pirate/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/es/admin/dashboard.json b/public/language/es/admin/dashboard.json index fe9e41590d..642065819c 100644 --- a/public/language/es/admin/dashboard.json +++ b/public/language/es/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/et/admin/dashboard.json b/public/language/et/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/et/admin/dashboard.json +++ b/public/language/et/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/fa-IR/admin/dashboard.json b/public/language/fa-IR/admin/dashboard.json index 1d54af9b57..b5fc4c9f28 100644 --- a/public/language/fa-IR/admin/dashboard.json +++ b/public/language/fa-IR/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/fi/admin/dashboard.json b/public/language/fi/admin/dashboard.json index eadf0f2e1b..4113ed55bd 100644 --- a/public/language/fi/admin/dashboard.json +++ b/public/language/fi/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/fr/admin/dashboard.json b/public/language/fr/admin/dashboard.json index 2330a5a060..ae60b88b5d 100644 --- a/public/language/fr/admin/dashboard.json +++ b/public/language/fr/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Fin", "filter": "Filtre", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/gl/admin/dashboard.json b/public/language/gl/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/gl/admin/dashboard.json +++ b/public/language/gl/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/he/admin/dashboard.json b/public/language/he/admin/dashboard.json index 9d235e73f2..472c01a389 100644 --- a/public/language/he/admin/dashboard.json +++ b/public/language/he/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "סיום", "filter": "סינון", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/hr/admin/dashboard.json b/public/language/hr/admin/dashboard.json index d0921aaf29..ad7919906e 100644 --- a/public/language/hr/admin/dashboard.json +++ b/public/language/hr/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/hu/admin/dashboard.json b/public/language/hu/admin/dashboard.json index 0230121d88..3dd5958b6e 100644 --- a/public/language/hu/admin/dashboard.json +++ b/public/language/hu/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Vége", "filter": "Szűrő", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/hy/admin/dashboard.json b/public/language/hy/admin/dashboard.json index 7f7a5eb103..56895bd3cc 100644 --- a/public/language/hy/admin/dashboard.json +++ b/public/language/hy/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/id/admin/dashboard.json b/public/language/id/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/id/admin/dashboard.json +++ b/public/language/id/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/it/admin/dashboard.json b/public/language/it/admin/dashboard.json index 4c7414aff3..a4c83d4091 100644 --- a/public/language/it/admin/dashboard.json +++ b/public/language/it/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Fine", "filter": "Filtro", "view-as-json": "Visualizza come JSON", - "expand-analytics": "Espandi l'analisi" + "expand-analytics": "Espandi l'analisi", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ja/admin/dashboard.json b/public/language/ja/admin/dashboard.json index 2c9b925c20..936a823210 100644 --- a/public/language/ja/admin/dashboard.json +++ b/public/language/ja/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ko/admin/dashboard.json b/public/language/ko/admin/dashboard.json index 5f2e2bcca9..4f3677be07 100644 --- a/public/language/ko/admin/dashboard.json +++ b/public/language/ko/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/lt/admin/dashboard.json b/public/language/lt/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/lt/admin/dashboard.json +++ b/public/language/lt/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/lv/admin/dashboard.json b/public/language/lv/admin/dashboard.json index 040c085396..37c238865f 100644 --- a/public/language/lv/admin/dashboard.json +++ b/public/language/lv/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ms/admin/dashboard.json b/public/language/ms/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/ms/admin/dashboard.json +++ b/public/language/ms/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/nb/admin/dashboard.json b/public/language/nb/admin/dashboard.json index b603b9dc0d..902e55a91e 100644 --- a/public/language/nb/admin/dashboard.json +++ b/public/language/nb/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/nl/admin/dashboard.json b/public/language/nl/admin/dashboard.json index 37d87256d8..c68cfa7079 100644 --- a/public/language/nl/admin/dashboard.json +++ b/public/language/nl/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/pl/admin/dashboard.json b/public/language/pl/admin/dashboard.json index e607aebde2..6a635b8d08 100644 --- a/public/language/pl/admin/dashboard.json +++ b/public/language/pl/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/pt-BR/admin/dashboard.json b/public/language/pt-BR/admin/dashboard.json index c9ece029f7..5f67dcddcc 100644 --- a/public/language/pt-BR/admin/dashboard.json +++ b/public/language/pt-BR/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/pt-PT/admin/dashboard.json b/public/language/pt-PT/admin/dashboard.json index dfc2f254d9..5b97161633 100644 --- a/public/language/pt-PT/admin/dashboard.json +++ b/public/language/pt-PT/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ro/admin/dashboard.json b/public/language/ro/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/ro/admin/dashboard.json +++ b/public/language/ro/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/ru/admin/dashboard.json b/public/language/ru/admin/dashboard.json index 5a34d7b2fa..232816875c 100644 --- a/public/language/ru/admin/dashboard.json +++ b/public/language/ru/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Окончание", "filter": "Фильтр", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/rw/admin/dashboard.json b/public/language/rw/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/rw/admin/dashboard.json +++ b/public/language/rw/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sc/admin/dashboard.json b/public/language/sc/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/sc/admin/dashboard.json +++ b/public/language/sc/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sk/admin/dashboard.json b/public/language/sk/admin/dashboard.json index 283a4d2a8d..d30f11dbc7 100644 --- a/public/language/sk/admin/dashboard.json +++ b/public/language/sk/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sl/admin/dashboard.json b/public/language/sl/admin/dashboard.json index b03c9ae0eb..0e64701cd0 100644 --- a/public/language/sl/admin/dashboard.json +++ b/public/language/sl/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sq-AL/admin/dashboard.json b/public/language/sq-AL/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/sq-AL/admin/dashboard.json +++ b/public/language/sq-AL/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sr/admin/dashboard.json b/public/language/sr/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/sr/admin/dashboard.json +++ b/public/language/sr/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/sv/admin/dashboard.json b/public/language/sv/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/sv/admin/dashboard.json +++ b/public/language/sv/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/th/admin/dashboard.json b/public/language/th/admin/dashboard.json index c75f2d68ac..681c202f47 100644 --- a/public/language/th/admin/dashboard.json +++ b/public/language/th/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/tr/admin/dashboard.json b/public/language/tr/admin/dashboard.json index ef7ed1fe81..a08b3a6082 100644 --- a/public/language/tr/admin/dashboard.json +++ b/public/language/tr/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "Bitiş", "filter": "Filtre", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/uk/admin/dashboard.json b/public/language/uk/admin/dashboard.json index 6123907fd5..b230979fca 100644 --- a/public/language/uk/admin/dashboard.json +++ b/public/language/uk/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/vi/admin/dashboard.json b/public/language/vi/admin/dashboard.json index 34d9568c1a..66af8c637c 100644 --- a/public/language/vi/admin/dashboard.json +++ b/public/language/vi/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Bộ lọc", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/zh-CN/admin/dashboard.json b/public/language/zh-CN/admin/dashboard.json index c5d0846322..990e68e257 100644 --- a/public/language/zh-CN/admin/dashboard.json +++ b/public/language/zh-CN/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "结束", "filter": "过滤器", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } diff --git a/public/language/zh-TW/admin/dashboard.json b/public/language/zh-TW/admin/dashboard.json index 9a84af9c27..0f7a66ab6d 100644 --- a/public/language/zh-TW/admin/dashboard.json +++ b/public/language/zh-TW/admin/dashboard.json @@ -92,5 +92,7 @@ "end": "End", "filter": "Filter", "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics" + "expand-analytics": "Expand analytics", + "clear-search-history": "Clear Search History", + "clear-search-history-confirm": "Are you sure you want to clear entire search history?" } From af3c5e542a59139d6eace472ac7ed00d03bd253e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 21:13:31 -0400 Subject: [PATCH 279/300] chore(deps): update dependency eslint to v8.47.0 (#11904) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0a8975fd2b..f2c1b0aa2a 100644 --- a/install/package.json +++ b/install/package.json @@ -155,7 +155,7 @@ "@commitlint/cli": "17.7.1", "@commitlint/config-angular": "17.7.0", "coveralls": "3.1.1", - "eslint": "8.46.0", + "eslint": "8.47.0", "eslint-config-nodebb": "0.2.1", "eslint-plugin-import": "2.27.5", "grunt": "1.6.1", From 12771b70c0cf6c5dd9153226edb8e569ea9c0d97 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 21:13:50 -0400 Subject: [PATCH 280/300] fix(deps): update dependency esbuild to v0.19.1 (#11903) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f2c1b0aa2a..5e6f6c1478 100644 --- a/install/package.json +++ b/install/package.json @@ -63,7 +63,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.19.0", + "esbuild": "0.19.1", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From fd385647a21f6a66738b4637436806e16b664212 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 21:14:23 -0400 Subject: [PATCH 281/300] fix(deps): update dependency lru-cache to v10.0.1 (#11899) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 5e6f6c1478..a315f057dd 100644 --- a/install/package.json +++ b/install/package.json @@ -83,7 +83,7 @@ "jsonwebtoken": "9.0.1", "lodash": "4.17.21", "logrotate-stream": "0.2.9", - "lru-cache": "10.0.0", + "lru-cache": "10.0.1", "mime": "3.0.0", "mkdirp": "3.0.1", "mongodb": "5.7.0", From b8d926f917af91ce03eeafd1fd2dd7715b44eec6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 21:15:10 -0400 Subject: [PATCH 282/300] fix(deps): update dependency nodebb-plugin-ntfy to v1.4.0 (#11905) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a315f057dd..0fec1d2319 100644 --- a/install/package.json +++ b/install/package.json @@ -98,7 +98,7 @@ "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", "nodebb-plugin-mentions": "4.3.4", - "nodebb-plugin-ntfy": "1.3.0", + "nodebb-plugin-ntfy": "1.4.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", "nodebb-theme-harmony": "1.1.33", From 762658d428b647d20fae36efe27bc1ccff47c283 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 21:35:38 -0400 Subject: [PATCH 283/300] fix(deps): update dependency nodebb-plugin-2factor to v7.2.1 (#11898) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 0fec1d2319..db6d6fd424 100644 --- a/install/package.json +++ b/install/package.json @@ -91,7 +91,7 @@ "mousetrap": "1.6.5", "multiparty": "4.2.3", "nconf": "0.12.0", - "nodebb-plugin-2factor": "7.1.3", + "nodebb-plugin-2factor": "7.2.1", "nodebb-plugin-composer-default": "10.2.9", "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", From b49698270c9cdc32c1773a549840fcfcd7fbc172 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sat, 12 Aug 2023 09:19:08 +0000 Subject: [PATCH 284/300] Latest translations and fallbacks --- public/language/fr/admin/admin.json | 4 +-- public/language/fr/admin/extend/rewards.json | 4 +-- public/language/fr/admin/extend/widgets.json | 4 +-- .../language/fr/admin/manage/admins-mods.json | 4 +-- public/language/fr/admin/manage/groups.json | 14 +++++----- public/language/fr/admin/manage/tags.json | 4 +-- public/language/fr/admin/manage/uploads.json | 2 +- public/language/fr/admin/manage/users.json | 4 +-- public/language/fr/admin/menu.json | 4 +-- public/language/fr/admin/settings/api.json | 2 +- public/language/fr/admin/settings/chat.json | 2 +- public/language/fr/admin/settings/email.json | 2 +- .../language/fr/admin/settings/general.json | 2 +- public/language/fr/error.json | 6 ++-- public/language/fr/global.json | 2 +- public/language/fr/modules.json | 28 +++++++++---------- public/language/fr/themes/harmony.json | 12 ++++---- public/language/fr/themes/persona.json | 14 +++++----- public/language/fr/users.json | 2 +- 19 files changed, 58 insertions(+), 58 deletions(-) diff --git a/public/language/fr/admin/admin.json b/public/language/fr/admin/admin.json index 4b5c2f385e..30e90b3093 100644 --- a/public/language/fr/admin/admin.json +++ b/public/language/fr/admin/admin.json @@ -13,6 +13,6 @@ "max": "Max:", "view": "Voir", "edit": "Éditer ", - "add": "Add", - "select-icon": "Select Icon" + "add": "Ajouter", + "select-icon": "Sélectionner un icône" } \ No newline at end of file diff --git a/public/language/fr/admin/extend/rewards.json b/public/language/fr/admin/extend/rewards.json index b0c72b2bcb..49973403a5 100644 --- a/public/language/fr/admin/extend/rewards.json +++ b/public/language/fr/admin/extend/rewards.json @@ -1,12 +1,12 @@ { "rewards": "Récompenses", - "add-reward": "Add reward", + "add-reward": "Nouvelle récompense", "condition-if-users": "Si la propriété de l'utilisateur", "condition-is": "Est :", "condition-then": "Alors :", "max-claims": "Nombre de fois que la récompense peut être obtenue", "zero-infinite": "Entrez 0 pour infini", - "select-reward": "Select reward", + "select-reward": "Sélectionner une récompense", "delete": "Supprimer", "enable": "Activer", "disable": "Désactiver", diff --git a/public/language/fr/admin/extend/widgets.json b/public/language/fr/admin/extend/widgets.json index 66eb113295..d8b8fa5088 100644 --- a/public/language/fr/admin/extend/widgets.json +++ b/public/language/fr/admin/extend/widgets.json @@ -27,7 +27,7 @@ "container.placeholder": "Glissez et déposez un bloc ou entrez HTML ici.", "show-to-groups": "Visible pour les groupes", "hide-from-groups": "Masquer pour les groupes", - "start-date": "Start date", - "end-date": "End date", + "start-date": "Date de début", + "end-date": "Date de fin", "hide-on-mobile": "Masquer sur mobile" } \ No newline at end of file diff --git a/public/language/fr/admin/manage/admins-mods.json b/public/language/fr/admin/manage/admins-mods.json index d5a6aaa1c5..35579e669b 100644 --- a/public/language/fr/admin/manage/admins-mods.json +++ b/public/language/fr/admin/manage/admins-mods.json @@ -1,11 +1,11 @@ { - "manage-admins-and-mods": "Manage Admins & Mods", + "manage-admins-and-mods": "Gérer les admins et les modos", "administrators": "Administrateurs", "global-moderators": "Modérateurs Globaux", "moderators": "Modérateurs", "no-global-moderators": "Aucun Modérateur Global ", "no-sub-categories": "Aucunes sous-catégories", - "view-children": "View children (%1)", + "view-children": "Afficher les enfants (%1)", "no-moderators": "Aucun Modérateur", "add-administrator": "Ajouter un Administrateur", "add-global-moderator": "Ajouter un Modérateur Global", diff --git a/public/language/fr/admin/manage/groups.json b/public/language/fr/admin/manage/groups.json index 1c73034c21..b8159c5705 100644 --- a/public/language/fr/admin/manage/groups.json +++ b/public/language/fr/admin/manage/groups.json @@ -1,10 +1,10 @@ { - "manage-groups": "Manage Groups", - "add-group": "Add group", - "edit-group": "Edit Group", - "back-to-groups": "Back to groups", - "view-group": "View group", - "icon-and-title": "Icon & Title", + "manage-groups": "Gérer les groupes", + "add-group": "Ajouter un groupe", + "edit-group": "Éditer un groupe", + "back-to-groups": "Retour aux groupes", + "view-group": "Voir le groupe", + "icon-and-title": "Icône & titre", "name": "Nom du groupe", "badge": "Badge", "properties": "Propriétées", @@ -16,7 +16,7 @@ "edit": "Éditer", "delete": "Supprimer", "privileges": "Privilèges", - "members-csv": "Members (CSV)", + "members-csv": "Membres (CSV)", "search-placeholder": "Rechercher", "create": "Créer un groupe", "description-placeholder": "Une courte description de votre groupe", diff --git a/public/language/fr/admin/manage/tags.json b/public/language/fr/admin/manage/tags.json index 7e1ebd3584..f7fc238bfd 100644 --- a/public/language/fr/admin/manage/tags.json +++ b/public/language/fr/admin/manage/tags.json @@ -1,11 +1,11 @@ { - "manage-tags": "Manage Tags", + "manage-tags": "Gérer les mots-clés", "none": "Votre forum n'a pour l'instant aucun sujet avec mots-clés.", "bg-color": "Couleur d'arrière plan", "text-color": "Couleur du texte", "description": "Pour une sélection multiple :\nSélectionnez des mots-clés en cliquant ou en sélectionnant avec votre souris ou utilisez la touche CTRL .", "create": "Créer le mot-clés", - "add-tag": "Add tag", + "add-tag": "Ajouter un mots-clés", "modify": "Modifier les mots-clés", "rename": "Renommer les mots-clés", "delete": "Supprimer la sélection", diff --git a/public/language/fr/admin/manage/uploads.json b/public/language/fr/admin/manage/uploads.json index 73e359622d..4edb3d8152 100644 --- a/public/language/fr/admin/manage/uploads.json +++ b/public/language/fr/admin/manage/uploads.json @@ -1,5 +1,5 @@ { - "manage-uploads": "Manage Uploads", + "manage-uploads": "Gérer les téléchargements", "upload-file": "Envoyer un fichier", "filename": "Nom du fichier", "usage": "Utilisé dans le message", diff --git a/public/language/fr/admin/manage/users.json b/public/language/fr/admin/manage/users.json index ef00aa09d7..3d55eb623a 100644 --- a/public/language/fr/admin/manage/users.json +++ b/public/language/fr/admin/manage/users.json @@ -1,5 +1,5 @@ { - "manage-users": "Manage Users", + "manage-users": "Gérer les utilisateurs", "users": "Utilisateurs", "edit": "Actions", "make-admin": "Promouvoir Admin", @@ -18,7 +18,7 @@ "purge": "Supprimer le(s) compte(s) et le contenu", "download-csv": "Exporter en CSV", "manage-groups": "Gérer les groupes", - "set-reputation": "Set Reputation", + "set-reputation": "Définir une réputation", "add-group": "Ajouter un groupe", "create": "Créer un utilisateur", "invite": "Inviter par mail", diff --git a/public/language/fr/admin/menu.json b/public/language/fr/admin/menu.json index 2180c33ed5..8d62e18051 100644 --- a/public/language/fr/admin/menu.json +++ b/public/language/fr/admin/menu.json @@ -73,9 +73,9 @@ "development/info": "Info", "rebuild-and-restart-forum": "Régénérer & Redémarrer votre forum", - "rebuild-and-restart": "Rebuild & Restart", + "rebuild-and-restart": "Régénérer & Redémarrer", "restart-forum": "Redémarrer le forum", - "restart": "Restart", + "restart": "Redémarrer", "logout": "Déconnexion ", "view-forum": "Voir le forum", diff --git a/public/language/fr/admin/settings/api.json b/public/language/fr/admin/settings/api.json index e8215ecfb7..cbf82947e6 100644 --- a/public/language/fr/admin/settings/api.json +++ b/public/language/fr/admin/settings/api.json @@ -14,7 +14,7 @@ "uid-help-text": "Spécifiez un ID utilisateur à associer à ce token. Si l'ID utilisateur est 0, il sera considéré comme un token maître, qui peut prendre l'identité d'autres utilisateurs en fonction du paramètre _uid", "description": "Description", "last-seen": "Last seen", - "created": "Created", + "created": "Créée", "create-token": "Create Token", "update-token": "Update Token", "master-token": "Master token", diff --git a/public/language/fr/admin/settings/chat.json b/public/language/fr/admin/settings/chat.json index dc25273c0e..0cd3d8201f 100644 --- a/public/language/fr/admin/settings/chat.json +++ b/public/language/fr/admin/settings/chat.json @@ -4,7 +4,7 @@ "disable-editing": "Désactiver l'édition/la suppression des messages des discussions", "disable-editing-help": "Les administrateurs et modérateurs globaux sont dispensés de cette restriction", "max-length": "Longueur maximales des messages de discussion", - "max-chat-room-name-length": "Maximum length of chat room names", + "max-chat-room-name-length": "Longueur maximale des noms de salons", "max-room-size": "Nombre maximum d'utilisateurs dans une même discussion", "delay": "Temps entre chaque message de discussion (en millisecondes)", "notification-delay": "Délai de notification pour les messages de chat. (0 pour aucun délai)", diff --git a/public/language/fr/admin/settings/email.json b/public/language/fr/admin/settings/email.json index f44a23d0d7..2d1e56a0db 100644 --- a/public/language/fr/admin/settings/email.json +++ b/public/language/fr/admin/settings/email.json @@ -42,7 +42,7 @@ "subscriptions.hour-help": "Veuillez entrer un nombre représentant l'heure à laquelle envoyer les lettres d'activités (c'est à dire 0 pour minuit, 17 pour 5:00 pm). Gardez à l'esprit qu'il s'agit de l'heure du serveur, et peut ne pas correspondre à votre heure locale.
        L'heure du serveur est :
        La prochaine lettre d'activités sera envoyée à ", "notifications.remove-images": "Supprimer les images des notifications par e-mail", "require-email-address": "Exiger une adresse e-mail aux nouveaux utilisateurs ", - "require-email-address-warning": "By default, users can opt-out of entering an email address by leaving the field blank. Enabling this option means new users will have to enter and confirm an email address in order to proceed with registration and subsequent access to the forum. It does not ensure user will enter a real email address, nor even an address they own.", + "require-email-address-warning": "Par défaut, les utilisateurs peuvent refuser de saisir une adresse e-mail en laissant le champ vide. L'activation de cette option signifie que les nouveaux utilisateurs devront entrer et confirmer une adresse e-mail afin de procéder à l'inscription et à l'accès ultérieur au forum. Cela ne garantit pas que l'utilisateur saisira une véritable adresse e-mail, ni même une adresse qu'il possède.", "send-validation-email": "Envoyer une confirmation de validation lorsqu'un e-mail est ajouté ou modifié", "include-unverified-emails": "Envoyer des mails aux destinataires qui n'ont pas explicitement confirmé leurs mails", "include-unverified-warning": "Par défaut, les utilisateurs dont les mails sont associés à leur compte ont déjà été vérifiés, mais il existe des situations où ce n'est pas le cas (par exemple, les connexions SSO, les utilisateurs bénéficiant de droits acquis, etc.). Activez ce paramètre à vos risques et périls – l'envoi de mails à des adresses non vérifiées peut constituer une violation des lois anti-spam régionales.", diff --git a/public/language/fr/admin/settings/general.json b/public/language/fr/admin/settings/general.json index acd5e41788..7ebebf00de 100644 --- a/public/language/fr/admin/settings/general.json +++ b/public/language/fr/admin/settings/general.json @@ -1,5 +1,5 @@ { - "general-settings": "General Settings", + "general-settings": "Réglages Principaux", "on-this-page": "On this page:", "site-settings": "Réglages du site", "title": "Titre du site", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index e42b5182bf..71304010e0 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -55,7 +55,7 @@ "user-banned-reason-until": "Désolé, ce compte a été banni jusqu'au %1 (Raison : %2).", "user-too-new": "Désolé, vous devez attendre encore %1 seconde(s) avant d'envoyer votre premier message", "blacklisted-ip": "Désolé, votre adresse IP a été bannie de cette communauté. Si vous pensez que c'est une erreur, veuillez contacter un administrateur.", - "cant-blacklist-self-ip": "You can't blacklist your own IP", + "cant-blacklist-self-ip": "Vous ne pouvez pas mettre votre propre IP sur liste noire", "ban-expiry-missing": "Veuillez entrer une date de fin de banissement.", "no-category": "Cette catégorie n'existe pas", "no-topic": "Ce sujet n'existe pas", @@ -165,7 +165,7 @@ "chat-room-does-not-exist": "Le salon de discussion n'existe pas.", "cant-add-users-to-chat-room": "Impossible d'ajouter des utilisateurs au salon.", "cant-remove-users-from-chat-room": "Impossible de supprimer des utilisateurs du salon.", - "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", + "chat-room-name-too-long": "Le nom de la salon est trop long. Les noms ne peuvent pas contenir plus de %1 caractères.", "already-voting-for-this-post": "Vous avez déjà voté pour ce message.", "reputation-system-disabled": "Le système de réputation est désactivé", "downvoting-disabled": "Les votes négatifs ne sont pas autorisés", @@ -200,7 +200,7 @@ "not-in-room": "L'utilisateur n'est pas dans cette salle", "cant-kick-self": "Vous ne pouvez pas vous exclure vous-même du groupe", "no-users-selected": "Aucun utilisateur sélectionné", - "no-groups-selected": "No group(s) selected", + "no-groups-selected": "Aucun groupe(s) sélectionné", "invalid-home-page-route": "Chemin vers la page d'accueil invalide", "invalid-session": "Session Invalide", "invalid-session-text": "Il semblerait que votre session de connexion ne soit plus active. Merci de rafraîchir cette page.", diff --git a/public/language/fr/global.json b/public/language/fr/global.json index a8598837a6..fbd61b0d5f 100644 --- a/public/language/fr/global.json +++ b/public/language/fr/global.json @@ -51,7 +51,7 @@ "nextpage": "Page suivante", "alert.success": "Succès", "alert.error": "Erreur", - "alert.warning": "Warning", + "alert.warning": "Avertissement", "alert.info": "Info", "alert.banned": "Bannis", "alert.banned.message": "Vous venez d'être banni, votre accès est désormais restreint.", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index dc49960d2d..0f773f5e32 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -10,7 +10,7 @@ "chat.no_active": "Vous n'avez aucune discussion en cours.", "chat.user_typing": "%1 est en train d'écrire ...", "chat.user_has_messaged_you": "%1 vous a envoyé un message.", - "chat.replying-to": "Replying to %1", + "chat.replying-to": "En réponse à %1", "chat.see_all": "Tous les chats", "chat.mark_all_read": "Marquez tous comme lu", "chat.no-messages": "Veuillez sélectionner un destinataire pour voir l'historique des discussions", @@ -28,21 +28,21 @@ "chat.three_months": "3 Mois", "chat.delete_message_confirm": "Êtes-vous sûr de vouloir supprimer ce message ?", "chat.retrieving-users": "Ajouter des utilisateurs ...", - "chat.view-users-list": "View users list", - "chat.public-rooms": "Public Rooms (%1)", - "chat.private-rooms": "Private Rooms (%1)", - "chat.create-room": "Create Chat Room", - "chat.private.option": "Private (Only visible to users added to room)", - "chat.public.option": "Public (Visible to every user in selected groups)", - "chat.public.groups-help": "To create a chat room that is visible to all users select registered-users from the group list.", + "chat.view-users-list": "Afficher la liste de utilisateurs", + "chat.public-rooms": "Salon Publique (ù1)", + "chat.private-rooms": "Salon Privé (%1)", + "chat.create-room": "Créer une salon de discussion", + "chat.private.option": "Privé (uniquement visible pour les utilisateurs ajoutés au salon)", + "chat.public.option": "Public (Visible par tous les utilisateurs des groupes sélectionnés)", + "chat.public.groups-help": "Pour créer une salon de discussion visible par tous les utilisateurs, sélectionnez les utilisateurs enregistrés dans la liste des groupes.", "chat.manage-room": "Gérer l'espace de discussion", "chat.add-user": "Ajouter un utilisateur", - "chat.notification-settings": "Notification Settings", - "chat.default-notification-setting": "Default Notification Setting", - "chat.notification-setting-room-default": "Room Default", - "chat.notification-setting-none": "No notifications", - "chat.notification-setting-at-mention-only": "@mention only", - "chat.notification-setting-all-messages": "All messages", + "chat.notification-settings": "Paramètres de notification", + "chat.default-notification-setting": "Paramètres des notifications par défaut", + "chat.notification-setting-room-default": "Salon par défaut", + "chat.notification-setting-none": "Aucunes notifications", + "chat.notification-setting-at-mention-only": "@mention seulement", + "chat.notification-setting-all-messages": "Tous les messages", "chat.select-groups": "Sélectionner des groupes", "chat.add-user-help": "Rechercher des utilisateurs ici. Lorsque cette option est sélectionnée, l'utilisateur sera ajouté à l'espace de discussion. Le nouvel utilisateur ne pourra pas visualiser les échanges avant d'être ajoutés à la conversation. Seuls les propriétaires de l'espace de discussion () peuvent supprimer des utilisateurs.", "chat.confirm-chat-with-dnd-user": "Cet utilisateur a son statut en mode \"Ne pas déranger\". Voulez-vous quand même discuter avec lui ?", diff --git a/public/language/fr/themes/harmony.json b/public/language/fr/themes/harmony.json index dc3c021cc2..9c6527fee9 100644 --- a/public/language/fr/themes/harmony.json +++ b/public/language/fr/themes/harmony.json @@ -7,10 +7,10 @@ "settings.title": "Configuration du thème", "settings.enableQuickReply": "Activer les réponses rapide", "settings.centerHeaderElements": "Centrer les éléments d'en-tête", - "settings.mobileTopicTeasers": "Show topic teasers on mobile", - "settings.stickyToolbar": "Sticky toolbar", - "settings.stickyToolbar.help": "The toolbar on topic and category pages will stick to the top of the page", - "settings.autohideBottombar": "Auto hide bottom bar", - "settings.autohideBottombar.help": "The bottom bar on mobile view will be hidden when the page is scrolled down", - "settings.chatModals": "Enable chat modals" + "settings.mobileTopicTeasers": "Afficher les teasers de sujet sur mobile", + "settings.stickyToolbar": "Barre d'outils", + "settings.stickyToolbar.help": "La barre d'outils sur les pages de sujets et de catégories restera en haut de la page", + "settings.autohideBottombar": "Masquer automatiquement la barre inférieure", + "settings.autohideBottombar.help": "La barre inférieure de la vue mobile sera masquée lorsque la page défilera vers le bas", + "settings.chatModals": "Activer les discussions" } \ No newline at end of file diff --git a/public/language/fr/themes/persona.json b/public/language/fr/themes/persona.json index c6aec765ad..f0cc2ac77a 100644 --- a/public/language/fr/themes/persona.json +++ b/public/language/fr/themes/persona.json @@ -1,10 +1,10 @@ { - "settings.title": "Theme settings", - "settings.intro": "You can customise your theme settings here. Settings are stored on a per-device basis, so you are able to have different settings on different devices (phone, tablet, desktop, etc.)", + "settings.title": "Configuration du thème", + "settings.intro": "Vous pouvez personnaliser les paramètres de votre thème ici. Les paramètres sont stockés sur une base par appareil, vous pouvez donc avoir différents paramètres sur différents appareils (téléphone, tablette, ordinateur de bureau, etc.)", "settings.mobile-menu-side": "Changer la position du menu en version mobiles", - "settings.autoHidingNavbar": "Automatically hide the navbar on scroll", - "settings.autoHidingNavbar-xs": "Very small screens (e.g. phones in portrait mode)", - "settings.autoHidingNavbar-sm": "Smaller screens (e.g. phones, some tablets)", - "settings.autoHidingNavbar-md": "Medium sized screens (e.g. tablets in landscape mode)", - "settings.autoHidingNavbar-lg": "Larger screens (e.g. desktop computers)" + "settings.autoHidingNavbar": "Masquer automatiquement la barre de navigation lors du défilement", + "settings.autoHidingNavbar-xs": "Très petits écrans (par exemple, téléphones en mode portrait)", + "settings.autoHidingNavbar-sm": "Petits écrans (par exemple, téléphones, certaines tablettes)", + "settings.autoHidingNavbar-md": "Moyen écrans (ex. tablettes en mode paysage)", + "settings.autoHidingNavbar-lg": "Grands écrans (par exemple, ordinateurs de bureau)" } \ No newline at end of file diff --git a/public/language/fr/users.json b/public/language/fr/users.json index 21a2ac5df0..36b9dd9a45 100644 --- a/public/language/fr/users.json +++ b/public/language/fr/users.json @@ -6,7 +6,7 @@ "most_flags": "Les plus signalés", "search": "Rechercher", "enter_username": "Entrez le nom d'un utilisateur", - "search-user-for-chat": "Search for a user to start chat", + "search-user-for-chat": "Rechercher un utilisateur pour démarrer la discussion", "load_more": "Charger la suite", "users-found-search-took": "%1 utilisateur(s) trouvé(s)! La recherche a pris %2 secondes.", "filter-by": "Filtrer par", From ae3e853078cccddb89052df9e355a83d16eab4fa Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Sun, 13 Aug 2023 09:18:25 +0000 Subject: [PATCH 285/300] Latest translations and fallbacks --- public/language/bg/admin/dashboard.json | 4 ++-- .../fr/admin/appearance/customise.json | 4 ++-- .../language/fr/admin/appearance/skins.json | 2 +- public/language/fr/admin/dashboard.json | 22 +++++++++---------- .../language/fr/admin/manage/categories.json | 14 ++++++------ .../language/fr/admin/manage/privileges.json | 4 ++-- public/language/fr/admin/menu.json | 2 +- public/language/fr/admin/settings/api.json | 18 +++++++-------- .../language/fr/admin/settings/general.json | 6 ++--- public/language/fr/admin/settings/guest.json | 2 +- public/language/fr/admin/settings/post.json | 2 +- .../fr/admin/settings/reputation.json | 2 +- public/language/fr/admin/settings/user.json | 2 +- public/language/fr/email.json | 4 ++-- public/language/fr/modules.json | 8 +++---- public/language/fr/topic.json | 4 ++-- 16 files changed, 50 insertions(+), 50 deletions(-) diff --git a/public/language/bg/admin/dashboard.json b/public/language/bg/admin/dashboard.json index e5566620d1..1702728fc7 100644 --- a/public/language/bg/admin/dashboard.json +++ b/public/language/bg/admin/dashboard.json @@ -93,6 +93,6 @@ "filter": "Филтриране", "view-as-json": "Преглед като JSON", "expand-analytics": "Разгъване на данните за анализ", - "clear-search-history": "Clear Search History", - "clear-search-history-confirm": "Are you sure you want to clear entire search history?" + "clear-search-history": "Изчистване на историята на търсенията", + "clear-search-history-confirm": "Наистина ли искате да изчистите историята на търсенията?" } diff --git a/public/language/fr/admin/appearance/customise.json b/public/language/fr/admin/appearance/customise.json index eeff047b45..52942da8a3 100644 --- a/public/language/fr/admin/appearance/customise.json +++ b/public/language/fr/admin/appearance/customise.json @@ -15,6 +15,6 @@ "custom-css.livereload": "Activer le rechargement en direct", "custom-css.livereload.description": "Activez cette option pour forcer toutes les sessions sur chaque appareil connecté à votre compte à se rafraichir lorsque vous cliquez sur Enregistrer.", "bsvariables": "_variables.scss", - "bsvariables.description": "Override bootstrap variables here. You can also use a tool like bootstrap.build and paste the output here.
        Changes require a rebuild & restart.", - "bsvariables.enable": "Enable _variables.scss" + "bsvariables.description": "Remplacez les variables de lancement ici. Vous pouvez également utiliser un outil comme bootstrap.build et copier coller le code ici.
        Les modifications nécessitent une reconstruction et un redémarrage.", + "bsvariables.enable": "Activer _variables.scss" } \ No newline at end of file diff --git a/public/language/fr/admin/appearance/skins.json b/public/language/fr/admin/appearance/skins.json index 283e53ebb8..0f3e380e01 100644 --- a/public/language/fr/admin/appearance/skins.json +++ b/public/language/fr/admin/appearance/skins.json @@ -1,6 +1,6 @@ { "skins": "Skins", - "bootswatch-skins": "Bootswatch Skins", + "bootswatch-skins": "Skins de lancement", "custom-skins": "Skins personnalisé", "add-skin": "Ajouter un Skin", "save-custom-skins": "Sauvegarder le Skin personnalisé", diff --git a/public/language/fr/admin/dashboard.json b/public/language/fr/admin/dashboard.json index ae60b88b5d..df6995a46f 100644 --- a/public/language/fr/admin/dashboard.json +++ b/public/language/fr/admin/dashboard.json @@ -26,13 +26,13 @@ "updates": "Mises à jour", "running-version": "NodeBB v%1 est actuellement installé.", "keep-updated": "Assurez-vous que votre version de NodeBB est à jour pour les derniers patchs de sécurité et correctifs de bugs.", - "up-to-date": "You are up-to-date ", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-upgrade-available": "This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.", - "prerelease-warning": "This is a pre-release version of NodeBB. Unintended bugs may occur. ", + "up-to-date": "

        Votre version est à jour

        ", + "upgrade-available": "

        Une nouvelle version (v%1) est disponible. Veuillez mettre à jour NodeBB.

        ", + "prerelease-upgrade-available": "

        Votre version est dépassée. Une nouvelle version (v%1) est disponible. Veuillez mettre à jour NodeBB.

        ", + "prerelease-warning": "

        Ceci est une version préliminaire de NodeBB. Des bugs inattendus peuvent se produire.

        ", "fallback-emailer-not-found": "Email de secours introuvable!", - "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator", - "latest-lookup-failed": "Failed to look up latest available version of NodeBB", + "running-in-development": "Le forum est en mode développement. Il peut être sujet à certaines vulnérabilités, veuillez contacter votre administrateur système.", + "latest-lookup-failed": "Erreur de vérification de la dernière version disponible de NodeBB", "notices": "Informations", "restart-not-required": "Pas de redémarrage nécessaire", @@ -48,7 +48,7 @@ "restart-disabled": "La régénération et le redémarrage de votre forum ont été désactivés car vous ne semblez pas les exécuter à l'aide du serveur approprié.", "maintenance-mode": "Mode maintenance", "maintenance-mode-title": "Cliquez ici pour passer NodeBB en mode maintenance", - "dark-mode": "Dark Mode", + "dark-mode": "Mode sombre", "realtime-chart-updates": "Mises à jour des graphiques en temps réel", "active-users": "Utilisateurs actifs", @@ -91,8 +91,8 @@ "start": "Début", "end": "Fin", "filter": "Filtre", - "view-as-json": "View as JSON", - "expand-analytics": "Expand analytics", - "clear-search-history": "Clear Search History", - "clear-search-history-confirm": "Are you sure you want to clear entire search history?" + "view-as-json": "Voir le JSON", + "expand-analytics": "Développer les statistiques", + "clear-search-history": "Effacer l'historique", + "clear-search-history-confirm": "Êtes-vous sûr de vouloir effacer tout l'historique de recherche ?" } diff --git a/public/language/fr/admin/manage/categories.json b/public/language/fr/admin/manage/categories.json index 0f75ab999b..28e32bd26d 100644 --- a/public/language/fr/admin/manage/categories.json +++ b/public/language/fr/admin/manage/categories.json @@ -1,11 +1,11 @@ { - "manage-categories": "Manage Categories", - "add-category": "Add category", - "jump-to": "Jump to...", + "manage-categories": "Gérer les catégories", + "add-category": "Ajouter une catégorie", + "jump-to": "Aller à...", "settings": "Paramètres de la catégorie", - "edit-category": "Edit Category", + "edit-category": "Retour aux catégories", "privileges": "Privilèges", - "back-to-categories": "Back to categories", + "back-to-categories": "Retour aux catégories", "name": "Nom de la catégorie", "description": "Description de la catégorie", "bg-color": "Couleur d'arrière plan", @@ -19,10 +19,10 @@ "post-queue": "File d'attente", "tag-whitelist": "Liste blanche de mots clés", "upload-image": "Envoyer une image", - "upload": "Upload", + "upload": "Envoi", "delete-image": "Enlever", "category-image": "Image de la catégorie", - "image-and-icon": "Image & Icon", + "image-and-icon": "Image et icône", "parent-category": "Catégorie parente", "optional-parent-category": "Catégorie parente (optionnel)", "top-level": "Vers le haut", diff --git a/public/language/fr/admin/manage/privileges.json b/public/language/fr/admin/manage/privileges.json index b9b29d5bf3..c8ddcfed56 100644 --- a/public/language/fr/admin/manage/privileges.json +++ b/public/language/fr/admin/manage/privileges.json @@ -1,6 +1,6 @@ { - "manage-privileges": "Manage Privileges", - "discard-changes": "Discard changes", + "manage-privileges": "Gérer les privilèges", + "discard-changes": "Annuler les modifications", "global": "Global", "admin": "Admin", "group-privileges": "Privilèges de groupe", diff --git a/public/language/fr/admin/menu.json b/public/language/fr/admin/menu.json index 8d62e18051..e6af9b58c5 100644 --- a/public/language/fr/admin/menu.json +++ b/public/language/fr/admin/menu.json @@ -14,7 +14,7 @@ "manage/users": "Utilisateurs", "manage/admins-mods": "Modération", "manage/registration": "File d'inscription", - "manage/flagged-content": "Flagged Content", + "manage/flagged-content": "Contenu signalé", "manage/post-queue": "File d’attente des messages", "manage/groups": "Groupes", "manage/ip-blacklist": "Liste noire d'IPs", diff --git a/public/language/fr/admin/settings/api.json b/public/language/fr/admin/settings/api.json index cbf82947e6..fad2658239 100644 --- a/public/language/fr/admin/settings/api.json +++ b/public/language/fr/admin/settings/api.json @@ -3,27 +3,27 @@ "settings": "Paramètres", "lead-text": "À partir de cette page, vous pouvez paramétrer l'accès à l'API dans NodeBB.", "intro": "Par défaut, l'API authentifie les utilisateurs en fonction de leur cookie de session, mais NodeBB prend également en charge l'authentification du porteur via des tokens générés via cette page.", - "warning": "Be advised — treat tokens like passwords. If they are leaked, your account should be considered compromised.", + "warning": "Soyez Informé : Utiliser les jetons comme des mots de passe. S'ils sont divulgués, votre compte doit être considéré comme compromis.", "docs": "Cliquez ici pour accéder à la documentation de l'API", "require-https": "Forcer l'utilisation de l'API via HTTPS uniquement", "require-https-caveat": "Remarque: certaines installations impliquant des load balancer peuvent transmettre leurs requêtes à NodeBB via HTTP, auquel cas cette option doit rester désactivée.", "uid": "ID Utilisateur", - "token": "Token", + "token": "Jeton", "uid-help-text": "Spécifiez un ID utilisateur à associer à ce token. Si l'ID utilisateur est 0, il sera considéré comme un token maître, qui peut prendre l'identité d'autres utilisateurs en fonction du paramètre _uid", "description": "Description", - "last-seen": "Last seen", + "last-seen": "Vu pour la dernière fois", "created": "Créée", - "create-token": "Create Token", - "update-token": "Update Token", - "master-token": "Master token", + "create-token": "Créer un Jeton", + "update-token": "Mettre à jour le Jeton", + "master-token": "Jeton maître", "last-seen-never": "Cette clé n'a jamais été utilisée.", "no-description": "Aucune description spécifiée.", "actions": "Actions", "edit": "Éditer ", - "roll": "Roll", + "roll": "Jeter", - "delete-confirm": "Are you sure you wish to delete this token? It will not be recoverable.", - "roll-confirm": "Are you sure you wish to regenerate this token? The old token will be immediately revoked and will not be recoverable." + "delete-confirm": "Voulez-vous vraiment supprimer ce jeton ? Il ne sera pas récupérable.", + "roll-confirm": "Voulez-vous vraiment régénérer ce jeton ? L'ancien jeton sera immédiatement révoqué et ne sera pas récupérable." } \ No newline at end of file diff --git a/public/language/fr/admin/settings/general.json b/public/language/fr/admin/settings/general.json index 7ebebf00de..47dcf81c8c 100644 --- a/public/language/fr/admin/settings/general.json +++ b/public/language/fr/admin/settings/general.json @@ -1,13 +1,13 @@ { "general-settings": "Réglages Principaux", - "on-this-page": "On this page:", + "on-this-page": "Sur cette page:", "site-settings": "Réglages du site", "title": "Titre du site", "title.short": "Titre court", "title.short-placeholder": "Si aucun titre court n'est spécifié, le titre du site sera utilisé", "title.url": "URL du lien du titre", "title.url-placeholder": "URL du titre du site", - "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index. Note: This is not the external URL used in emails, etc. That is set by the url property in config.json", + "title.url-help": "Lorsque le titre est cliqué, il renvoi les utilisateurs à cette adresse. Si laissé vide, l'utilisateur sera envoyé à l'index du forum. Remarque : il ne s'agit pas de l'URL externe utilisée dans les e-mails, etc. Elle est définie par la propriété url dans config.json", "title.name": "Nom de votre communauté", "title.show-in-header": "Afficher le titre du site dans l'en-tête", "browser-title": "Titre dans le navigateur", @@ -18,7 +18,7 @@ "description": "Description du site", "keywords": "Mots-clés du site", "keywords-placeholder": "Mots-clés décrivant votre communauté, séparés par des virgules", - "logo-and-icons": "Site Logo & Icons", + "logo-and-icons": "Logo et icônes du site", "logo.image": "Image", "logo.image-placeholder": "Chemin vers un logo à afficher dans l'en-tête du site", "logo.upload": "Télécharger", diff --git a/public/language/fr/admin/settings/guest.json b/public/language/fr/admin/settings/guest.json index 8352c80508..f8853ee263 100644 --- a/public/language/fr/admin/settings/guest.json +++ b/public/language/fr/admin/settings/guest.json @@ -1,6 +1,6 @@ { "settings": "Paramètres", - "guest-settings": "Guest Settings", + "guest-settings": "Paramètres d'invité", "handles.enabled": "Autoriser les invités à poster", "handles.enabled-help": "Cette option affiche un nouveau champ qui permet aux invités de choisir un nom qui sera associé à chaque message qu'ils rédigent. Si désactivé, il seront simplement nommés \"Invité\".", "topic-views.enabled": "Autoriser les invités à augmenter le nombre de consultations de sujets", diff --git a/public/language/fr/admin/settings/post.json b/public/language/fr/admin/settings/post.json index 8f2c807cd7..41b9ea9b66 100644 --- a/public/language/fr/admin/settings/post.json +++ b/public/language/fr/admin/settings/post.json @@ -40,7 +40,7 @@ "teaser.last-reply": "Dernier – Affiche le dernier message, ou \"Aucune réponse\" si il n'y a pas de réponse", "teaser.first": "Premier", "showPostPreviewsOnHover": "Afficher un aperçu des messages au survol des liens", - "unread-and-recent": "Unread & Recent Settings", + "unread-and-recent": "Paramètres non lus et récents", "unread.cutoff": "Nombre de jours pour les messages non-lus", "unread.min-track-last": "Nombre minimum de messages dans le sujet avant de garder en mémoire le dernier message lu", "recent.max-topics": "Maximum de sujets récents", diff --git a/public/language/fr/admin/settings/reputation.json b/public/language/fr/admin/settings/reputation.json index a5063ef3a9..a888590efc 100644 --- a/public/language/fr/admin/settings/reputation.json +++ b/public/language/fr/admin/settings/reputation.json @@ -27,5 +27,5 @@ "flags.action-on-resolve": "Procédez comme suit lorsqu'un signalement est résolu", "flags.action-on-reject": "Procédez comme suit lorsqu'un signalement est rejeté", "flags.action.nothing": "Ne rien faire", - "flags.action.rescind": "Rescind the notification sent to moderators/administrators" + "flags.action.rescind": "Annuler la notification envoyée aux modérateurs/administrateurs" } \ No newline at end of file diff --git a/public/language/fr/admin/settings/user.json b/public/language/fr/admin/settings/user.json index 1e8fcc0d2c..e1648547fe 100644 --- a/public/language/fr/admin/settings/user.json +++ b/public/language/fr/admin/settings/user.json @@ -59,7 +59,7 @@ "max-about-me-length": "Longueur maximum du À propos de moi", "terms-of-use": "Conditions générales d'utilisation du forum (Laisser vide pour désactiver)", "user-search": "Rechercher un utilisateur", - "user-search-results-per-page": "Number of users to display in search results", + "user-search-results-per-page": "Nombre d'utilisateurs à afficher dans les résultats de recherche", "default-user-settings": "Réglages par défaut des utilisateurs", "show-email": "Afficher l'adresse e-mail", "show-fullname": "Afficher le nom complet", diff --git a/public/language/fr/email.json b/public/language/fr/email.json index f17e26ee17..161cf7ed0b 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -22,8 +22,8 @@ "reset.notify.subject": "Mot de passe modifié", "reset.notify.text1": "Nous vous informons que le %1, votre mot de passe a été modifié.", "reset.notify.text2": "Si vous n'avez pas autorisé ceci, veuillez contacter immédiatement un administrateur.", - "digest.unread-rooms": "Unread rooms", - "digest.room-name-unreadcount": "%1 (%2 unread)", + "digest.unread-rooms": "Discussions Non-Lus", + "digest.room-name-unreadcount": "%1 (%2 non lu)", "digest.latest_topics": "Derniers sujets de %1 :", "digest.top-topics": "Meilleurs sujets de %1", "digest.popular-topics": "Sujets populaires de %1", diff --git a/public/language/fr/modules.json b/public/language/fr/modules.json index 0f773f5e32..31b7833088 100644 --- a/public/language/fr/modules.json +++ b/public/language/fr/modules.json @@ -61,10 +61,10 @@ "chat.kick": "Exclure", "chat.show-ip": "Voir IP", "chat.owner": "Espace Admin", - "chat.grant-rescind-ownership": "Grant/Rescind Ownership", - "chat.system.user-join": "%1 has joined the room ", - "chat.system.user-leave": "%1 has left the room ", - "chat.system.room-rename": "%2 has renamed this room to \"%1\" ", + "chat.grant-rescind-ownership": "Promouvoir/rétrograder comme propriétaire", + "chat.system.user-join": "%1 a rejoint la discussion ", + "chat.system.user-leave": "%1 a quitté la discussion ", + "chat.system.room-rename": "%2 a renommé cette discussion en \"%1\" ", "composer.compose": "Écrire", "composer.show_preview": "Afficher l'aperçu", "composer.hide_preview": "Masquer l'aperçu", diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index ccfd7a11a6..582860ef1c 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -43,7 +43,7 @@ "wrote-ago": "écrit ", "wrote-on": "a écrit sur ", "replied-to-user-ago": "a répondu à %3 ", - "replied-to-user-on": "replied to %3 on ", + "replied-to-user-on": "a répondu à %3 le ", "user-locked-topic-ago": "%1 a verrouillé ce sujet %2", "user-locked-topic-on": "%1 a verrouillé ce sujet sur %2", "user-unlocked-topic-ago": "%1 a déverrouillé ce sujet %2", @@ -164,7 +164,7 @@ "composer.schedule": "Planification", "composer.replying_to": "En réponse à %1", "composer.new_topic": "Nouveau sujet", - "composer.editing-in": "Editing post in %1", + "composer.editing-in": "Modification du message dans %1", "composer.uploading": "envoi en cours…", "composer.thumb_url_label": "Coller une URL de vignette du sujet", "composer.thumb_title": "Ajouter une vignette à ce sujet", From 5d030a7730b0ec0a71f4c785cb77d179ed80b914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 13 Aug 2023 10:30:23 -0400 Subject: [PATCH 286/300] chore: up harmony/composer --- install/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/package.json b/install/package.json index db6d6fd424..9c9c708a42 100644 --- a/install/package.json +++ b/install/package.json @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.2.1", - "nodebb-plugin-composer-default": "10.2.9", + "nodebb-plugin-composer-default": "10.2.10", "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.4.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.33", + "nodebb-theme-harmony": "1.1.34", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", "nodebb-theme-persona": "13.2.17", From c9663718443eef79e0c7f7a70070d647c5cfc2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 13 Aug 2023 10:41:09 -0400 Subject: [PATCH 287/300] chore: up composer --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 9c9c708a42..f41fb43e6d 100644 --- a/install/package.json +++ b/install/package.json @@ -92,7 +92,7 @@ "multiparty": "4.2.3", "nconf": "0.12.0", "nodebb-plugin-2factor": "7.2.1", - "nodebb-plugin-composer-default": "10.2.10", + "nodebb-plugin-composer-default": "10.2.11", "nodebb-plugin-dbsearch": "6.2.0", "nodebb-plugin-emoji": "5.1.3", "nodebb-plugin-emoji-android": "4.0.0", From 2a1e33dd95fe01d027420d54fa42b0ffe9d5dbce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 13 Aug 2023 16:08:42 -0400 Subject: [PATCH 288/300] fix(deps): update dependency autoprefixer to v10.4.15 (#11907) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f41fb43e6d..f0c89136b7 100644 --- a/install/package.json +++ b/install/package.json @@ -37,7 +37,7 @@ "ace-builds": "1.24.0", "archiver": "5.3.1", "async": "3.2.4", - "autoprefixer": "10.4.14", + "autoprefixer": "10.4.15", "bcryptjs": "2.4.3", "benchpressjs": "2.5.1", "body-parser": "1.20.2", From 6f3b7bc8efbfc081507b205d216db1faa025738a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 13 Aug 2023 16:08:51 -0400 Subject: [PATCH 289/300] chore(deps): update dependency lint-staged to v13.3.0 (#11908) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index f0c89136b7..afcf7fd080 100644 --- a/install/package.json +++ b/install/package.json @@ -162,7 +162,7 @@ "grunt-contrib-watch": "1.1.0", "husky": "8.0.3", "jsdom": "22.1.0", - "lint-staged": "13.2.3", + "lint-staged": "13.3.0", "mocha": "10.2.0", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", From 282306bd2ed98652b5fb0b61cf472aa664cb42e0 Mon Sep 17 00:00:00 2001 From: Misty Release Bot Date: Mon, 14 Aug 2023 09:19:15 +0000 Subject: [PATCH 290/300] Latest translations and fallbacks --- public/language/it/admin/dashboard.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/language/it/admin/dashboard.json b/public/language/it/admin/dashboard.json index a4c83d4091..53bef3d279 100644 --- a/public/language/it/admin/dashboard.json +++ b/public/language/it/admin/dashboard.json @@ -93,6 +93,6 @@ "filter": "Filtro", "view-as-json": "Visualizza come JSON", "expand-analytics": "Espandi l'analisi", - "clear-search-history": "Clear Search History", - "clear-search-history-confirm": "Are you sure you want to clear entire search history?" + "clear-search-history": "Cancella cronologia delle ricerche", + "clear-search-history-confirm": "Sei sicuro di voler cancellare l'intera cronologia delle ricerche?" } From d9e08e05d132ed61fbb45436e83fb29de6ce30f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:36:30 -0400 Subject: [PATCH 291/300] fix(deps): update dependency esbuild to v0.19.2 (#11910) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index afcf7fd080..c38066a85b 100644 --- a/install/package.json +++ b/install/package.json @@ -63,7 +63,7 @@ "csrf-sync": "4.0.1", "daemon": "1.1.0", "diff": "5.1.0", - "esbuild": "0.19.1", + "esbuild": "0.19.2", "express": "4.18.2", "express-session": "1.17.3", "express-useragent": "1.0.15", From ee78b41891ca5be5e5592d9c01a920397cea2b31 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:39:44 -0400 Subject: [PATCH 292/300] chore(deps): update dependency lint-staged to v14 (#11909) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index c38066a85b..e13c827fcd 100644 --- a/install/package.json +++ b/install/package.json @@ -162,7 +162,7 @@ "grunt-contrib-watch": "1.1.0", "husky": "8.0.3", "jsdom": "22.1.0", - "lint-staged": "13.3.0", + "lint-staged": "14.0.0", "mocha": "10.2.0", "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", From c83a70236cc60ba51e325331e9d8084c7dbd20cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 14 Aug 2023 22:43:36 -0400 Subject: [PATCH 293/300] chore: up harmony --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index e13c827fcd..954d240ebb 100644 --- a/install/package.json +++ b/install/package.json @@ -101,7 +101,7 @@ "nodebb-plugin-ntfy": "1.4.0", "nodebb-plugin-spam-be-gone": "2.1.1", "nodebb-rewards-essentials": "0.2.3", - "nodebb-theme-harmony": "1.1.34", + "nodebb-theme-harmony": "1.1.35", "nodebb-theme-lavender": "7.1.3", "nodebb-theme-peace": "2.1.10", "nodebb-theme-persona": "13.2.17", From ffa8b72910d6bfebebdb81d77bf3111a6377d795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 15 Aug 2023 01:46:24 -0400 Subject: [PATCH 294/300] chore: up emoji --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 954d240ebb..73a6613810 100644 --- a/install/package.json +++ b/install/package.json @@ -94,7 +94,7 @@ "nodebb-plugin-2factor": "7.2.1", "nodebb-plugin-composer-default": "10.2.11", "nodebb-plugin-dbsearch": "6.2.0", - "nodebb-plugin-emoji": "5.1.3", + "nodebb-plugin-emoji": "5.1.5", "nodebb-plugin-emoji-android": "4.0.0", "nodebb-plugin-markdown": "12.1.7", "nodebb-plugin-mentions": "4.3.4", From 6476c4b832e46ab7084ed6d5ea2a3f8c81ceed96 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:33:53 -0400 Subject: [PATCH 295/300] fix(deps): update dependency cron to v2.4.1 (#11911) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 73a6613810..7b6913a2be 100644 --- a/install/package.json +++ b/install/package.json @@ -58,7 +58,7 @@ "connect-pg-simple": "9.0.0", "connect-redis": "7.1.0", "cookie-parser": "1.4.6", - "cron": "2.4.0", + "cron": "2.4.1", "cropperjs": "1.5.13", "csrf-sync": "4.0.1", "daemon": "1.1.0", From 7f6865cc2b786bad74af80c4090139a1960dcd5a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:34:04 -0400 Subject: [PATCH 296/300] chore(deps): update dependency smtp-server to v3.13.0 (#11913) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 7b6913a2be..7abab422e3 100644 --- a/install/package.json +++ b/install/package.json @@ -167,7 +167,7 @@ "mocha-lcov-reporter": "1.3.0", "mockdate": "3.0.5", "nyc": "15.1.0", - "smtp-server": "3.12.0" + "smtp-server": "3.13.0" }, "optionalDependencies": { "sass-embedded": "1.64.2" From 4a97ee0f8e4cda5dc8aae2553692cd1930d940e2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:34:14 -0400 Subject: [PATCH 297/300] fix(deps): update dependency ace-builds to v1.24.1 (#11914) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 7abab422e3..4a21993a69 100644 --- a/install/package.json +++ b/install/package.json @@ -34,7 +34,7 @@ "@fortawesome/fontawesome-free": "6.4.2", "@isaacs/ttlcache": "1.4.1", "@popperjs/core": "2.11.8", - "ace-builds": "1.24.0", + "ace-builds": "1.24.1", "archiver": "5.3.1", "async": "3.2.4", "autoprefixer": "10.4.15", From 980e0a3a71be7d0eb32423fe99564e6993950cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 15 Aug 2023 15:06:28 -0400 Subject: [PATCH 298/300] wait for images to load before scrolling to bottom --- install/package.json | 1 + public/src/client/chats.js | 12 +++++++----- public/src/client/chats/messages.js | 14 +++++++++++--- public/src/modules/chat.js | 4 ++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/install/package.json b/install/package.json index 4a21993a69..391a7f14e6 100644 --- a/install/package.json +++ b/install/package.json @@ -72,6 +72,7 @@ "graceful-fs": "4.2.11", "helmet": "7.0.0", "html-to-text": "9.0.5", + "imagesloaded": "5.0.0", "ipaddr.js": "2.1.0", "jquery": "3.7.0", "jquery-deserialize": "2.0.0", diff --git a/public/src/client/chats.js b/public/src/client/chats.js index c8743f9d80..997092b53e 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -62,8 +62,9 @@ define('forum/chats', [ } Chats.initialised = true; - messages.scrollToBottom($('[component="chat/message/content"]')); - messages.wrapImagesInLinks($('[component="chat/message/content"]')); + const changeContentEl = $('[component="chat/message/content"]'); + messages.wrapImagesInLinks(changeContentEl); + messages.scrollToBottomAfterImageLoad(changeContentEl); create.init(); hooks.fire('action:chat.loaded', $('.chats-full')); @@ -283,11 +284,12 @@ define('forum/chats', [ // https://stackoverflow.com/questions/454202/creating-a-textarea-with-auto-resize const textarea = parent.find('[component="chat/input"]'); textarea.on('input', function () { - const isAtBottom = messages.isAtBottom(parent.find('[component="chat/message/content"]')); + const chatContentEl = parent.find('[component="chat/message/content"]'); + const isAtBottom = messages.isAtBottom(chatContentEl); textarea.css({ height: 0 }); textarea.css({ height: messages.calcAutoTextAreaHeight(textarea) + 'px' }); if (isAtBottom) { - messages.scrollToBottom(parent.find('[component="chat/message/content"]')); + messages.scrollToBottom(chatContentEl); } }); }; @@ -526,7 +528,7 @@ define('forum/chats', [ Chats.setActive(roomId); Chats.addEventListeners(); hooks.fire('action:chat.loaded', $('.chats-full')); - messages.scrollToBottom(mainWrapper.find('[component="chat/message/content"]')); + messages.scrollToBottomAfterImageLoad(mainWrapper.find('[component="chat/message/content"]')); if (history.pushState) { history.pushState({ url: url, diff --git a/public/src/client/chats/messages.js b/public/src/client/chats/messages.js index fc875fea04..f8adbeae5e 100644 --- a/public/src/client/chats/messages.js +++ b/public/src/client/chats/messages.js @@ -3,9 +3,9 @@ define('forum/chats/messages', [ 'components', 'hooks', 'bootbox', 'alerts', - 'messages', 'api', 'forum/topic/images', + 'messages', 'api', 'forum/topic/images', 'imagesloaded', ], function ( - components, hooks, bootbox, alerts, messagesModule, api, images + components, hooks, bootbox, alerts, messagesModule, api, images, imagesLoaded ) { const messages = {}; @@ -95,7 +95,7 @@ define('forum/chats/messages', [ newMessage.appendTo(chatContentEl); messages.onMessagesAddedToDom(newMessage); if (isAtBottom || msgData.self) { - messages.scrollToBottom(chatContentEl); + messages.scrollToBottomAfterImageLoad(chatContentEl); // remove some message elements if there are too many const chatMsgEls = chatContentEl.find('[data-mid]'); if (chatMsgEls.length > 150) { @@ -137,6 +137,14 @@ define('forum/chats/messages', [ return distanceToBottom < (threshold || 100); } }; + messages.scrollToBottomAfterImageLoad = function (containerEl) { + if (containerEl && containerEl.length) { + const msgBodyEls = containerEl[0].querySelectorAll('[component="chat/message/body"]'); + imagesLoaded(msgBodyEls, () => { + messages.scrollToBottom(containerEl); + }); + } + }; messages.scrollToBottom = function (containerEl) { if (containerEl && containerEl.length) { diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 31f81927a0..23e0b67f6b 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -209,7 +209,7 @@ define('chat', [ if (modal.is(':visible')) { taskbar.updateActive(modal.attr('data-uuid')); if (ChatsMessages.isAtBottom(modal.find('[component="chat/message/content"]'))) { - ChatsMessages.scrollToBottom(modal.find('[component="chat/message/content"]')); + ChatsMessages.scrollToBottomAfterImageLoad(modal.find('[component="chat/message/content"]')); } } else if (!ajaxify.data.template.chats) { module.toggleNew(modal.attr('data-uuid'), true, true); @@ -453,7 +453,7 @@ define('chat', [ const chatModal = $('.chat-modal[data-uuid="' + uuid + '"]'); chatModal.removeClass('hide'); taskbar.updateActive(uuid); - ChatsMessages.scrollToBottom(chatModal.find('.chat-content')); + ChatsMessages.scrollToBottomAfterImageLoad(chatModal.find('.chat-content')); module.focusInput(chatModal); const roomId = chatModal.attr('data-roomid'); api.del(`/chats/${roomId}/state`, {}); From a013b16128eaf33c7636ae52bece3625d461f743 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 10:18:23 -0400 Subject: [PATCH 299/300] fix(deps): update dependency sharp to v0.32.5 (#11916) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 391a7f14e6..a8a9421f7a 100644 --- a/install/package.json +++ b/install/package.json @@ -128,7 +128,7 @@ "sass": "1.65.1", "semver": "7.5.4", "serve-favicon": "2.5.0", - "sharp": "0.32.4", + "sharp": "0.32.5", "sitemap": "7.1.1", "socket.io": "4.7.2", "socket.io-client": "4.7.2", From eafa03ab567fd49f480291f7809c26ba796038e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 10:18:40 -0400 Subject: [PATCH 300/300] fix(deps): update dependency postcss to v8.4.28 (#11915) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index a8a9421f7a..1b0e6b64fa 100644 --- a/install/package.json +++ b/install/package.json @@ -114,7 +114,7 @@ "passport-local": "1.0.0", "pg": "8.11.2", "pg-cursor": "2.10.2", - "postcss": "8.4.27", + "postcss": "8.4.28", "postcss-clean": "1.2.0", "progress-webpack-plugin": "1.0.16", "prompt": "1.3.0",