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

277 lines
12 KiB
XML
Raw Normal View History

2020-06-07 19:04:43 +03:00
{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()) < time() + 2678400" 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">
2020-06-15 21:18:23 +03:00
<div class="messenger-app--messages" data-bind="event: { scroll: onMessagesScroll }">
2020-06-07 19:04:43 +03:00
<div data-bind="foreach: messages">
2021-01-27 20:59:11 +03:00
<div class="messenger-app--messages---message" data-bind="css: { unread: !read }">
2020-06-07 19:04:43 +03:00
<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>
2020-06-07 19:04:43 +03:00
</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>
2020-06-07 19:04:43 +03:00
</div>
<div class="time" align="right">
<span data-bind="text: timing.sent"></span>
2020-06-07 19:04:43 +03:00
</div>
</div>
</div>
</div>
<div class="messenger-app--input">
{if $correspondent->getId() === $thisUser->getId() || ($correspondent->getSubscriptionStatus($thisUser) === 3)}
<img class="ava" src="{$thisUser->getAvatarUrl()}" 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()}" 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("");
2020-06-15 21:18:23 +03:00
this.sendMessage = model => {
2020-06-07 19:04:43 +03:00
if(model.messageContent() === "") return false;
window.Msg.sendMessage(model.messageContent());
model.messageContent("");
2020-06-15 21:18:23 +03:00
};
this.loadHistory = _ => {
window.Msg._loadHistory();
};
2020-06-07 19:04:43 +03:00
2020-06-15 21:18:23 +03:00
this.onMessagesScroll = (model, e) => {
if(e.target.scrollTop < 21)
model.loadHistory();
};
2020-06-07 19:04:43 +03:00
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,
2021-01-27 20:59:11 +03:00
"read": false,
"attachments": [],
2020-06-07 19:04:43 +03:00
"_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,
2021-01-27 20:59:11 +03:00
"read": true,
2020-06-07 19:04:43 +03:00
"_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}