Compare commits

...

6 Commits

Author SHA1 Message Date
adb
07117763bf integrate master 2020-11-09 00:23:54 +01:00
adb
94eddf81a6 Merge remote-tracking branch 'origin/master' into chatInformations
# Conflicts:
#	src/views/chat.vue
2020-11-08 23:56:37 +01:00
adb
451b30c3f2 dynamic loaded chat and PWA 2020-11-08 23:36:13 +01:00
adb
fd4fff2a78 first working chat version 2020-11-08 15:50:18 +01:00
adb
e86f0635c1 login backend 2020-11-08 14:35:10 +01:00
adb
49aa6731df login 2020-11-07 20:31:55 +01:00
11 changed files with 152 additions and 95 deletions

41
api.js
View File

@ -21,17 +21,42 @@ const wss = new ws.Server({
});
//WS handler
let user = [];
wss.on('connection', (ws, req) => {
let thisuser = ""
console.log(`${req.socket.remoteAddress} connected`)
ws.on('message', msgJSON => {
let msg = JSON.parse(msgJSON)
console.log(`${req.socket.remoteAddress} => ${msgJSON}`)
if (msg.type === 'message') wss.clients.forEach(client => client.send(msgJSON))
console.log(`${req.socket.remoteAddress} (${thisuser}) => ${msgJSON}`)
if (msg.type === 'message')
if (thisuser === ""){
ws.send(JSON.stringify({type: "error", content: "please login before writing"}))
ws.send('{"type":"route","path":"/login"}')
}else if (msg.content.text === "")
ws.send(JSON.stringify({type: "error", content: "your message was empty"}))
else{
msg.content.user = thisuser
msg.content.text = msg.content.text.replace(/</g, "&lt").replace(/>/g, "&gt").replace(/\n/g, "<br>")
wss.clients.forEach(client => client.send(JSON.stringify(msg)))
}
else if (msg.type === 'login' && msg.content.user !== ""){
if (msg.content.user.length >= 20) ws.send(JSON.stringify({type: "error", content: "username is too long"}))
else if (msg.content.user === "you" || user.indexOf(msg.content.user) !== -1)
ws.send(JSON.stringify({type: "error", content: "username already exist"}))
else{
thisuser = msg.content.user
user.push(msg.content.user)
ws.send('{"type":"route","path":"/chat"}')
ws.send(JSON.stringify({type: "info", username: thisuser}))
wss.clients.forEach(client =>
client.send(JSON.stringify({type: "room", name: "open chat", user: user})))
}
}
})
let msg = {
type: "info",
time: Date.now(),
content: "connected"
}
ws.send(JSON.stringify(msg))
ws.on('close', () => {
user.splice(user.indexOf(thisuser), 1);
console.log(`${req.socket.remoteAddress} (${thisuser}) closed`)
})
ws.send(JSON.stringify({type: "info", time: Date.now(), content: "connected"}))
})

View File

@ -3,6 +3,10 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<!-- PWA support -->
<link rel="manifest" href="./manifest.json"/>
<meta name="theme-color" content="#2F3BA2"/>
<meta name="description" content="open chat"/>
<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0'/>
<link rel="icon" href="<%= BASE_URL %>favicon.ico"/>
<title><%= htmlWebpackPlugin.options.title %></title>

9
public/manifest.json Normal file
View File

@ -0,0 +1,9 @@
{
"name": "open chat",
"short_name": "open chat",
"start_url": "/",
"display": "standalone",
"background_color": "#14181b",
"theme_color": "#00BCD4",
"orientation": "portrait-primary"
}

Binary file not shown.

Before

(image error) Size: 4.3 KiB

View File

