Skip to content

Commit

Permalink
Added "customize the templates" section to readme
Browse files Browse the repository at this point in the history
Added django-debug-toolbar to requirements,urls,settings
Added dialogs.html custom template to example project, renamed extra_css to css in it
  • Loading branch information
delneg committed Feb 26, 2017
1 parent f0f5872 commit d11836a
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 4 deletions.
14 changes: 14 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ Example project
You can check out our example project by cloning the repo and heading into example/ directory.
There is a README file for you to check, initial data to check out the chat included.


Customize the templates
-----------------------

How to customize the template?
Just copy::

venv/lib/pythonX.X/site-packages/django_private_chat/templates/django_private_chat/dialogs.html
to
yourapp/templates/django_private_chat/dialogs.html
And feel free to edit it as you like!
We intentionally left the JS code inside for it to be editable easily.


Exsiting project quickstart
---------------------------

Expand Down
7 changes: 5 additions & 2 deletions example/example/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@
'django.contrib.messages',
'django.contrib.staticfiles',

'debug_toolbar',
'django_private_chat',
'custom_app'

'custom_app',
]

l = (
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
Expand All @@ -53,6 +54,7 @@
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

)

from django import get_version
Expand Down Expand Up @@ -178,3 +180,4 @@
}
}
}
INTERNAL_IPS = ['127.0.0.1', 'localhost']
7 changes: 6 additions & 1 deletion example/example/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@
"""
from django.conf.urls import url, include
from django.contrib import admin

from django.conf import settings

urlpatterns = [
url(r'^admin/', admin.site.urls),
# This might be reduntant, check later
url(r'', include('django_private_chat.urls')),
url(r'', include('custom_app.urls'))
]
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
1 change: 1 addition & 0 deletions example/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@

django-private-chat>=0.1.0
Django==1.10.5
django-debug-toolbar==1.6
2 changes: 1 addition & 1 deletion example/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<link href="{% static "css/style.css" %}" rel="stylesheet" type="text/css" media="all">
<title>{% block title %}{% endblock %}</title>

{% block extra_css %}{% endblock %}
{% block css %}{% endblock %}
</head>

<body>
Expand Down
290 changes: 290 additions & 0 deletions example/templates/django_private_chat/dialogs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
{# This template is here just to demonstrate how to customize the default one. #}
{# It has none to very few changes #}
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block css %}
{% endblock css %}

{% block content %}
<input id="owner_username" type="hidden" value="{{ request.user.username }}">
<div class="container">
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans "Chat list" %}</h3>
</div>
<div class="panel-body">
<div class="user-list-div">
<ul style="list-style-type: none;">
{% for dialog in object_list %}
<li>
{% if dialog.owner == request.user %}
{% with dialog.opponent.username as username %}
<a href="{% url 'dialogs_detail' username %}" id="user-{{ username }}"
class="btn btn-danger">{% trans "Chat with" %} {{ username }}</a>
{% endwith %}
{% else %}
{% with dialog.owner.username as username %}
<a href="{% url 'dialogs_detail' username %}" id="user-{{ username }}"
class="btn btn-danger">{% trans "Chat with" %} {{ username }}</a>
{% endwith %}
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-9">
<div class="well well-lg">
<div class="row">
<div class="col-md-3 col-md-offset-9">
<span class="pull-right" hidden id="typing-text">
<strong>{{ opponent_username }} {% trans "is typing..." %}</strong>
</span>
</div>
<p>
{{ opponent_username }}
</p>
<p class="text-success" id="online-status" style="display: none">{% trans "Online" %}</p>
<p class="text-danger" id="offline-status" style="display: none">{% trans "Offline" %}</p>

<div class="messages-container">
<div id="messages" class="messages">
{% for msg in active_dialog.messages.all %}
<div class="row">
<p class="{% if msg.sender == request.user %}pull-left{% else %}pull-right{% endif %}">
<span class="username">{{ msg.sender.username }}:</span>
{{ msg.text }}
<span class="timestamp">&ndash; <span
data-livestamp="{{ msg.get_formatted_create_datetime }}">{{ msg.get_formatted_create_datetime }}</span></span>
</p>
</div>
{% endfor %}
</div>
</div>
</div>

<div class="row">
<div class="add-message">
<div class="form-group">
<textarea id="chat-message" class="form-control message"
placeholder="{% trans 'Write a message' %}"></textarea>
</div>

<div class="form-group clearfix">
<input id="btn-send-message" type="submit" class="btn btn-primary pull-right send-message"
style="margin-left: 10px;" value="{% trans 'Send' %}"/>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

{% block extra_js %}
<script>
var base_ws_server_path = "{{ ws_server_path }}";
$(document).ready(function () {
var websocket = null;

function getOpponnentUsername() {
return "{{ opponent_username }}";
}

// TODO: Use for adding new dialog
function addNewUser(packet) {
$('#user-list').html('');
packet.value.forEach(function (userInfo) {
if (userInfo.username == getUsername()) return;
var tmpl = Handlebars.compile($('#user-list-item-template').html());
$('#user-list').append(tmpl(userInfo))
});
}

function addNewMessage(packet) {
var msg_class = "";
if (packet['sender_name'] == $("#owner_username").val()) {
msg_class = "pull-left";
} else {
msg_class = "pull-right";
}
var msgElem =
$('<div class="row">' +
'<p class="' + msg_class + '">' +
'<span class="username">' + packet['sender_name'] + ': </span>' +
packet['message'] +
' <span class="timestamp">&ndash; <span data-livestamp="' + packet['created'] + '"> ' + packet['created'] + '</span></span> ' +
'</p> ' +
'</div>');
$('#messages').append(msgElem);
scrollToLastMessage()
}

function scrollToLastMessage() {
var $msgs = $('#messages');
$msgs.animate({"scrollTop": $msgs.prop('scrollHeight')})
}

function generateMessage(context) {
var tmpl = Handlebars.compile($('#chat-message-template').html());
return tmpl({msg: context})
}

function setUserOnlineOffline(username, online) {
var elem = $("#user-" + username);
if (online) {
elem.attr("class", "btn btn-success");
} else {
elem.attr("class", "btn btn-danger");
}
}

function gone_online() {
$("#offline-status").hide();
$("#online-status").show();
}

function gone_offline() {
$("#online-status").hide();
$("#offline-status").show();
}

function setupChatWebSocket() {
var opponent_username = getOpponnentUsername();
websocket = new WebSocket(base_ws_server_path + '{{ request.session.session_key }}/' + opponent_username);

websocket.onopen = function (event) {
var opponent_username = getOpponnentUsername();

var onOnlineCheckPacket = JSON.stringify({
type: "check-online",
session_key: '{{ request.session.session_key }}',
username: opponent_username
{# Sending username because the user needs to know if his opponent is online #}
});
var onConnectPacket = JSON.stringify({
type: "online",
session_key: '{{ request.session.session_key }}'

});

console.log('connected, sending:', onConnectPacket);
websocket.send(onConnectPacket);
console.log('checking online opponents with:', onOnlineCheckPacket);
websocket.send(onOnlineCheckPacket);
};


window.onbeforeunload = function () {

var onClosePacket = JSON.stringify({
type: "offline",
session_key: '{{ request.session.session_key }}',
username: opponent_username,
{# Sending username because to let opponnent know that the user went offline #}
});
console.log('unloading, sending:', onClosePacket);
websocket.send(onClosePacket);
websocket.close();
};


websocket.onmessage = function (event) {
var packet;

try {
packet = JSON.parse(event.data);
console.log(packet)
} catch (e) {
console.log(e);
}

switch (packet.type) {
case "new-dialog":
// TODO: add new dialog to dialog_list
break;
case "user-not-found":
// TODO: dispay some kind of an error that the user is not found
break;
case "gone-online":
if (packet.usernames.indexOf(opponent_username) != -1) {
gone_online();
} else {
gone_offline();
}
for (var i = 0; i < packet.usernames.length; ++i) {
setUserOnlineOffline(packet.usernames[i], true);
}
break;
case "gone-offline":
if (packet.username == opponent_username) {
gone_offline();
}
setUserOnlineOffline(packet.username, false);
break;
case "new-message":
addNewMessage(packet);
break;
case "opponent-typing":
var typing_elem = $('#typing-text');
if (!typing_elem.is(":visible")) {
typing_elem.fadeIn(500);
} else {
typing_elem.stop(true);
typing_elem.fadeIn(0);
}
typing_elem.fadeOut(3000);
break;

default:
console.log('error: ', event)
}
}
}

function sendMessage(message) {
var opponent_username = getOpponnentUsername();
var newMessagePacket = JSON.stringify({
type: 'new-message',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
message: message
});
websocket.send(newMessagePacket)
}

$('#chat-message').keypress(function (e) {
if (e.which == 13 && this.value) {
sendMessage(this.value);
this.value = "";
return false
} else {
var opponent_username = getOpponnentUsername();
var packet = JSON.stringify({
type: 'is-typing',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
typing: true
});
websocket.send(packet);
}
});

$('#btn-send-message').click(function (e) {
var $chatInput = $('#chat-message');
var msg = $chatInput.val();
if (!msg) return;
sendMessage($chatInput.val());
$chatInput.val('')
});

setupChatWebSocket();
scrollToLastMessage();
});

</script>
{% endblock %}

0 comments on commit d11836a

Please sign in to comment.