Skip to content

Commit bedcd39

Browse files
committed
Merge branch 'frontend-refactor'
2 parents 8f64b3b + f548bf7 commit bedcd39

File tree

6 files changed

+188
-95
lines changed

6 files changed

+188
-95
lines changed

logviewer/app.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import flask
1515
from flask import (Flask, request, redirect, session, url_for, render_template,
16-
current_app)
16+
current_app, jsonify)
1717

1818
from logviewer.exc import AuthenticationError
1919
from logviewer.parser import parse_log
@@ -315,8 +315,12 @@ def log(channel, date):
315315
else:
316316
last_no = 0
317317
if request.is_xhr:
318-
return render_template('_messages.html',
319-
log=log, messages=messages, last_no=last_no)
318+
if messages:
319+
html = render_template('_messages.html',
320+
log=log, messages=messages, last_no=last_no)
321+
return jsonify(html=html, last_no=last_no)
322+
else:
323+
return jsonify(html=None)
320324
options = {}
321325
if log.is_today and 'recent' in request.args:
322326
recent = int(request.args['recent'])

logviewer/static/chat.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
function ChatSession(options) {
2+
this.options = options;
3+
this.from = options.from || 0;
4+
this.onUpdate = options.onUpdate || function(){};
5+
}
6+
7+
ChatSession.prototype = {
8+
start: function() {
9+
this.socket = io.connect(this.options.url);
10+
var self = this;
11+
this.socket.on('update', function() {
12+
self.update(self.onUpdate);
13+
});
14+
},
15+
16+
send: function(msg) {
17+
this.socket.emit('msg', {
18+
nick: this.options.nickname,
19+
channel: this.options.channel,
20+
msg: msg
21+
});
22+
},
23+
24+
update: function(next) {
25+
var self = this;
26+
$.getJSON('?from=' + this.from, function(data) {
27+
if (!data.html) return;
28+
self.from = data.last_no + 1;
29+
if (next) next.call(self, data.html);
30+
});
31+
}
32+
};
33+
34+
function LogView(el) {
35+
this.el = el;
36+
}
37+
38+
LogView.prototype = {
39+
append: function(data) {
40+
this.el.append(data);
41+
apply_noreferrer(this.el);
42+
},
43+
44+
scrollToBottom: function() {
45+
$(window).scrollTop($(document).height() + 100000);
46+
},
47+
48+
shouldScrollToBottom: function() {
49+
var $doc = $(document),
50+
$window = $(window);
51+
return $doc.height() <= $window.scrollTop() + $window.height() + 20;
52+
}
53+
};
54+
55+
function ChatController(options) {
56+
this.options = options;
57+
this.session = options.session;
58+
this.session.onUpdate = $.proxy(this.onUpdate, this);
59+
60+
var self = this;
61+
this.options.startChatView.on('click', function() {
62+
self.startChat();
63+
return false;
64+
});
65+
this.options.inputFormView.on('submit', function() {
66+
self.sendMessage();
67+
return false;
68+
});
69+
}
70+
71+
ChatController.prototype = {
72+
startChat: function() {
73+
this.options.startChatView.slideUp();
74+
this.options.inputFormView.slideDown();
75+
var self = this;
76+
77+
this.normalTitle = document.title;
78+
observeWindowVisibility(function(visible) {
79+
self.setWindowVisible(visible);
80+
});
81+
82+
this.session.update(function(data) {
83+
self.appendLog(data);
84+
self.options.logView.scrollToBottom();
85+
});
86+
this.session.start();
87+
},
88+
89+
onUpdate: function(data) {
90+
var willScroll = this.options.logView.shouldScrollToBottom();
91+
this.appendLog(data);
92+
if (willScroll)
93+
this.options.logView.scrollToBottom();
94+
if (!this._windowVisible)
95+
this.notifyPendingLog();
96+
},
97+
98+
appendLog: function(data) {
99+
this.options.logView.append(data);
100+
},
101+
102+
sendMessage: function() {
103+
var msg = this.options.inputView.val();
104+
if (msg) {
105+
this.session.send(msg);
106+
this.options.inputView.val('');
107+
}
108+
},
109+
110+
setWindowVisible: function(visible) {
111+
if (!this._windowVisible && visible) {
112+
// Become visible
113+
document.title = this.normalTitle;
114+
}
115+
this._windowVisible = visible;
116+
},
117+
118+
notifyPendingLog: function() {
119+
document.title = '+ ' + this.normalTitle;
120+
}
121+
};
122+
123+
(function(exports) {
124+
var hidden, visibilityChange;
125+
if (typeof document.hidden !== "undefined") {
126+
hidden = "hidden";
127+
visibilityChange = "visibilitychange";
128+
} else if (typeof document.mozHidden !== "undefined") {
129+
hidden = "mozHidden";
130+
visibilityChange = "mozvisibilitychange";
131+
} else if (typeof document.msHidden !== "undefined") {
132+
hidden = "msHidden";
133+
visibilityChange = "msvisibilitychange";
134+
} else if (typeof document.webkitHidden !== "undefined") {
135+
hidden = "webkitHidden";
136+
visibilityChange = "webkitvisibilitychange";
137+
}
138+
139+
exports.isWindowVisible = function() {
140+
return !document[hidden];
141+
};
142+
143+
exports.observeWindowVisibility = function(callback) {
144+
if (typeof document.addEventListener !== "undefined" &&
145+
typeof hidden !== "undefined") {
146+
callback(exports.isWindowVisible());
147+
document.addEventListener(visibilityChange, function() {
148+
callback(exports.isWindowVisible());
149+
}, false);
150+
}
151+
};
152+
})(window);