@ -1,28 +1,23 @@
<template>
<div class="chatInformation">
<div id="chatInformation">
<h1>open chat</h1>
<icon class="closeBtn" onclick="this.parentNode.style.display = 'none'" ic="./sym/ic_close_white_24px.svg" />
<div id="box">
<div class="informationBox">
<div class="picBoxBig"><div class="placeholderBig"><p>O P</p></div></div>
<div class="picBoxBig"><div class="placeholderBig"><p>{{chatroom.name.substr(0,2)}}</p></div></div>
<div class="roomInformation">
<div class="roomName">Open Chat room</div>
<div class="users">2 members</div>
<div class="roomName">{{chatroom.name}}</div>
<div class="users">{{chatroom.user.length}} members</div>
</div>
</div>
<div id="textMembers">Members</div>
<div class="contentBox">
<div class="picBox"><div class="picPlaceholder"><p>O P</p></div></div>
<div class="information">
<div class="userName">TechCrafter07</div>
<div class="status">Online</div>
</div>
</div>
<div class="contentBox">
<div class="picBox"><div class="picPlaceholder"><p>O P</p></div></div>
<div class="information">
<div class="userName">Alban</div>
<div class="status">Online</div>
<h2 v-if="chatroom.user.length !== 0">members</h2>
<div v-for="user in chatroom.user" :key="user">
<div class="contentBox">
<div class="picBox"><div class="picPlaceholder"><p>{{user.substr(0,2)}}</p></div></div>
<div class="information">
<div class="userName">{{user}}</div>
<div class="status">online</div>
</div>
</div>
</div>
</div>
@ -30,30 +25,38 @@
</template>
<script>
import icon from './icon.vue';
import main from '@/main.js'
export default {
name: "chatInformation",
components:{
icon
},
data(){
return {
chatroom: main.data().chatroom
}
}
}
</script>
<style scoped>
.chatInformation{
#chatInformation{
position: absolute;
left: 50%;
transform: translate(-50%, 0);
top: 5rem;
width: calc(100% - 8rem);
max-width: 30rem;
height: calc(100% - 10rem);
background-color: #1d1d1d;
box-shadow: 6px 6px 20px #111;
border-radius: 1rem;
text-align: center;
display: none;
}
@media (max-width: 30rem) {
.chatInformation{
#chatInformation{
transform: unset;
top: 0;
left: 0;
@ -71,16 +74,14 @@ export default {
#box{
position: relative;
width: calc(100% - 2rem);
background-color: #2d2d2d;
padding: 0.001rem 1rem 1rem;
overflow: auto;
overflow-y: auto;
max-height: calc(100% - 8rem);
}
.informationBox{
margin-top: 0.2rem;
height: 5rem;
padding: 0.2rem;
border-bottom: 2px solid #9c9c9c;
}
.picBoxBig{
text-align: center;
@ -107,17 +108,9 @@ export default {
font-size: 1.2rem;
color: #9c9c9c;
}
#textMembers{
font-size: 1.5rem;
text-align: left;
margin-left: 0.2rem;
margin-top: 0.3rem;
margin-bottom: 0.2rem;
}
.contentBox{
margin-top: 0.2rem;
height: 3.2rem;
border-bottom: 2px solid #9c9c9c ;
padding: 0.2rem;
max-height: 48px;
}

View File

@ -32,5 +32,6 @@ export default {
background-color: #42b983;
border-radius: 1rem 1rem 1rem 0;
text-align: left;
word-break: break-word;
}
</style>

View File

@ -9,8 +9,8 @@
</template>
<script>
import icon from './icon.vue';
import main from '../main.js';
import icon from '@/components/icon.vue';
import main from '@/main.js';
export default {
name: "newMessage",
@ -23,7 +23,10 @@ export default {
this.msg.time = Date.now()
main.methods.sendWebSocket(this.msg)
this.msg.content.text = ""
this.resizeMessageBanner()
document.getElementById("messagesContainer").style.height = "calc(100% - 7rem)"
document.getElementById("newMessageInput").style.height = "1.25rem"
let msgContainer = document.getElementById("messagesContainer")
msgContainer.scrollTo(0, msgContainer.scrollHeight)
}
},
resizeMessageBanner(){
@ -33,7 +36,6 @@ export default {
let msgContainer = document.getElementById("messagesContainer")
msgContainer.style.height
= `calc(100% - ${id.parentElement.clientHeight}px - 3rem)`
//msgContainer.scrollTo(0, msgContainer.scrollHeight)
}
},
data(){
@ -42,9 +44,11 @@ export default {
type: "message",
time: Date.now(),
content: {
user: "you",
text: ""
}
}
},
chatroom: main.data().chatroom
}
}
}
@ -67,7 +71,7 @@ export default {
margin-bottom: 1rem;
left: 2rem;
min-height: 1.25rem;
max-height: 14rem;
max-height: 10rem;
width: calc(100% - 7rem);
height: 1.25rem;
background-color: #fff0;

View File

@ -1,11 +1,13 @@
<template>
<div class="topBanner">
<div>
<icon class="smallIcon" id="icon-arrow" ic="./sym/arrow_back-24px.svg" />
<router-link to="login">
<icon class="smallIcon" id="icon-arrow" ic="./sym/arrow_back-24px.svg" />
</router-link>
<icon class="smallIcon" id="picTop" ic="./sym/supervisor_account-24px.svg" />
<div id="container">
<div id="chatName">{{roomInfo.name}}</div>
<div id="users">{{roomInfo.user.length}} members</div>
<div id="chatName">{{chatroom.name}}</div>
<div id="users">{{chatroom.user.length}} members</div>
</div>
<icon v-on:click.native="showChatInfo()" class="smallIcon" id="icon-menu" ic="./sym/menu-24px.svg" />
</div>
@ -13,6 +15,7 @@
</template>
<script>
import icon from '@/components/icon.vue';
import main from '@/main.js';
export default {
name: "topBanner",
@ -26,10 +29,7 @@ export default {
},
data(){
return {
roomInfo: {
name: "open chat",
user: []
}
chatroom: main.data().chatroom
}
}
}
@ -40,7 +40,7 @@ export default {
width: 100%;
height: 3rem;
background-color: #1d1d1d;
box-shadow: 0 3px 10px #111;
box-shadow: 0 0px 5px #111;
}
.smallIcon{
top: 0.25rem;

View File

@ -27,17 +27,22 @@ const router = new VueRouter({
]
})
new Vue({
el: '#app',
router,
template: '<App/>',
components: {App}
}).$mount('#app')
let chatroom = {
name: "open chat",
user: [],
username: "you",
messages: []
};
export default {
mounted() {
sendMessage()
},
data(){
return {
chatroom: chatroom
}
},
methods: {
sendMessage(message){
let msg = {
@ -55,9 +60,22 @@ export default {
}
}
const wsurl = 'ws://127.0.0.1:8090'
const socket = new WebSocket(wsurl)
new Vue({
el: '#app',
router,
template: '<App/>',
components: {App},
data(){
return {
chatroom: chatroom
}
}
}).$mount('#app')
const wsurl = 'ws://127.0.0.1:8090'
//const wsurl = 'wss://chat.adb.sh:8080'
const socket = new WebSocket(wsurl)
function element(id){ return document.getElementById(id)}
socket.onopen = () => {
@ -76,14 +94,15 @@ socket.onmessage = (e) => {
console.log(`data received => ${e.data}`)
let msg = JSON.parse(e.data)
if (msg.type === 'error') show_error(msg.content)
else if (msg.type === 'route') router.push({path: msg.path})
else if (msg.type === 'room'){
chatroom.user = msg.user
}
else if (msg.type === "info") chatroom.username = msg.username
else if (msg.type === 'message'){
//just for now, ik it's dirty
element('messages').innerHTML +=
`<div class="messageContainer" data-v-032da2b2="">
<div class="message" data-v-032da2b2="">
${msg.content.text}
</div>
</div>`;
chatroom.messages.push(msg)
let msgContainer = document.getElementById("messagesContainer")
if (msgContainer.scrollHeight < msgContainer.scrollTop + 1000) msgContainer.scrollTo(0, msgContainer.scrollHeight)
}
}

View File

@ -2,27 +2,15 @@
<div>
<div ref="msgContainer" id="messagesContainer" class="messagesContainer">
<div id="messages" class="messages">
<message msg="Hey :D" />
<message msg="Du bist blööööd xD" />
<messageReceive msg="Du auch" />
<message msg="lol" />
<messageReceive msg="Du bist voll blöd, ich hasse dich, warum tust du das?!" />
<message msg="Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Ut imperdiet vel risus tristique mollis. Proin aliquam felis non vehicula ornare.
Fusce scelerisque pellentesque erat quis sollicitudin.
Quisque aliquet, ligula ut volutpat vulputate, ligula lorem dictum velit, et aliquam sapien orci sed magna.
Nam suscipit ex eget urna accumsan pulvinar. Pellentesque fringilla placerat feugiat.
Aenean aliquam vestibulum metus. Nulla augue turpis, consectetur vitae quam ac, porttitor rhoncus nunc.
Nullam non turpis consequat, placerat lectus nec, ornare orci.
Fusce lorem tortor, viverra ac suscipit sit amet, scelerisque id eros.
Suspendisse et ultricies elit, vitae pretium ipsum. Suspendisse vel ex in turpis pulvinar feugiat. "
/>
<messageReceive msg="Du hast Pizza!" />
<message msg="und Kuchen :P" />
<message msg="und Kuchen :P" />
<message msg="und Kuchen :P" />
<message msg="und Kuchen :P" />
<message msg="und Kuchen :P" />
<p style="text-align: center; font-style: italic;">you entered the chat</p>
<div v-for="(message, i) in chatroom.messages" :key="message.time">
<div v-if="message.content.user !== chatroom.username && function(){
return i===0 || chatroom.messages[i-1].content.user!==message.content.user;}()"
style="margin-left: 2rem; margin-top: 1rem">{{message.content.user}}
</div>
<messageReceive v-if="message.content.user !== chatroom.username" :msg=message.content.text />
<message v-if="message.content.user === chatroom.username" :msg=message.content.text />
</div>
</div>
</div>
<newMessage />
@ -35,17 +23,23 @@
import message from '@/components/message.vue';
import messageReceive from '@/components/messageReceive.vue';
import newMessage from '@/components/newMessage.vue';
import topBanner from "@/components/topBanner";
import chatInformation from "@/components/chatInformation";
import topBanner from '@/components/topBanner.vue';
import main from '@/main.js';
import ChatInformation from "@/components/chatInformation";
export default {
name: 'chat',
components: {
ChatInformation,
message,
messageReceive,
newMessage,
topBanner,
chatInformation
topBanner
},
data(){
return {
chatroom: main.data().chatroom
}
}
}
</script>

View File

@ -5,23 +5,31 @@
<label for="longurl-input"></label>
<input v-model="session.content.user" class="input" id="longurl-input" type="text" autocomplete="off" maxlength="20" placeholder="chose nickname">
</div>
<input type="hidden" value="search" name="login">
<textbtn text="login" />
<textbtn v-on:click.native="login()" text="login" />
</div>
</template>
<script>
import textbtn from '@/components/textbtn';
import main from "@/main";
export default {
name: "login.vue",
components: {
textbtn
},
methods: {
login() {
if (this.session.content.user !== "") {
this.session.time = Date.now()
main.methods.sendWebSocket(this.session)
}
}
},
data(){
return {
session: {
type: "session",
type: "login",
time: Date.now(),
content: {
user: ""