Skip to content

Commit 7af3a86

Browse files
authored
Update unity-forum-fixer.js
1 parent 2ed70df commit 7af3a86

File tree

1 file changed

+181
-70
lines changed

1 file changed

+181
-70
lines changed

unity-forum-fixer.js

Lines changed: 181 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// ==UserScript==
22
// @name UnityForumFixer
33
// @namespace https://unitycoder.com/
4-
// @version 0.1 (21.08.2024)
5-
// @description Fixes For Unity Forums
4+
// @version 0.3 (23.08.2024)
5+
// @description Fixes For Unity Forums - https://github.com/unitycoder/UnityForumFixer
66
// @author unitycoder.com
77
// @match https://discussions.unity.com/*
88
// @grant none
@@ -17,26 +17,37 @@
1717

1818
AppendCustomCSS();
1919
AddAssetStoreLink();
20-
// ShowOriginalPosterInfo(); // TODO needs some css adjustments for name location
21-
//setTimeout(test, 1000);
20+
NavBar();
21+
TopicsViewShowOriginalPosterInfo(); // TODO needs some css adjustments for name location
2222
FixPostActivityTime();
23+
PostViewShowOriginalPosterInfo();
24+
2325
setTimeout(OnUpdate, 1000); // run loop to update activity times (since some script changes them back to original..)
24-
NavBar();
2526
});
2627
})();
2728

29+
// runs every second to update things (if you scroll the page, need to update new data)
30+
// TODO could be better to catch page change/update some other way (xhrevent, mutation..), since it doesnt update now if click some item (like open post)
2831
function OnUpdate()
2932
{
3033
FixPostActivityTime();
34+
TopicsViewShowOriginalPosterInfo();
3135
setTimeout(OnUpdate, 1000);
3236
}
3337

38+
39+
3440
function AppendCustomCSS()
3541
{
3642

3743
var style = document.createElement('style');
3844
style.textContent =
3945
`
46+
// latest posts view
47+
.show-more.has-topics { width: 35%;!important;} /* updated topics alert */
48+
.alert.alert-info.clickable {width: 35%; padding:3px !important;} /* updated topics alert */
49+
50+
4051
.wrap.custom-search-banner-wrap h1 {display: none;} /* hide welcome banner */
4152
.wrap.custom-search-banner-wrap {padding:0px;} /* remove search bar padding */
4253
:root {--d-background-image: none !important;} /* hide big bg image */
@@ -54,23 +65,51 @@ function AppendCustomCSS()
5465
.title.raw-link.raw-topic-link:hover {color: rgb(82,132,189) !important; text-decoration: underline !important;} /*post title hover */
5566
.topic-list .topic-list-data:first-of-type {padding-left: 8px !important;} /* post topic rows, half the padding */
5667
.discourse-tags {font-size: 0.8em !important;} /* tags below post title, smaller */
57-
.post-activity {font-size: 0.9em !important;}
68+
.relative-date {font-size: 0.9em !important; color: rgb(150, 150, 150) !important;}
5869
.ember-view.bread-crumbs-left-outlet.breadcrumb-label {display: none !important;} /* "… or filter the topics via" */
5970
.navigation-container {--nav-space: 0 !important; padding-bottom: 6px;} /* navbar adjustments */
6071
.category-breadcrumb.ember-view {width:auto !important;} /* areas,categories,tags not 100% width */
6172
.navigation-controls { display: flex; justify-content: flex-end; width: 100%; } /* move new topic button to right, still would be nice to have in same row as other nav */
6273
.select-kit-row .desc { font-size: 0.92em !important; margin-top:1px; color: #777777 !important; } /* new topic dropdown descriptions */
6374
6475
.custom-search-banner-wrap > div {max-width:100% !important;} /* search bar maxwidth, need to find better location later */
65-
.sidebar-wrapper {width: 222px !important; font-size: 0.99em !important;} /* sidebar */
76+
.sidebar-wrapper {font-size: 0.99em !important;} /* sidebar */
6677
.sidebar-section-header-wrapper.sidebar-row {padding:4px !important;} /* sidebar headers bit to the left */
6778
.ember-view.sidebar-section-link.sidebar-row {height:25px !important;} /* sidebar row heights */
6879
.sidebar-section-link-prefix .svg-icon {height: 12px !important; width: 12px !important;} /* sidebar icons smaller */
6980
81+
/* post view, username */
82+
.user-name { margin-bottom: 5px; font-weight: bold; text-align: center; font-size: 0.9em; color: var(--primary); text-decoration: none; display: block; word-wrap: break-word; white-space: normal; width: 100%; }
83+
.user-name:hover { color: rgb(82,132,189); text-decoration: underline; }
84+
.names.trigger-user-card {visibility: hidden !important;}
85+
.row { display: flex; }
86+
.topic-avatar { flex-basis: 10%; margin:0 !important; }
87+
.topic-body { flex-basis: 90%; } /* Ensure the main content adjusts accordingly */
88+
.topic-avatar {background-color: #d1d1d132;}
89+
.post-avatar { display: flex; flex-direction: column; align-items: center; }
90+
/*.avatar { margin: 4px; } bug in topic view*/
91+
.topic-body {padding: 0 !important;}
92+
.topic-map.--op {display: none !important;} /* hide view count under op post, could move it somewhere else later */
93+
94+
.more-topics__container {display:none !important;} /* hide suggested topics at bottom */
95+
/* unity footer & content - could hide it.. but then unity is sad*/
96+
.unity-footer {font-size:0.7em !important; line-height: none !important; padding:0 !important; text-align:center !important;}
97+
.footer.unity-footer .unity-footer-content {padding-left:10px !important; line-height: 12px !important;}
98+
.unity-footer-content { display: flex; flex-direction: column; align-items: center; text-align: center; }
99+
.unity-footer-menu.unity-footer-menu-legal.processed { list-style: none; padding: 0; margin: 0; display: flex; justify-content: center; }
100+
.unity-footer-menu.unity-footer-menu-legal.processed li { margin: 0 10px; }
101+
102+
103+
/* custom added fields */
104+
.original-poster-span {font: 13px/1.231 arial,helvetica,clean,sans-serif; color: rgb(150, 150, 150); } /* original poster below post title */
105+
.latest-poster-span { display: block; word-break: break-all; max-width: 100%; } /* activity, latest poster */
106+
70107
`;
71108
document.head.appendChild(style);
72109
}
73110