logviewer/templates/_messages.html

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
11
{% from 'macros.html' import message_rows %}
22
{{ message_rows(messages) }}
3-
{% if messages %}
4-
<script>from={{ last_no + 1 }}</script>
5-
{% endif %}

logviewer/templates/base.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
<meta name="viewport" content="width=device-width" />
88
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" type="text/css">
99
<link rel="stylesheet" href="{{ url_for('static', filename='jquery.dropdown.css') }}" type="text/css">
10-
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
11-
<script type="text/javascript" src="{{ url_for('static', filename='socket.io/socket.io.min.js') }}"></script>
12-
<script type="text/javascript" src="{{ url_for('static', filename='jquery.dropdown.js') }}"></script>
1310
</head>
1411
<body>
1512
<div class="langdev__nav">
@@ -27,6 +24,9 @@ <h3><a href="http://langdev.org/">LangDev</a></h3>
2724
{% block content %}
2825
{% endblock %}
2926
<a name="bottom"></a>
27+
<script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js"></script>
28+
<script type="text/javascript" src="{{ url_for('static', filename='socket.io/socket.io.min.js') }}"></script>
29+
<script type="text/javascript" src="{{ url_for('static', filename='jquery.dropdown.js') }}"></script>
3030
<script type="text/javascript">
3131
function apply_noreferrer(element) {
3232
$(element).find('a:not([rel~="noreferrer"])').each(function(i, e) {
@@ -58,5 +58,7 @@ <h3><a href="http://langdev.org/">LangDev</a></h3>
5858
});
5959
});
6060
</script>
61+
{% block js %}
62+
{% endblock %}
6163
</body>
6264
</html>

logviewer/templates/log.html

Lines changed: 22 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -64,98 +64,34 @@ <h3>건너뛰기</h3>
6464
<a href="{{ url_for('logout') }}">로그아웃</a>
6565
</p>
6666
</form>
67+
{% else %}
68+
<p id="eol">* 로그의 끝입니다. *</p>
69+
{% endif %}
70+
</div>
71+
{% endblock %}
6772

