mirror of
https://github.com/openvk/openvk
synced 2024-11-11 09:29:29 +03:00
276 lines
12 KiB
XML
276 lines
12 KiB
XML
{extends "../@layout.xml"}
|
||
{block title}{$correspondent->getCanonicalName()}{/block}
|
||
|
||
{block header}
|
||
|
||
<a href="/im">{_my_messages}</a> »
|
||
<a href="{$correspondent->getURL()}">{$correspondent->getCanonicalName()}</a>
|
||
<div n:if="($online = $correspondent->getOnline()->timestamp()) + 2505600 > time()" style="float: right;">
|
||
{var diff = date_diff(date_create(), date_create('@' . $online))}
|
||
{if 5 >= $diff->i}
|
||
<span><b>{_online}</b></span>
|
||
{else}
|
||
<span>{$correspondent->isFemale() ? "заходила" : "заходил"} {$correspondent->getOnline()}</span>
|
||
{/if}
|
||
</div>
|
||
{/block}
|
||
|
||
{block wrap}
|
||
<div class="messenger-app">
|
||
<div class="messenger-app--messages" data-bind="event: { scroll: onMessagesScroll }">
|
||
<div data-bind="foreach: messages">
|
||
<div class="messenger-app--messages---message" data-bind="css: { unread: !read }">
|
||
<img class="ava" data-bind="attr: { src: sender.avatar, alt: sender.name }" />
|
||
<div class="_content">
|
||
<a href="#" data-bind="attr: { href: sender.link }">
|
||
<strong data-bind="text: sender.name"></strong>
|
||
</a>
|
||
<span class="text" data-bind="html: text"></span>
|
||
<div data-bind="foreach: attachments" class="attachments">
|
||
<div class="msg-attach-j">
|
||
<div data-bind="if: type === 'photo'" class="msg-attach-j-photo">
|
||
<a data-bind="attr: { href: link }">
|
||
<img data-bind="attr: { src: photo.url, alt: photo.caption }" />
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="time" align="right">
|
||
<span data-bind="text: timing.sent"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="messenger-app--input">
|
||
{if $correspondent->getId() === $thisUser->getId() || $correspondent->getPrivacyPermission('messages.write', $thisUser)}
|
||
<img class="ava" src="{$thisUser->getAvatarUrl('miniscule')}" alt="{$thisUser->getCanonicalName()}" />
|
||
<div class="messenger-app--input---messagebox">
|
||
<textarea
|
||
data-bind="value: messageContent, event: { keydown: onTextareaKeyPress }"
|
||
name="message"
|
||
placeholder="Введите сообщение"></textarea>
|
||
<button class="button" data-bind="click: sendMessage">Отправить</button>
|
||
</div>
|
||
<img class="ava" src="{$correspondent->getAvatarUrl('miniscule')}" alt="{$correspondent->getCanonicalName()}" />
|
||
{else}
|
||
<div class="blocked" data-localized-text="Вы не можете писать сообщения {$correspondent->getCanonicalName()} из-за его настроек приватности."></div>
|
||
{/if}
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://knockoutjs.com/downloads/knockout-3.5.1.js"></script>
|
||
<script>
|
||
function MessengerViewModel(initialMessages = []) {
|
||
window.messages = ko.observableArray(initialMessages);
|
||
this.messages = window.messages;
|
||
this.messageContent = ko.observable("");
|
||
|
||
this.sendMessage = model => {
|
||
if(model.messageContent() === "") return false;
|
||
|
||
window.Msg.sendMessage(model.messageContent());
|
||
model.messageContent("");
|
||
};
|
||
this.loadHistory = _ => {
|
||
window.Msg._loadHistory();
|
||
};
|
||
|
||
this.onMessagesScroll = (model, e) => {
|
||
if(e.target.scrollTop < 21)
|
||
model.loadHistory();
|
||
};
|
||
this.onTextareaKeyPress = (model, e) => {
|
||
if(e.which === 13) {
|
||
if(!e.metaKey && !e.shiftKey) {
|
||
let ta = u("textarea[name=message]").nodes[0];
|
||
ta.blur(); //Fix update
|
||
model.sendMessage(model);
|
||
ta.focus();
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
}
|
||
|
||
class Messenger {
|
||
constructor(messages = []) {
|
||
this.ko = ko.applyBindings(new MessengerViewModel(messages));
|
||
this.appEl = document.querySelector(".messenger-app--messages");
|
||
this.offset = 0;
|
||
|
||
this._loadHistory();
|
||
this._setupListener();
|
||
this.appEl.scrollTop = this.appEl.scrollHeight;
|
||
}
|
||
|
||
_loadHistory() {
|
||
let xhr = new XMLHttpRequest();
|
||
xhr.open("GET", "/im/api/messages" + {$correspondent->getId()} + `/${ this.offset }.json`, false);
|
||
xhr.send();
|
||
|
||
let messages = JSON.parse(xhr.responseText);
|
||
let lastMessage = messages[messages.length - 1];
|
||
if(typeof lastMessage !== "undefined") this.offset = lastMessage.uuid;
|
||
|
||
this.prependMessages(messages);
|
||
}
|
||
|
||
_setupListener() {
|
||
let listenLongpool = () => {
|
||
let xhr = new XMLHttpRequest();
|
||
xhr.open("GET", "/im12", true);
|
||
xhr.onload = () => {
|
||
let data = JSON.parse(xhr.responseText);
|
||
data.forEach(event => {
|
||
event = event.event;
|
||
if(event.type !== "newMessage")
|
||
return;
|
||
else if(event.message.sender.id !== {$correspondent->getId()})
|
||
return;
|
||
else if(this.offset >= event.message.uuid)
|
||
return void(console.warn("Gay message recieved, skipping. [-WHeterosexual]"));
|
||
|
||
this.addMessage(event.message);
|
||
this.offset = event.message.uuid;
|
||
});
|
||
|
||
listenLongpool();
|
||
};
|
||
xhr.send();
|
||
};
|
||
|
||
listenLongpool();
|
||
}
|
||
|
||
appendMessages(messages) {
|
||
messages.forEach(m => window.messages.push(m));
|
||
}
|
||
|
||
prependMessages(messages) {
|
||
messages.forEach(m => window.messages.unshift(m));
|
||
}
|
||
|
||
addMessage(message, scroll = true) {
|
||
this.appendMessages([message]);
|
||
|
||
if(scroll) {
|
||
this.appEl.scrollTop = this.appEl.scrollHeight;
|
||
}
|
||
}
|
||
|
||
_patchMessage(tempId, message) {
|
||
for(let i = window.messages().length - 1; i > -1; i--) {
|
||
let msg = window.messages()[i];
|
||
if(typeof msg._tuid === "undefined")
|
||
return;
|
||
else if(msg._tuid !== tempId)
|
||
return;
|
||
|
||
window.messages.valueWillMutate();
|
||
window.messages()[i] = message;
|
||
window.messages.valueHasMutated();
|
||
}
|
||
}
|
||
|
||
_newSelfMessage(content = "...") {
|
||
return {
|
||
"sender": {
|
||
"link": {$thisUser->getURL()},
|
||
"avatar": {$thisUser->getAvatarUrl()},
|
||
"name": {$thisUser->getFullName()}
|
||
},
|
||
"timing": {
|
||
"sent": window.API.Service.getTime(),
|
||
"edited": null
|
||
},
|
||
"text": content,
|
||
"read": false,
|
||
"attachments": [],
|
||
"_tuid": Math.ceil(performance.now())
|
||
};
|
||
}
|
||
|
||
_newReplyMessage(content = "...") {
|
||
return {
|
||
"sender": {
|
||
"link": {$correspondent->getURL()},
|
||
"avatar": {$correspondent->getAvatarUrl()},
|
||
"name": {$correspondent->getFullName()}
|
||
},
|
||
"timing": {
|
||
"sent": window.API.Service.getTime(),
|
||
"edited": null
|
||
},
|
||
"text": content,
|
||
"read": true,
|
||
"_tuid": Math.ceil(performance.now())
|
||
};
|
||
}
|
||
|
||
newMessage(content) {
|
||
let msg = this._newSelfMessage(content);
|
||
this.addMessage(msg);
|
||
|
||
return msg._tuid;
|
||
}
|
||
|
||
newReply(content) {
|
||
let msg = this._newReplyMessage(content);
|
||
this.addMessage(msg);
|
||
|
||
return msg._tuid;
|
||
}
|
||
|
||
newReplies(replies) {
|
||
replies.forEach(this.newReply);
|
||
}
|
||
|
||
sendMessage(content) {
|
||
console.debug("New outcoming message. Pushing preview to local stack.");
|
||
let tempId = this.newMessage(content);
|
||
|
||
let msgData = new FormData();
|
||
msgData.set("content", content);
|
||
msgData.set("hash", {$csrfToken});
|
||
|
||
let that = this;
|
||
let xhr = new XMLHttpRequest();
|
||
xhr.open("POST", "/im/api/messages" + {$correspondent->getId()} + "/create.json", true);
|
||
xhr.onreadystatechange = (function() {
|
||
if(this.readyState !== 4)
|
||
return;
|
||
else if(this.status !== 202) {
|
||
console.error("Message was not sent.");
|
||
that._patchMessage(tempId, {
|
||
sender: {
|
||
avatar: "/assets/packages/static/openvk/img/oof.apng",
|
||
id: -1,
|
||
link: "/support/manpages/messages/not-delivered.html",
|
||
name: "Сообщение не доставлено"
|
||
},
|
||
text: "При отправке этого сообщения произошла ошибка общего характера...",
|
||
timing: {
|
||
edited: null,
|
||
sent: "???"
|
||
},
|
||
uuid: -4096
|
||
});
|
||
|
||
return;
|
||
}
|
||
|
||
console.debug("Message sent, updating view.");
|
||
that._patchMessage(tempId, JSON.parse(xhr.responseText));
|
||
});
|
||
xhr.send(msgData);
|
||
console.debug("Message sent, awaiting response.");
|
||
}
|
||
}
|
||
|
||
window.Msg = new Messenger([]);
|
||
</script>
|
||
{/block}
|