openvk/Web/Presenters/templates/Messenger/App.xml

277 lines
12 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{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="html: 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);
msg.timing.sent = "<img src=\"/assets/packages/static/openvk/img/loading_mini.gif\">";
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}