68-
<script type="text/javascript">
69-
var from = {{ last_no + 1 }};
70-
var nickname = '{{ username }}';
71-
var channel = '{{ channel }}';
72-
73-
var socket;
74-
75-
var hidden, visibilityChange;
76-
if (typeof document.hidden !== "undefined") {
77-
hidden = "hidden";
78-
visibilityChange = "visibilitychange";
79-
} else if (typeof document.mozHidden !== "undefined") {
80-
hidden = "mozHidden";
81-
visibilityChange = "mozvisibilitychange";
82-
} else if (typeof document.msHidden !== "undefined") {
83-
hidden = "msHidden";
84-
visibilityChange = "msvisibilitychange";
85-
} else if (typeof document.webkitHidden !== "undefined") {
86-
hidden = "webkitHidden";
87-
visibilityChange = "webkitvisibilitychange";
88-
}
89-
90-
var origTitle = document.title;
91-
function handleVisibilityChange() {
92-
if (!document[hidden]) {
93-
document.title = origTitle;
94-
}
95-
}
96-
function notifyUpdate() {
97-
if (document[hidden]) {
98-
document.title = '+ ' + origTitle;
99-
}
100-
}
101-
102-
if (typeof document.addEventListener !== "undefined" &&
103-
typeof hidden !== "undefined") {
104-
// Handle page visibility change
105-
document.addEventListener(visibilityChange, handleVisibilityChange, false);
106-
}
107-
108-
$('#enable-chat a').click(function() {
109-
start_chat();
110-
return false;
73+
{% block js %}
74+
{% if log.is_today %}
75+
<script type="text/javascript" src="{{ url_for('static', filename='chat.js') }}"></script>
76+
<script>
77+
window.chat = new ChatSession({
78+
url: location.protocol + '//' + location.hostname + ':{{ LOGBOT_PORT }}',
79+
nickname: '{{ username }}',
80+
channel: '{{ channel }}',
81+
from: {{ last_no + 1 }}
11182
});
11283

113-
function scroll_to_bottom() {
114-
$(window).scrollTop($(document).height() + 100000);
115-
}
116-
117-
function start_chat() {
118-
$('#enable-chat').slideUp();
119-
$('#say').slideDown();
120-
_update_log(true);
121-
122-
socket = io.connect(location.protocol + '//' + location.hostname + ':{{ LOGBOT_PORT }}');
123-
124-
socket.on('update', function () {
125-
_update_log();
126-
});
127-
}
128-
129-
function _update_log(force_scroll) {
130-
var _from = from,
131-
$doc = $(document),
132-
$window = $(window),
133-
appendTarget = $('#updates');
134-
135-
$.get('?from=' + _from, function (data) {
136-
if (from > _from) return;
137-
notifyUpdate();
138-
var willScroll = force_scroll || $doc.height() <= $window.scrollTop() + $window.height() + 20;
139-
appendTarget.append(data)
140-
apply_noreferrer(appendTarget);
141-
if (willScroll) {
142-
scroll_to_bottom();
143-
}
144-
});
145-
}
84+
window.logView = new LogView($('#updates'));
14685

147-
$('#say').submit(function(event) {
148-
event.preventDefault();
149-
var msg = $('#msg').val();
150-
if (!msg) return;
151-
socket.emit('msg', {nick: nickname, channel: channel, msg: msg});
152-
$('#msg').attr('value', '');
153-
})
86+
window.chatController = new ChatController({
87+
session: chat,
88+
startChatView: $('#enable-chat'),
89+
inputFormView: $('#say'),
90+
inputView: $('#msg'),
91+
logView: window.logView
92+
});
15493
</script>
155-
{% else %}
156-
<p id="eol">* 로그의 끝입니다. *</p>
15794
{% endif %}
158-
15995
<script type="text/javascript">
16096
if ($.fn.dropdown) {
16197
$('#navbar > hgroup > h1').addClass('dropdown-target').css('margin-left', '-4px');

logviewer/templates/search_result.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ <h2><a href="{{ log.url() }}">#{{ log.name }} {{ log.date }}</a></h2>
3434
</div>
3535

3636
{{ page_nav(pages) }}
37+
{% endblock %}
3738

39+
{% block js %}
3840
<script type="text/javascript">
3941
var re = /{{ query_pattern }}/gi;
4042
var repl = "<span class=\"highlight\">$&</span>"

0 commit comments

Comments
 (0)