Eduard Kuzmenko
5 years ago
41 changed files with 2531 additions and 2275 deletions
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE----- |
||||
MIIDwDCCAqigAwIBAgIJAOqEYb8IH1NQMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV |
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX |
||||
aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDEaMBgGCSqGSIb3DQEJ |
||||
ARYLcXdlQGFzZC5jb20wHhcNMjAwNDEwMTc0OTU3WhcNMjAwNTEwMTc0OTU3WjB1 |
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 |
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxGjAYBgkq |
||||
hkiG9w0BCQEWC3F3ZUBhc2QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB |
||||
CgKCAQEAxxzMhd/vxT84pEcRIIZwYKe6C00OaRZq8VErgNoOQVr8hejj7FueGjAu |
||||
io841OcJjUHCgD7Bda/cu5FLs0ATxAkBow7K9+Qzx3Gnl87ZKkxlt4xFZ6mWvDiY |
||||
hovliUL+I+ll29l2cF2PXhl8q/VEsOl0+M45d5rzT/qy3PD3H/5CwqCVnovCXe5H |
||||
BEFCf82qYAEe+J/w5KjtiqgT4fx/n0XNXES0KO/ot2PWyjGnzs+V52yf2eChmfIr |
||||
Ae7+ykRM60YwIR3HHvCiVO5XtEqB3x207ADwcQGpC0oOvuj8YB8Jj76QUfLm559/ |
||||
pNjkZR07jMReX6Pzuuf7bEsQvfkMmwIDAQABo1MwUTAdBgNVHQ4EFgQUpn8Hwa3D |
||||
qFgdzvB62FYygrvZSlcwHwYDVR0jBBgwFoAUpn8Hwa3DqFgdzvB62FYygrvZSlcw |
||||
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAQYb7MFbTQ7i6bwoc |
||||
j6jQ67S3RkK1svqXVgoqjYHY69BEhO94vNQZeOgTJWRk1YjKfTwQAdLru8U2BjtA |
||||
gh76OiMsTXhnhOv/TPGBRFUwPt2BSY5G/aa6ZJ0XB/exsOo0z/34k9IIGCO3g/g6 |
||||
BpphITMjOJ8LbA8v0PBeHQD9d9u1ViuafgzvD6WwvmAkDKhGXDMyYDn5zjGo6L+w |
||||
rjmGjOn4c0rJAxPGEMABaGusuxhRFrFLxolohru3jSvvjjZ/zbXo3V6bR+Ta2IIC |
||||
cewd/gPI0odv1ObXNwdI/Dvu/1ymxcg8aVgjuMHtonkOAfxw9ghIuDfNtbV0Nb15 |
||||
SEzY5w== |
||||
-----END CERTIFICATE----- |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
const compression = require('compression'); |
||||
const express = require('express'); |
||||
const https = require('https'); |
||||
const fs = require('fs'); |
||||
|
||||
const app = express(); |
||||
|
||||
app.use(compression()); |
||||
app.use(express.static('public')); |
||||
|
||||
app.get('/', (req, res) => { |
||||
res.sendFile(__dirname + '/public/index.html'); |
||||
}); |
||||
|
||||
https.createServer({ |
||||
key: fs.readFileSync(__dirname + '/server.key'), |
||||
cert: fs.readFileSync(__dirname + '/server.cert') |
||||
}, app).listen(9001, () => { |
||||
console.log('Listening...'); |
||||
}); |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY----- |
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHHMyF3+/FPzik |
||||
RxEghnBgp7oLTQ5pFmrxUSuA2g5BWvyF6OPsW54aMC6KjzjU5wmNQcKAPsF1r9y7 |
||||
kUuzQBPECQGjDsr35DPHcaeXztkqTGW3jEVnqZa8OJiGi+WJQv4j6WXb2XZwXY9e |
||||
GXyr9USw6XT4zjl3mvNP+rLc8Pcf/kLCoJWei8Jd7kcEQUJ/zapgAR74n/DkqO2K |
||||
qBPh/H+fRc1cRLQo7+i3Y9bKMafOz5XnbJ/Z4KGZ8isB7v7KREzrRjAhHcce8KJU |
||||
7le0SoHfHbTsAPBxAakLSg6+6PxgHwmPvpBR8ubnn3+k2ORlHTuMxF5fo/O65/ts |
||||
SxC9+QybAgMBAAECggEAdWzciU9p3k/MncVzqlTezYHdTHDjQMKBy1Ntbo4qvgxk |
||||
xKx2Tpwxf4xOxlR01cpzbaUMigl4mmleqhekJ1Bw17ngB0PgG5Wvm73BctwAYtuv |
||||
WTIWdG4lgVd3TFIQyoSB0LgC5Ec5fEcRGBO73MXG/vaPj3Q/m/P77n0RIw/RDkIg |
||||
mZjPOAeVpaJxRInVgpEAfzPAB+yPyk1qxHzbBzQziyzZLxycF26vlHcGWbjWeOBA |
||||
0CLVwAHeoctLpxPYSTlEc1PCZvn0Lm4kMFuuUnf03Tc/nlvGD0iQ2s6ThdUs2dNV |
||||
uie5JzrgsZuRPQ2vxYGLAZZI4455HA+gENvQQd160QKBgQDsAwtAF1S4fAiuR9hY |
||||
Nh5PEM3MRb9FMaRN5p4PdinnCmkymrUoW/LKotyU7ASwKnmALUzQ0eUoIjvRC85B |
||||
rW5NpuK/GjURZYd6+AzrqoWcnuDe7ugj0G1U0yyBbtMbp+KELB30UMJexV7ovHPM |
||||
rCi5mz1EUy0SUTj1CyWEazco5wKBgQDX+b3xu3gtOxbDi0hGJ1u/TAvJGndHXDBK |
||||
yzaY0I8BIbPC6IWTiWkCImuogFoV7TruLpGJJa9QDzhBi2mkRGvS6XWDKEoRe/tb |
||||
l8BhGFbNqdDyMb6tNh8k8cpYSDLlzMgK1/5S6gUsr5jWA0fFegXRcexYmj0r+ibN |
||||
5AP1mZrELQKBgQCE5SXlnf2XsEgXEt+QtFCWxuiLWM7eQJi7QNvJ6winT2ZzF0hh |
||||
BH2PeutodAojxJcMBPYXM8mssrIqAVLQCr9svEc7wp8VP61tIdXsseVwjsoi3jYb |
||||
TJbzx8Fs1KHNFdjoAguP8hWw1cSemtc97cc01GRIX+mmQdQnr3IdwV2bCwKBgCiV |
||||
cl7pRmThdJ6cHqGoJbJlvNU2VvGe3ig/1WuTzTt+NMRMY0VdDdFr3GUWcVcrc+Zr |
||||
88ccwLu/kGeopdpLTSOd4QobWQe+D3afpnPYWf9diLjqJhVwVRvhH4/FSWMrPu/i |
||||
tJSqCvzhpkuY5DS0gEFiMfJYUWRhJkeMMD5HdfClAoGBANTEaSrZhmw2HgdXD4iE |
||||
sscOyh84+kJG77T+0B5jj+Oa5laulRwIjxZfndoSFlspQ+z1hDE9iqWGv+qd5u0u |
||||
yWWf6LB88hBAcLTg82AUuPTQXsOtkzBeb1Ny+xoKCL73nGcHCydoih0AA8+4oQWT |
||||
ecQb07xZUbaNB5HKRzcmalf6 |
||||
-----END PRIVATE KEY----- |
@ -0,0 +1,162 @@
@@ -0,0 +1,162 @@
|
||||
import { generatePathData } from "../lib/utils"; |
||||
|
||||
export default class BubbleGroups { |
||||
bubblesByGroups: Array<{timestamp: number, fromID: number, mid: number, group: HTMLDivElement[]}> = []; // map to group
|
||||
groups: Array<HTMLDivElement[]> = []; |
||||
//updateRAFs: Map<HTMLDivElement[], number> = new Map();
|
||||
newGroupDiff = 120; |
||||
|
||||
removeBubble(bubble: HTMLDivElement, mid: number) { |
||||
let details = this.bubblesByGroups.findAndSplice(g => g.mid == mid); |
||||
if(details && details.group.length) { |
||||
details.group.findAndSplice(d => d == bubble); |
||||
if(!details.group.length) { |
||||
this.groups.findAndSplice(g => g == details.group); |
||||
} |
||||
} |
||||
} |
||||
|
||||
addBubble(bubble: HTMLDivElement, message: any, reverse: boolean) { |
||||
let timestamp = message.date; |
||||
let fromID = message.fromID; |
||||
let group: HTMLDivElement[]; |
||||
|
||||
// try to find added
|
||||
//this.removeBubble(message.mid);
|
||||
|
||||
if(this.bubblesByGroups.length) { |
||||
if(reverse) { |
||||
let g = this.bubblesByGroups[0]; |
||||
if(g.fromID == fromID && (g.timestamp - timestamp) < this.newGroupDiff) { |
||||
group = g.group; |
||||
group.unshift(bubble); |
||||
} else { |
||||
this.groups.unshift(group = [bubble]); |
||||
} |
||||
} else { |
||||
let g = this.bubblesByGroups[this.bubblesByGroups.length - 1]; |
||||
if(g.fromID == fromID && (timestamp - g.timestamp) < this.newGroupDiff) { |
||||
group = g.group; |
||||
group.push(bubble); |
||||
} else { |
||||
this.groups.push(group = [bubble]); |
||||
} |
||||
} |
||||
} else { |
||||
this.groups.push(group = [bubble]); |
||||
} |
||||
|
||||
//console.log('addBubble', bubble, message.mid, fromID, reverse, group);
|
||||
|
||||
this.bubblesByGroups[reverse ? 'unshift' : 'push']({timestamp, fromID, mid: message.mid, group}); |
||||
this.updateGroup(group, reverse); |
||||
} |
||||
|
||||
setClipIfNeeded(bubble: HTMLDivElement, remove = false) { |
||||
//console.log('setClipIfNeeded', bubble, remove);
|
||||
if(bubble.classList.contains('is-message-empty')/* && !bubble.classList.contains('is-reply') */ |
||||
&& (bubble.classList.contains('photo') || bubble.classList.contains('video'))) { |
||||
let container = bubble.querySelector('.bubble__media-container') as SVGSVGElement; |
||||
//console.log('setClipIfNeeded', bubble, remove, container);
|
||||
if(!container) return; |
||||
|
||||
Array.from(container.children).forEach(object => { |
||||
if(object instanceof SVGDefsElement) return; |
||||
|
||||
if(remove) { |
||||
object.removeAttributeNS(null, 'clip-path'); |
||||
} else { |
||||
let clipID = container.dataset.clipID; |
||||
let path = container.firstElementChild.firstElementChild.lastElementChild as SVGPathElement; |
||||
let width = +object.getAttributeNS(null, 'width'); |
||||
let height = +object.getAttributeNS(null, 'height'); |
||||
let isOut = bubble.classList.contains('is-out'); |
||||
let isReply = bubble.classList.contains('is-reply'); |
||||
let d = ''; |
||||
|
||||
//console.log('setClipIfNeeded', object, width, height, isOut);
|
||||
|
||||
let tr: number, tl: number; |
||||
if(bubble.classList.contains('forwarded') || isReply) { |
||||
tr = tl = 0; |
||||
} else if(isOut) { |
||||
tr = bubble.classList.contains('is-group-first') ? 12 : 6; |
||||
tl = 12; |
||||
} else { |
||||
tr = 12; |
||||
tl = bubble.classList.contains('is-group-first') ? 12 : 6; |
||||
} |
||||
|
||||
if(isOut) { |
||||
d = generatePathData(0, 0, width - 9, height, tl, tr, 0, 12); |
||||
} else { |
||||
d = generatePathData(9, 0, width - 9, height, tl, tr, 12, 0); |
||||
} |
||||
|
||||
path.setAttributeNS(null, 'd', d); |
||||
object.setAttributeNS(null, 'clip-path', 'url(#' + clipID + ')'); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
updateGroup(group: HTMLDivElement[], reverse = false) { |
||||
/* if(this.updateRAFs.has(group)) { |
||||
window.cancelAnimationFrame(this.updateRAFs.get(group)); |
||||
this.updateRAFs.delete(group); |
||||
} */ |
||||
|
||||
//this.updateRAFs.set(group, window.requestAnimationFrame(() => {
|
||||
//this.updateRAFs.delete(group);
|
||||
|
||||
if(!group.length) { |
||||
return; |
||||
} |
||||
|
||||
let first = group[0]; |
||||
|
||||
//appImManager.scrollPosition.prepareFor(reverse ? 'up' : 'down');
|
||||
|
||||
//console.log('updateGroup', group, first);
|
||||
|
||||
if(group.length == 1) { |
||||
first.classList.add('is-group-first', 'is-group-last'); |
||||
this.setClipIfNeeded(first); |
||||
return; |
||||
} else { |
||||
first.classList.remove('is-group-last'); |
||||
first.classList.add('is-group-first'); |
||||
this.setClipIfNeeded(first, true); |
||||
} |
||||
|
||||
let length = group.length - 1; |
||||
for(let i = 1; i < length; ++i) { |
||||
let bubble = group[i]; |
||||
bubble.classList.remove('is-group-last', 'is-group-first'); |
||||
this.setClipIfNeeded(bubble, true); |
||||
} |
||||
|
||||
let last = group[group.length - 1]; |
||||
last.classList.remove('is-group-first'); |
||||
last.classList.add('is-group-last'); |
||||
this.setClipIfNeeded(last); |
||||
|
||||
//appImManager.scrollPosition.restore();
|
||||
//}));
|
||||
} |
||||
|
||||
updateGroupByMessageID(mid: number) { |
||||
let details = this.bubblesByGroups.find(g => g.mid == mid); |
||||
if(details) { |
||||
this.updateGroup(details.group); |
||||
} |
||||
} |
||||
|
||||
cleanup() { |
||||
this.bubblesByGroups = []; |
||||
/* for(let value of this.updateRAFs.values()) { |
||||
window.cancelAnimationFrame(value); |
||||
} |
||||
this.updateRAFs.clear(); */ |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
// @ts-ignore
|
||||
import LottiePlayer from "lottie-web/build/player/lottie_canvas.min.js"; |
||||
|
||||
(window as any).lottie = LottiePlayer; |
Loading…
Reference in new issue