Merge pull request #46 from torhve/master

Changes
This commit is contained in:
David Cormier 2013-10-15 14:38:35 -07:00
commit 4014a4a696
6 changed files with 197 additions and 123 deletions

View File

@ -71,6 +71,26 @@ input#sendMessage {
border: 0; border: 0;
width: 100%; width: 100%;
} }
.panel input {
max-width: 300px;
}
input[type=text], input[type=password] {
color: black;
border: 0;
-webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.4),
0 0 16px rgba(0,0,0,0.4);
-moz-box-shadow:
inset 0 0 8px rgba(0,0,0,0.4),
0 0 16px rgba(0,0,0,0.4);
box-shadow:
inset 0 0 8px rgba(0,0,0,0.4),
0 0 16px rgba(0,0,0,0.4);
background: rgba(255,255,255,0.5);
}
#sidebar, .panel {
background: #282828;
}
#sidebar { #sidebar {
position: fixed; position: fixed;
width: 12%; width: 12%;
@ -78,8 +98,7 @@ input#sendMessage {
height: 100%; height: 100%;
min-width: 130px; min-width: 130px;
overflow: auto; overflow: auto;
background: #282828; }
}
.content { .content {
height: 100%; height: 100%;
min-height: 100%; min-height: 100%;

View File

@ -16,6 +16,7 @@
<script type="text/javascript" src="js/websockets.js"></script> <script type="text/javascript" src="js/websockets.js"></script>
<script type="text/javascript" src="js/models.js"></script> <script type="text/javascript" src="js/models.js"></script>
<script type="text/javascript" src="js/plugins.js"></script> <script type="text/javascript" src="js/plugins.js"></script>
<script type="text/javascript" src="js/favico-0.3.0.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
</head> </head>
@ -28,58 +29,99 @@
WeeChat web frontend WeeChat web frontend
</small> </small>
</h2> </h2>
<div class="alert alert-info">WeeChat 0.4.2 or later is required</div>
<div class="alert alert-danger" ng-show="errorMessage"> <div class="alert alert-danger" ng-show="errorMessage">
<strong>Oh no!</strong> We cannot connect! <strong>Oh no!</strong> We cannot connect!
</div> </div>
<form class="form-signin" role="form"> <div class="panel-group" id="accordion">
<div class="form-group"> <div class="panel ">
<label class="control-label" for="host">WeeChat hostname</label> <div class="panel-heading">
<input type="text" class="form-control" id="host" ng-model="host" placeholder="Address"> <h4 class="panel-title">
<p class="help-block">Enter the hostname to the WeeChat relay</p> <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
</div> Connection settings
<div class="form-group"> </a>
<label class="control-label" for="port">WeeChat port number</label> </h4>
<input type="text" class="form-control" id="port" ng-model="port" placeholder="9001">
<p class="help-block">Enter the the port to the WeeChat relay</p>
</div>
<div class="form-group">
<label class="control-label" for="password">WeeChat relay password</label>
<input type="password" class="form-control" id="password" ng-model="password" placeholder="Password">
<p class="help-block">Password will be stored in your browser session</p>
</div> </div>
<div class="form-group"> <div id="collapseOne" class="panel-collapse collapse in">
<label class="control-label" for="proto">Encryption</label> <div class="panel-body">
<input type="checkbox" class="form-control" id="ssl" ng-model="ssl"> <form class="form-signin" role="form">
<p class="help-block">Check the box if you want to encrypt communication between browser and WeeChat. <strong>Note</strong>: Due to a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=594502">bug</a> encryption will not work in Firefox. You must also first visit the URL https://weechathost:relayport/ to accept the certificate</p> <div class="form-group">
<label class="control-label" for="host">WeeChat hostname</label>
<input type="text" class="form-control" id="host" ng-model="host" placeholder="Address">
<p class="help-block">Enter the hostname to the WeeChat relay</p>
</div>
<div class="form-group">
<label class="control-label" for="port">WeeChat port number</label>
<input type="text" class="form-control" id="port" ng-model="port" placeholder="9001">
<p class="help-block">Enter the the port to the WeeChat relay</p>
</div>
<div class="form-group">
<label class="control-label" for="password">WeeChat relay password</label>
<input type="password" class="form-control" id="password" ng-model="password" placeholder="Password">
<p class="help-block">Password will be stored in your browser session</p>
</div>
<div class="form-group">
<label class="control-label" for="proto">Encryption</label>
<input type="checkbox" class="form-control" id="ssl" ng-model="ssl">
<p class="help-block">Read encryption instructions for help</p>
</div>
<div class="form-group">
<label class="control-label" for="port">Lines</label>
<input type="text" class="form-control" id="lines" ng-model="lines" placeholder="40">
<p class="help-block">Enter number of lines to sync from WeeChat on connect</p>
</div>
<button class="btn btn-lg btn-primary" ng-click="connect()">Connect!</button>
</form>
</div>
</div>
</div>
<div class="panel ">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo">
Usage instructions
</a>
</h4>
</div>
<div id="collapseTwo" class="panel-collapse collapse">
<div class="panel-body">
<div>To start using, please enable relay in your WeeChat client:
<pre>
/set relay.network.password yourpassword
/relay add weechat 9001</pre>
<span class="label label-warning">WeeChat version 0.4.2 or higher is required.</span><br>
The communication goes directly between your browser and your weechat in clear text.
Connection settings are saved between sessions, including password, in your own browser.
</div>
</div>
</div>
<div class="panel ">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseThree">
Encryption instructions
</a>
</h4>
</div>
<div id="collapseThree" class="panel-collapse collapse">
<div class="panel-body">
If you check the encryption box, communication between browser and WeeChat will be encrypted.<br>
<strong>Note</strong>: Due to a <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=594502">bug</a> encryption will not work in Firefox. You must also first visit the URL https://weechathost:relayport/ to accept the certificate</p>
If you want to use encrypted session you first have to set up the relay using SSL like this:
<pre>
$ mkdir -p ~/.weechat/ssl
$ cd ~/.weechat/ssl
$ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out relay.pem
</pre>
If WeeChat is already running, you can reload the certificate and private key with command:
<pre>
/relay sslcertkey
/relay add ssl.weechat 8000
</pre>
</div>
</div>
</div>
</div>
</div> </div>
<div class="form-group">
<label class="control-label" for="port">Lines</label>
<input type="text" class="form-control" id="lines" ng-model="lines" placeholder="40">
<p class="help-block">Enter number of lines to sync from WeeChat on connect</p>
</div>
<button class="btn btn-lg btn-primary" ng-click="connect()">Connect!</button>
</form>
<h3>Instructions</h3>
<div>To start using, please enable relay in your WeeChat client:
<pre>
/set relay.network.password yourpassword
/relay add weechat 9001</pre>
Note: The communication goes directly between your browser and your weechat in clear text.
Connection settings are saved between sessions, including password, in your own browser.
<h4>Encryption</h4>
If you want to use encrypted session you first have to set up the relay using SSL
<pre>
$ mkdir -p ~/.weechat/ssl
$ cd ~/.weechat/ssl
$ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out relay.pem
</pre>
If WeeChat is already running, you can reload the certificate and private key with command:
<pre>
/relay sslcertkey
/relay add ssl.weechat 8000
</pre>
</div> </div>
</div> </div>
<div class="content" ng-show="connected"> <div class="content" ng-show="connected">
@ -100,7 +142,8 @@ $ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out rel
</li> </li>
<li class="label" ng-class="{'active': content.active }" ng-repeat="(key, content) in buffers | toArray | filter:search | filter:hasUnread | orderBy:'content.number':true"> <li class="label" ng-class="{'active': content.active }" ng-repeat="(key, content) in buffers | toArray | filter:search | filter:hasUnread | orderBy:'content.number':true">
<a href="#" ng-click="setActiveBuffer(content.id)" title="{{ content.fullName }}"> <a href="#" ng-click="setActiveBuffer(content.id)" title="{{ content.fullName }}">
<span class="badge pull-right" ng-class="{'danger': content.notification }" ng-bind="content.unread"></span> <span class="badge pull-right" ng-hide="content.notification" ng-if="content.unread" ng-bind="content.unread"></span>
<span class="badge pull-right danger" ng-show="content.notification" ng-bind="content.notification"></span>
{{ content.shortName }}<span ng-hide="content.shortName">{{ content.fullName }}</span> {{ content.shortName }}<span ng-hide="content.shortName">{{ content.fullName }}</span>
</a> </a>
</li> </li>
@ -119,7 +162,7 @@ $ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out rel
<span ng-repeat="part in bufferline.prefix" class="text" style="{{ part.fg }}">{{ part.text }}</span> <span ng-repeat="part in bufferline.prefix" class="text" style="{{ part.fg }}">{{ part.text }}</span>
</td> </td>
<td class="message"> <td class="message">
<span ng-repeat="part in bufferline.content" class="text" style="{{ part.fg }}">{{ part.text }} </span> <span ng-repeat="part in bufferline.content" class="text" style="{{ part.fg }}" ng-bind-html="part.text"></span>
<div ng-repeat="metadata in bufferline.metadata"> <div ng-repeat="metadata in bufferline.metadata">
<div ng-show="metadata.visible"> <div ng-show="metadata.visible">

7
js/favico-0.3.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -16,10 +16,10 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
var number = message['number'] var number = message['number']
var pointer = message['pointers'][0] var pointer = message['pointers'][0]
var lines = [] var lines = []
var active = false; var active = false
var notification = false; var notification = 0
var unread = ''; var unread = 0
var lastSeen = -2; var lastSeen = -2
/* /*
* Adds a line to this buffer * Adds a line to this buffer
@ -30,7 +30,7 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
var addLine = function(line) { var addLine = function(line) {
lines.push(line); lines.push(line);
} }
return { return {
id: pointer, id: pointer,
fullName: fullName, fullName: fullName,
@ -40,6 +40,8 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
lines: lines, lines: lines,
addLine: addLine, addLine: addLine,
lastSeen: lastSeen, lastSeen: lastSeen,
unread: unread,
notification: notification,
} }
} }
@ -100,6 +102,8 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
var BufferList = [] var BufferList = []
activeBuffer = null; activeBuffer = null;
unreads = 0;
notifications = 0;
this.model = { 'buffers': {} } this.model = { 'buffers': {} }
@ -161,11 +165,12 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
} }
}); });
activeBuffer.notification = false;
activeBuffer.active = true; activeBuffer.active = true;
activeBuffer.unread = ''; activeBuffer.unread = 0;
activeBuffer.notification = 0;
$rootScope.$emit('activeBufferChanged'); $rootScope.$emit('activeBufferChanged');
$rootScope.$emit('notificationChanged');
} }
/* /*

View File

@ -55,31 +55,46 @@ plugins.service('plugins', ['userPlugins', '$sce', function(userPlugins, $sce)
*/ */
var contentForMessage = function(message) { var contentForMessage = function(message) {
var content = []; message.metadata = [];
for (var i = 0; i < plugins.length; i++) { for (var i = 0; i < plugins.length; i++) {
var nsfw = false; var nsfw = false;
var visible = true; var visible = true;
if (message.match(nsfwRegexp)) { if (message.text.match(nsfwRegexp)) {
var nsfw = true; var nsfw = true;
var visible = false; var visible = false;
} }
var pluginContent = plugins[i].contentForMessage(message); var pluginContent = plugins[i].contentForMessage(message.text);
if (pluginContent) { if (pluginContent) {
var pluginContent = {'visible': visible, var pluginContent = {'visible': visible,
'content': $sce.trustAsHtml(pluginContent), 'content': $sce.trustAsHtml(pluginContent),
'nsfw': nsfw, 'nsfw': nsfw,
'name': plugins[i].name } 'name': plugins[i].name }
content.push(pluginContent); message.metadata.push(pluginContent);
if (plugins[i].exclusive) { if (plugins[i].exclusive) {
break; break;
} }
} }
} }
return content;
/* Replace all URLs with hyperlinks */
var urlRegexp = RegExp(/(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:\/~+#-]*[\w@?^=%&amp;\/~+#-])?/g);
for(k in message.content) {
var text = message.content[k].text;
var url = text.match(urlRegexp);
for(i in url) {
var u = url[i];
text = text.replace(u, '<a target="_blank" href="' + u + '">' + u + '</a>');
}
message.content[k].text = $sce.trustAsHtml(text);
}
return message;
} }
return { return {
@ -124,16 +139,6 @@ plugins.factory('userPlugins', function() {
}); });
youtubePlugin.name = 'youtube video'; youtubePlugin.name = 'youtube video';
var urlPlugin = new Plugin(function(message) {
var url = message.match(urlRegexp);
if (url) {
return '<a target="_blank" href="' + url[0] + '">' + url[0] + '</a>';
}
return null;
});
urlPlugin.name = 'url';
var imagePlugin = new Plugin(function(message) { var imagePlugin = new Plugin(function(message) {
var url = message.match(urlRegexp); var url = message.match(urlRegexp);
@ -149,6 +154,6 @@ plugins.factory('userPlugins', function() {
imagePlugin.name = 'image'; imagePlugin.name = 'image';
return { return {
plugins: [youtubePlugin, urlPlugin, imagePlugin] plugins: [youtubePlugin, imagePlugin]
} }
}); });

View File

@ -191,7 +191,7 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
// Only react to line if its displayed // Only react to line if its displayed
if(message.displayed) { if(message.displayed) {
var buffer = models.getBuffer(message.buffer); var buffer = models.getBuffer(message.buffer);
message.metadata = plugins.PluginManager.contentForMessage(message.text); message = plugins.PluginManager.contentForMessage(message);
buffer.addLine(message); buffer.addLine(message);
if (buffer.active) { if (buffer.active) {
@ -200,16 +200,14 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
if (!initial) { if (!initial) {
if (!buffer.active && _.contains(message.tags, 'notify_message') && !_.contains(message.tags, 'notify_none')) { if (!buffer.active && _.contains(message.tags, 'notify_message') && !_.contains(message.tags, 'notify_none')) {
if (buffer.unread == '' || buffer.unread == undefined) { buffer.unread++;
buffer.unread = 1; $rootScope.$emit('notificationChanged');
}else {
buffer.unread++;
}
} }
if(message.highlight || _.contains(message.tags, 'notify_private') ) { if(message.highlight || _.contains(message.tags, 'notify_private') ) {
buffer.notification++;
$rootScope.createHighlight(buffer, message); $rootScope.createHighlight(buffer, message);
buffer.notification = true; $rootScope.$emit('notificationChanged');
} }
} }
} }
@ -243,18 +241,6 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
old.shortName = obj['short_name']; old.shortName = obj['short_name'];
} }
/*
* Handle answers to (bufinfo) messages
*
* (bufinfo) messages are specified by this client. It is the first
* message that is sent to the relay after connection.
*/
var handleBufferInfo = function(message) {
// buffer info from message
}
/* /*
* Handle answers to (lineinfo) messages * Handle answers to (lineinfo) messages
* *
@ -276,7 +262,6 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
} }
var eventHandlers = { var eventHandlers = {
bufinfo: handleBufferInfo,
lineinfo: handleLineInfo, lineinfo: handleLineInfo,
_buffer_closing: handleBufferClosing, _buffer_closing: handleBufferClosing,
_buffer_line_added: handleBufferLineAdded, _buffer_line_added: handleBufferLineAdded,
@ -292,7 +277,7 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
}]); }]);
weechat.factory('connection', ['$q', '$rootScope', '$log', 'handlers', 'colors', 'models', function($q, $rootScope, $log, handlers, colors, models) { weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'colors', 'models', function($q, $rootScope, $log, storage, handlers, colors, models) {
protocol = new WeeChatProtocol(); protocol = new WeeChatProtocol();
var websocket = null; var websocket = null;
@ -329,14 +314,16 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', 'handlers', 'colors',
websocket.binaryType = "arraybuffer" websocket.binaryType = "arraybuffer"
websocket.onopen = function (evt) { websocket.onopen = function (evt) {
doSend(WeeChatProtocol.formatInit({ $log.info("Connected to relay");
doSend(WeeChatProtocol.formatInit({
password: passwd, password: passwd,
compression: 'off' compression: 'off'
})); }));
doSendWithCallback(WeeChatProtocol.formatHdata({ doSendWithCallback(WeeChatProtocol.formatHdata({
path: 'buffer:gui_buffers(*)', path: 'buffer:gui_buffers(*)',
keys: ['number,full_name,short_name,title'] keys: ['number,full_name,short_name,title']
})).then(function(hdata) { })).then(function(message) {
$log.info("Parsing bufinfo");
var bufferInfos = message['objects'][0]['content']; var bufferInfos = message['objects'][0]['content'];
// buffers objects // buffers objects
for (var i = 0; i < bufferInfos.length ; i++) { for (var i = 0; i < bufferInfos.length ; i++) {
@ -347,16 +334,19 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', 'handlers', 'colors',
models.setActiveBuffer(buffer.id); models.setActiveBuffer(buffer.id);
} }
} }
$rootScope.connected = true;
// Request latest buffer lines for each buffer }).then(function() {
$rootScope.getLines(); $log.info("Parsing lineinfo");
doSendWithCallback(WeeChatProtocol.formatHdata({
path: "buffer:gui_buffers(*)/own_lines/last_line(-"+storage.get('lines')+")/data",
keys: []
})).then(function(hdata) {
handlers.handleLineInfo(hdata);
});
}).then(function() {
doSend(WeeChatProtocol.formatSync({}));
$log.info("Synced");
}); });
doSend(WeeChatProtocol.formatSync({}));
$log.info("Connected to relay");
$rootScope.connected = true;
$rootScope.$apply();
} }
websocket.onclose = function (evt) { websocket.onclose = function (evt) {
@ -395,18 +385,9 @@ weechat.factory('connection', ['$q', '$rootScope', '$log', 'handlers', 'colors',
})); }));
} }
var getLines = function(count) {
doSendWithCallback(WeeChatProtocol.formatHdata({
path: "buffer:gui_buffers(*)/own_lines/last_line(-"+count+")/data",
keys: []
})).then(function(hdata) {
handlers.handleLineInfo(hdata);
});
}
return { return {
send: doSend, send: doSend,
getLines: getLines,
connect: connect, connect: connect,
sendMessage: sendMessage sendMessage: sendMessage
} }
@ -428,13 +409,29 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
} }
} }
$rootScope.$on('activeBufferChanged', function() { $rootScope.$on('activeBufferChanged', function() {
$rootScope.scrollToBottom(); $rootScope.scrollToBottom();
document.getElementById('sendMessage').focus(); document.getElementById('sendMessage').focus();
var ab = models.getActiveBuffer(); var ab = models.getActiveBuffer();
$rootScope.pageTitle = ab.shortName + ' | ' + ab.title; $rootScope.pageTitle = ab.shortName + ' | ' + ab.title;
}); });
$rootScope.$on('notificationChanged', function() {
var notifications = _.reduce(models.model.buffers, function(memo, num) { return (memo||0) + num.notification;});
if (notifications > 0 ) {
$scope.favico = new Favico({
animation:'none'
});
$scope.favico.badge(notifications);
}else {
var unread = _.reduce(models.model.buffers, function(memo, num) { return (memo||0) + num.unread;});
$scope.favico = new Favico({
animation:'none',
bgColor : '#5CB85C',
textColor : '#ff0',
});
$scope.favico.badge(unread);
}
});
$scope.buffers = models.model.buffers; $scope.buffers = models.model.buffers;
$scope.activeBuffer = models.getActiveBuffer $scope.activeBuffer = models.getActiveBuffer
@ -480,9 +477,6 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
$scope.connect = function() { $scope.connect = function() {
connection.connect($scope.host, $scope.port, $scope.password, $scope.ssl); connection.connect($scope.host, $scope.port, $scope.password, $scope.ssl);
} }
$rootScope.getLines = function() {
connection.getLines($scope.lines);
}
/* Function gets called from bufferLineAdded code if user should be notified */ /* Function gets called from bufferLineAdded code if user should be notified */
$rootScope.createHighlight = function(buffer, message) { $rootScope.createHighlight = function(buffer, message) {
@ -510,7 +504,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
if (models.getActiveBuffer() == buffer) { if (models.getActiveBuffer() == buffer) {
return true; return true;
} }
return (parseInt(buffer.unread) || 0) > 0; return buffer.unread > 0;
} }
return true; return true;
}; };
@ -519,10 +513,10 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
// Find next buffer with activity and switch to it // Find next buffer with activity and switch to it
for(i in $scope.buffers) { for(i in $scope.buffers) {
var buffer = $scope.buffers[i]; var buffer = $scope.buffers[i];
if(buffer.notification) { if(buffer.notification > 0) {
$scope.setActiveBuffer(buffer.id); $scope.setActiveBuffer(buffer.id);
break; break;
}else if((parseInt(buffer.unread) || 0) > 0) { }else if(buffer.unread > 0) {
$scope.setActiveBuffer(buffer.id); $scope.setActiveBuffer(buffer.id);
break; break;
} }
@ -560,5 +554,6 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
return true; return true;
} }
}; };
}] }]
); );