111+
// HEADER
112+
74113
function AddAssetStoreLink()
75114
{
76115
// Create the new list item
@@ -91,90 +130,162 @@ function AddAssetStoreLink()
91130
}
92131
}
93132

94-
function ShowOriginalPosterInfo()
133+
function NavBar()
134+
{
135+
// remove "try the" text
136+
document.querySelectorAll('div[title="Try the Product Areas"] .name').forEach(el => {
137+
if (el.textContent.trim() === "Try the Product Areas") {
138+
el.textContent = "Product Areas";
139+
}
140+
});
141+
}
142+
143+
144+
// FORUM VIEW
145+
146+
function TopicsViewShowOriginalPosterInfo()
95147
{
96-
// Select all <td> elements with the class 'posters topic-list-data'
97-
var posterCells = document.querySelectorAll('td.posters.topic-list-data');
148+
// Select all topic rows
149+
const topicRows = document.querySelectorAll('tr.topic-list-item');
98150

99-
// Loop through each <td> element
100-
posterCells.forEach(function(cell)
101-
{
102-
// Select the first <a> element with a data-user-card attribute inside the current <td>
103-
var firstUserLink = cell.querySelector('a[data-user-card]');
104-
if (firstUserLink)
105-
{
106-
// Get the value of the data-user-card attribute
107-
var userCardValue = firstUserLink.getAttribute('data-user-card');
108-
109-
// Create a new <div> element to display the user card value
110-
var userCardDiv = document.createElement('div');
111-
userCardDiv.textContent = userCardValue;
112-
userCardDiv.style.fontSize = '12px'; // Optional: make the text smaller
113-
userCardDiv.style.marginTop = '4px'; // Optional: add some space above the text
114-
115-
// Insert the new <div> below the first image
116-
firstUserLink.parentNode.insertBefore(userCardDiv, firstUserLink.nextSibling);
117-
}
118-
});
151+
topicRows.forEach(row => {
152+
// Find the first 'a' element inside the 'posters topic-list-data' cell that does not have the 'latest' class (Original Poster)
153+
let firstPosterLink = row.querySelector('td.posters.topic-list-data a:not(.latest)');
154+
155+
// If there is no such element, it might be a single poster with 'latest single' class
156+
if (!firstPosterLink) {
157+
firstPosterLink = row.querySelector('td.posters.topic-list-data a.latest.single');
158+
}
159+
160+
if (firstPosterLink) {
161+
// Extract the username from the 'data-user-card' attribute for the original poster
162+
const originalPosterUsername = firstPosterLink.getAttribute('data-user-card');
163+
164+
// Find the topic creation date from the title attribute in the activity column
165+
const activityCell = row.querySelector('td.activity');
166+
const titleText = activityCell ? activityCell.getAttribute('title') : '';
167+
const creationDateMatch = titleText.match(/Created: (.+?)(?:\n|$)/);
168+
169+
let creationDateFormatted = 'Unknown'; // Default to "Unknown" if no date is found
170+
if (creationDateMatch) {
171+
const creationDateStr = creationDateMatch[1];
172+
const creationDate = new Date(creationDateStr);
173+
creationDateFormatted = formatDateString(creationDate);
174+
}
175+
176+
// Find the 'link-bottom-line' element to insert the original poster's name and creation date before it
177+
const linkBottomLine = row.querySelector('td.main-link .link-bottom-line');
178+
if (linkBottomLine && !row.querySelector('.original-poster-span')) {
179+
// Create a new span element for the original poster's username and creation date
180+
const originalPosterSpan = document.createElement('span');
181+
originalPosterSpan.textContent = originalPosterUsername+","+creationDateFormatted;
182+
originalPosterSpan.className = 'original-poster-span'; // Adding a class to prevent duplication
183+
originalPosterSpan.style.display = 'block'; // Ensure it's placed as a block element
184+
185+
// Insert the original poster span before the link-bottom-line
186+
linkBottomLine.parentNode.insertBefore(originalPosterSpan, linkBottomLine);
187+
}
188+
}
189+
190+
// Find the most recent poster (always marked with 'latest')
191+
const latestPosterLink = row.querySelector('td.posters.topic-list-data a.latest');
192+
if (latestPosterLink) {
193+
// Extract the username from the 'data-user-card' attribute
194+
const latestPosterUsername = latestPosterLink.getAttribute('data-user-card');
195+
196+
// Find the 'post-activity' element
197+
const postActivity = row.querySelector('td.activity .post-activity');
198+
if (postActivity && !row.querySelector('.latest-poster-span')) {
199+
// Create a new span element for the latest poster's username
200+
const latestPosterSpan = document.createElement('span');
201+
latestPosterSpan.textContent = latestPosterUsername;
202+
latestPosterSpan.className = 'latest-poster-span'; // Adding a class to prevent duplication
203+
latestPosterSpan.style.display = 'block'; // Ensure it's placed as a block element
204+
205+
// Insert the latest poster span before the <a> tag, placing it outside the link
206+
postActivity.parentNode.insertBefore(latestPosterSpan, postActivity);
207+
}
208+
}
209+
});
119210
}
120211

