diff --git a/src/app/chatMetadata.js b/src/app/chatMetadata.js
index 92fc1ce..c1a1d6a 100644
--- a/src/app/chatMetadata.js
+++ b/src/app/chatMetadata.js
@@ -26,8 +26,9 @@ class chatMetadata{
* @param {String} msg - Contents of the message, with links replaced with numbered file-seperator markers
* @param {String} type - Message Type Identifier, used for client-side processing.
* @param {Array} links - Array of URLs/Links included in the message.
+ * @param {Number} timestamp - UTC Epoch from when message was sent
*/
- constructor(user, flair, highLevel, msg, type, links){
+ constructor(user, flair, highLevel, msg, type, links, timestamp = Date.now()){
/**
* Name of user who sent the message
*/
@@ -57,6 +58,11 @@ class chatMetadata{
* Array of URLs/Links included in the message.
*/
this.links = links;
+
+ /**
+ * Datetime message was sent
+ */
+ this.timestamp = timestamp;
}
}
diff --git a/src/schemas/channel/chatSchema.js b/src/schemas/channel/chatSchema.js
index abeb9ab..641cd32 100644
--- a/src/schemas/channel/chatSchema.js
+++ b/src/schemas/channel/chatSchema.js
@@ -51,6 +51,10 @@ const chatSchema = new mongoose.Schema({
type: [linkSchema],
required: true,
},
+ timestamp: {
+ type: mongoose.SchemaTypes.Number,
+ default: Date.now()
+ }
});
module.exports = chatSchema;
\ No newline at end of file
diff --git a/src/views/partial/panels/settings.ejs b/src/views/partial/panels/settings.ejs
index b0c9e9b..a467288 100644
--- a/src/views/partial/panels/settings.ejs
+++ b/src/views/partial/panels/settings.ejs
@@ -16,7 +16,7 @@ along with this program. If not, see . %>
Client Settings
-
Playeback Settings
+
Playback Settings
Youtube Player Type:
+
+
Chat nameplate:
+
+
+
+
+
+
Aspect Ratio Lock Limiter:
diff --git a/www/css/channel.css b/www/css/channel.css
index 728201b..bd96277 100644
--- a/www/css/channel.css
+++ b/www/css/channel.css
@@ -13,6 +13,10 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .*/
+:root{
+ --chat-entry-flex-direction: row;
+}
+
body{
height: 100%;
}
@@ -169,11 +173,23 @@ p.panel-head-element{
display: flex;
align-content: center;
font-size: 10pt;
+ flex-direction: var(--chat-entry-flex-direction);
+}
+
+.chat-entry-nameplate, .pm-panel-sesh-entry-nameplate{
+ display: flex;
}
.chat-entry-username, .pm-panel-sesh-entry-username{
margin: auto 0.2em auto 0;
text-wrap: nowrap;
+ width: 100%;
+}
+
+.chat-entry-timestamp, .pm-panel-sesh-entry-timestamp{
+ /* Yeah, yeah, I know, it's gross to use float over flex XP*/
+ float: right;
+ font-size: 8pt;
}
.chat-entry-body, .pm-panel-sesh-entry-body{
diff --git a/www/css/panel/settings.css b/www/css/panel/settings.css
index 2b4f64a..0acb581 100644
--- a/www/css/panel/settings.css
+++ b/www/css/panel/settings.css
@@ -44,7 +44,6 @@ along with this program. If not, see .*/
.settings-panel-setting input[type=checkbox]{
flex: 0 0 auto;
width: auto;
- margin: auto;
}
.settings-panel-setting input[type=number]{
diff --git a/www/css/theme/movie-night.css b/www/css/theme/movie-night.css
index 78c6cbb..5e4d372 100644
--- a/www/css/theme/movie-night.css
+++ b/www/css/theme/movie-night.css
@@ -542,6 +542,10 @@ select.panel-head-element{
text-decoration-color: var(--danger0-alt0);
}
+.chat-entry-timestamp, .pm-panel-sesh-entry-timestamp{
+ color: var(--accent0-alt1);
+}
+
/* popup */
.popup-backer{
diff --git a/www/css/theme/the-network-classic.css b/www/css/theme/the-network-classic.css
index 6591897..5d231a9 100644
--- a/www/css/theme/the-network-classic.css
+++ b/www/css/theme/the-network-classic.css
@@ -452,6 +452,10 @@ p.channel-guide-entry-item{
background-color: var(--bg1-alt0);
}
+.chat-entry-timestamp, .pm-panel-sesh-entry-timestamp{
+ color: var(--accent0-alt0);
+}
+
.serverwhisper{
color: var(--accent0-alt1)
}
diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js
index 13d2bda..010c343 100644
--- a/www/js/channel/channel.js
+++ b/www/js/channel/channel.js
@@ -327,6 +327,26 @@ class channel{
//Set theme
ThemeManager.setTheme(value);
//We're fuckin' done here
+ return;
+ case 'nameplateFormat':
+ switch(value){
+ //If we're throwin' the nameplate to the left
+ case 'left':
+ console.log("FUCK")
+ document.body.style.setProperty("--chat-entry-flex-direction", "row");
+ break;
+ //If we're throwin' er' up top, or someones bein' some sorta smartass
+ default:
+ document.body.style.setProperty("--chat-entry-flex-direction", "column");
+ break;
+ }
+
+ //If the chatbox is loaded in
+ if(this.chatBox != null){
+ //Re render any existing chats
+ this.chatBox.rerenderBuffer();
+ }
+
return;
case 'chatWidthMin':
//If the chat isn't loaded
@@ -391,6 +411,7 @@ class channel{
["liveSyncTolerance", 10],
["syncDelta", 6],
["theme", "The Network (Classic)"],
+ ["nameplateFormat", "left"],
["chatWidthMin", 20],
["disablePortrait", false],
["disableSendButton", false],
diff --git a/www/js/channel/chat.js b/www/js/channel/chat.js
index b297963..88b271b 100644
--- a/www/js/channel/chat.js
+++ b/www/js/channel/chat.js
@@ -680,4 +680,24 @@ class chatBox{
this.chatBuffer.scrollTop = this.chatBuffer.scrollHeight - Math.round(this.chatBuffer.getBoundingClientRect().height);
}
}
+
+ /**
+ * Re-render buffer from raw data (useful for settings changes)
+ */
+ rerenderBuffer(){
+ //Yank existing messages from buffer, converting nodelist to array to avoid annoying behavior in for loops
+ const buffer = Array.from(this.chatBuffer.children);
+
+ //Iterate through all received messages
+ for(const message of buffer){
+ //Pull raw message data from saved message
+ const rawData = JSON.parse(message.dataset.rawData);
+
+ //Nuke the message
+ message.remove();
+
+ //Re-render chat out to the buffer
+ this.displayChat(rawData);
+ }
+ }
}
\ No newline at end of file
diff --git a/www/js/channel/chatPostprocessor.js b/www/js/channel/chatPostprocessor.js
index 1ab660c..50c37eb 100644
--- a/www/js/channel/chatPostprocessor.js
+++ b/www/js/channel/chatPostprocessor.js
@@ -97,8 +97,9 @@ class chatPostprocessor{
const classSuffix = pm ? 'pm-panel-sesh' : 'chat';
const classSuffixAlt = pm ? classSuffix : 'chat-panel';
- //Create chat-entry span
+ //Create chat-entry span, and store raw message data
this.chatEntry = document.createElement('span');
+ this.chatEntry.dataset.rawData = JSON.stringify(this.rawData);
//Add classes to classlist
this.chatEntry.classList.add(
@@ -108,11 +109,19 @@ class chatPostprocessor{
`${classSuffix}-${color}`
);
+ //Create Date object from message timestamp
+ let timestamp = new Date(this.rawData.timestamp);
+
+ //Create nameplate span to hold username and high level
+ let nameplate = document.createElement('span');
+ nameplate.classList.add(`${classSuffixAlt}-buffer`, `${classSuffix}-entry-nameplate`, );
+ nameplate.title = timestamp.toLocaleString();
+
//Create high-level label
let highLevel = document.createElement('p');
highLevel.classList.add(`${classSuffixAlt}-buffer`,`${classSuffix}-entry-high-level`,"high-level");
highLevel.textContent = utils.unescapeEntities(`${this.rawData.highLevel}`);
- this.chatEntry.appendChild(highLevel);
+ nameplate.appendChild(highLevel);
//If we're not using classic flair
if(this.rawData.flair != "classic"){
@@ -120,7 +129,7 @@ class chatPostprocessor{
flair = `flair-${this.rawData.flair}`;
}
- //Create username label
+ //Create username label to the nameplate
let userLabel = document.createElement('p');
userLabel.classList.add(`${classSuffixAlt}-buffer`, `${classSuffix}-entry-username`, );
@@ -129,11 +138,25 @@ class chatPostprocessor{
flairSpan.classList.add(`${classSuffix}-entry-flair-span`, flair);
flairSpan.innerHTML = this.rawData.user;
- //Inject flair span into user label before the colon
- userLabel.innerHTML = `${flairSpan.outerHTML}: `;
+ let colonSpan = document.createElement('span');
+ colonSpan.classList.add(`${classSuffix}-entry-colon-span`);
+ if(localStorage.getItem('nameplateFormat') == "left"){
+ colonSpan.innerHTML = ': ';
+ }else if(localStorage.getItem('nameplateFormat') == "timestamp"){
+ colonSpan.classList.add(`${classSuffix}-entry-timestamp`);
+ colonSpan.innerHTML = ` (${timestamp.toLocaleString()})`;
+ }
- //Append user label
- this.chatEntry.appendChild(userLabel);
+
+ //Append flair and colon(or timestamp) spans to userLabel
+ userLabel.appendChild(flairSpan);
+ userLabel.appendChild(colonSpan);
+
+ //Append user label to the nameplate
+ nameplate.appendChild(userLabel);
+
+ //Append nameplate to the chat entry
+ this.chatEntry.appendChild(nameplate);
//Create chat body
this.chatBody = document.createElement('p');
diff --git a/www/js/channel/panels/settingsPanel.js b/www/js/channel/panels/settingsPanel.js
index 62daf0e..f244114 100644
--- a/www/js/channel/panels/settingsPanel.js
+++ b/www/js/channel/panels/settingsPanel.js
@@ -62,6 +62,11 @@ class settingsPanel extends panelObj{
*/
this.theme = this.panelDocument.querySelector("#settings-panel-theme");
+ /**
+ * Chat nameplate format
+ */
+ this.nameplateFormat = this.panelDocument.querySelector("#settings-panel-nameplate-format");
+
/**
* Chat Width Minimum while Size-Locked to Media Aspect Ratio
*/
@@ -144,6 +149,7 @@ class settingsPanel extends panelObj{
this.liveSyncTolerance.addEventListener('change', this.updateLiveSyncTolerance.bind(this));
this.syncDelta.addEventListener('change', this.updateSyncDelta.bind(this));
this.theme.addEventListener('change', this.updateTheme.bind(this));
+ this.nameplateFormat.addEventListener('change', this.updateNameplateFormat.bind(this));
this.chatWidthMinimum.addEventListener('change', this.updateChatWidthMinimum.bind(this));
this.disablePortrait.addEventListener('change', this.updateDisablePortrait.bind(this));
this.disableSendButton.addEventListener('change', this.updateDisableSendButton.bind(this));
@@ -163,6 +169,7 @@ class settingsPanel extends panelObj{
this.liveSyncTolerance.value = localStorage.getItem("liveSyncTolerance");
this.syncDelta.value = localStorage.getItem("syncDelta");
this.theme.querySelector('select').value = localStorage.getItem("theme");
+ this.nameplateFormat.querySelector('select').value = localStorage.getItem("nameplateFormat");
this.chatWidthMinimum.value = localStorage.getItem("chatWidthMin");
this.disablePortrait.checked = localStorage.getItem("disablePortrait") == 'true';
this.disableSendButton.checked = localStorage.getItem("disableSendButton") == 'true';
@@ -261,6 +268,15 @@ class settingsPanel extends panelObj{
client.processConfig("theme", theme);
}
+ /**
+ * Update nameplate format
+ */
+ updateNameplateFormat(){
+ let format = this.nameplateFormat.querySelector('select').value;
+ localStorage.setItem("nameplateFormat", format);
+ client.processConfig("nameplateFormat", format);
+ }
+
/**
* Handles Chat Width minimum Changes
*/