121-
function FixPostActivityTime()
212+
function FixPostActivityTime()
122213
{
123-
document.querySelectorAll('.relative-date').forEach(function(el) {
124-
const dataTime = parseInt(el.getAttribute('data-time'), 10);
125-
if (!dataTime) return;
214+
document.querySelectorAll('.relative-date').forEach(function (el)
215+
{
216+
const dataTime = parseInt(el.getAttribute('data-time'), 10);
217+
if (!dataTime) return;
126218

127-
const date = new Date(dataTime);
128-
const now = new Date();
129-
const diffInHours = Math.floor((now - date) / (1000 * 60 * 60));
219+
const date = new Date(dataTime);
220+
const now = new Date();
221+
const diffInMinutes = Math.floor((now - date) / (1000 * 60));
222+
const diffInHours = Math.floor(diffInMinutes / 60);
130223

131-
let timeString;
132-
if (diffInHours > 6) {
133-
timeString = formatDateString(date);
224+
let timeString;
225+
if (diffInHours >= 1) {
226+
const remainingMinutes = diffInMinutes % 60;
227+
if (remainingMinutes > 0) {
228+
timeString = `${diffInHours} hour${diffInHours !== 1 ? 's' : ''} ${remainingMinutes} minute${remainingMinutes !== 1 ? 's' : ''} ago`;
134229
} else {
135-
const diffInMinutes = Math.floor((now - date) / (1000 * 60));
136-
timeString = `${diffInMinutes} minute${diffInMinutes !== 1 ? 's' : ''} ago`;
230+
timeString = `${diffInHours} hour${diffInHours !== 1 ? 's' : ''} ago`;
137231
}
232+
} else if (diffInMinutes >= 1) {
233+
timeString = `${diffInMinutes} minute${diffInMinutes !== 1 ? 's' : ''} ago`;
234+
} else {
235+
timeString = `just now`;
236+
}
138237

139-
el.textContent = timeString;
140-
});
238+
el.textContent = timeString;
239+
});
141240
}
142241

143242

243+
// POST VIEW
144244

245+
function PostViewShowOriginalPosterInfo()
246+
{
247+
// Select all elements that contain the avatar with a data-user-card attribute
248+
document.querySelectorAll('.trigger-user-card.main-avatar').forEach(function(avatar) {
249+
// Get the user name from the data-user-card attribute
250+
var userName = avatar.getAttribute('data-user-card');
251+
252+
// Create a new anchor element to wrap the user name and link to the profile
253+
var userLink = document.createElement('a');
254+
userLink.className = 'user-name';
255+
userLink.href = 'https://discussions.unity.com/u/' + userName;
256+
userLink.textContent = userName;
257+
258+
// Insert the user name link before the avatar image
259+
avatar.parentNode.insertBefore(userLink, avatar);
260+
});
261+
}
262+
263+
264+
265+
// HELPER METHODS
145266

146267
function formatDate(date)
147268
{
148-
const options = { hour: '2-digit', minute: '2-digit', hour12: false };
149-
return date.toLocaleTimeString('en-GB', options); // Format as "HH:MM"
269+
const options = { hour: '2-digit', minute: '2-digit', hour12: false };
270+
return date.toLocaleTimeString('en-GB', options); // Format as "HH:MM"
150271
}
151272

152273
function formatDateString(date)
153274
{
154-
const today = new Date();
155-
const yesterday = new Date(today);
156-
yesterday.setDate(today.getDate() - 1);
157-
const oneWeekAgo = new Date(today);
158-
oneWeekAgo.setDate(today.getDate() - 7);
159-
160-
if (date >= today.setHours(0, 0, 0, 0)) { // Today
161-
return `Today at ${formatDate(date)}`;
162-
} else if (date >= yesterday.setHours(0, 0, 0, 0)) { // Yesterday
163-
return `Yesterday at ${formatDate(date)}`;
164-
} else if (date >= oneWeekAgo) { // Within the past week
165-
const dayName = date.toLocaleDateString('en-GB', { weekday: 'long' });
166-
return `${dayName} at ${formatDate(date)}`;
167-
} else { // Older than one week
168-
return date.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
169-
}
170-
}
275+
const today = new Date();
276+
const yesterday = new Date(today);
277+
yesterday.setDate(today.getDate() - 1);
278+
const oneWeekAgo = new Date(today);
279+
oneWeekAgo.setDate(today.getDate() - 7);
171280

172-
function NavBar()
173-
{
174-
// remove "try the" text
175-
document.querySelectorAll('div[title="Try the Product Areas"] .name').forEach(el => {
176-
if (el.textContent.trim() === "Try the Product Areas") {
177-
el.textContent = "Product Areas";
281+
if (date >= today.setHours(0, 0, 0, 0)) { // Today
282+
return `Today at ${formatDate(date)}`;
283+
} else if (date >= yesterday.setHours(0, 0, 0, 0)) { // Yesterday
284+
return `Yesterday at ${formatDate(date)}`;
285+
} else if (date >= oneWeekAgo) { // Within the past week
286+
const dayName = date.toLocaleDateString('en-GB', { weekday: 'long' });
287+
return `${dayName} at ${formatDate(date)}`;
288+
} else { // Older than one week
289+
return date.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
178290
}
179-
});
180291
}

0 commit comments

Comments
 (0)