Merge
This commit is contained in:
parent
0ba0ded728
commit
8028070aaa
|
@ -1,6 +1,8 @@
|
||||||
A web client for WeeChat
|
A web client for WeeChat
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
Required Weechat version: 0.4.2
|
||||||
|
|
||||||
To use the web interface you first need to set a relay and a password:
|
To use the web interface you first need to set a relay and a password:
|
||||||
|
|
||||||
/relay add weechat 9001
|
/relay add weechat 9001
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
html {
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
|
@ -8,6 +6,11 @@ body {
|
||||||
padding-bottom:70px;
|
padding-bottom:70px;
|
||||||
padding-top: 70px;
|
padding-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input#sendMessage {
|
||||||
|
border: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
.content {
|
.content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
188
index.html
188
index.html
|
@ -1,126 +1,126 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html ng-app="weechat" ng-cloak>
|
<html ng-app="weechat" ng-cloak>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title ng-bind-template="WeeChat {{ pageTitle}}"></title>
|
<title ng-bind-template="WeeChat {{ pageTitle}}"></title>
|
||||||
|
|
||||||
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||||
<link rel="shortcut icon" type="image/png" href="img/favicon.png" >
|
<link rel="shortcut icon" type="image/png" href="img/favicon.png" >
|
||||||
<link href="css/glowingbear.css" rel="stylesheet" media="screen">
|
<link href="css/glowingbear.css" rel="stylesheet" media="screen">
|
||||||
<script type="text/javascript" src="js/angular.min.js"></script>
|
<script type="text/javascript" src="js/angular.min.js"></script>
|
||||||
<script type="text/javascript" src="js/underscore.js"></script>
|
<script type="text/javascript" src="js/underscore.js"></script>
|
||||||
<script type="text/javascript" src="js/localstorage.js"></script>
|
<script type="text/javascript" src="js/localstorage.js"></script>
|
||||||
<script type="text/javascript" src="js/protocol.js"></script>
|
<script type="text/javascript" src="js/weechat-protocol.js"></script>
|
||||||
<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/plugins.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>
|
||||||
<body>
|
<body ng-controller="WeechatCtrl">
|
||||||
<div ng-controller="WeechatCtrl">
|
<nav ng-show="connected" class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
|
||||||
<div ng-hide="connected" class="container">
|
<div class="navbar-header">
|
||||||
<h2>
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
<img src="img/favicon.png">
|
<span class="sr-only">Toggle navigation</span>
|
||||||
glowing bear
|
<span class="icon-bar"></span>
|
||||||
<small>
|
<span class="icon-bar"></span>
|
||||||
WeeChat web frontend
|
<span class="icon-bar"></span>
|
||||||
</small>
|
</button>
|
||||||
</h2>
|
</div>
|
||||||
<div>To start using, please enable relay in your WeeChat client:
|
<div class="navbar-collapse collapse">
|
||||||
<pre>
|
<ul class="nav navbar-nav ">
|
||||||
|
<li class="label" ng-class="{'active': content.active }" ng-repeat="(key, content) in buffers | toArray | orderBy:'content.number':true">
|
||||||
|
<a href="#" ng-click="setActiveBuffer(content.id)" title="{{ content.fullName }}">{{ content.shortName }} <span class="badge" ng-class="{'danger': content.notification }" ng-bind="content.unread"></span></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div ng-hide="connected" class="container">
|
||||||
|
<h2>
|
||||||
|
<img src="img/favicon.png">
|
||||||
|
glowing bear
|
||||||
|
<small>
|
||||||
|
WeeChat web frontend
|
||||||
|
</small>
|
||||||
|
</h2>
|
||||||
|
<div>To start using, please enable relay in your WeeChat client:
|
||||||
|
<pre>
|
||||||
/set relay.network.password yourpassword
|
/set relay.network.password yourpassword
|
||||||
/relay add weechat 9001</pre>
|
/relay add weechat 9001</pre>
|
||||||
Note: The communication goes directly between your browser and your weechat in clear text.
|
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.
|
Connection settings are saved between sessions, including password, in your own browser.
|
||||||
<h4>Encryption</h4>
|
<h4>Encryption</h4>
|
||||||
If you want to use encrypted session you first have to set up the relay using SSL
|
If you want to use encrypted session you first have to set up the relay using SSL
|
||||||
<pre>
|
<pre>
|
||||||
$ mkdir -p ~/.weechat/ssl
|
$ mkdir -p ~/.weechat/ssl
|
||||||
$ cd ~/.weechat/ssl
|
$ cd ~/.weechat/ssl
|
||||||
$ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out relay.pem
|
$ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out relay.pem
|
||||||
</pre>
|
</pre>
|
||||||
If WeeChat is already running, you can reload the certificate and private key with command:
|
If WeeChat is already running, you can reload the certificate and private key with command:
|
||||||
<pre>
|
<pre>
|
||||||
/relay sslcertkey
|
/relay sslcertkey
|
||||||
/relay add ssl.weechat 8000
|
/relay add ssl.weechat 8000
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
|
||||||
<h3>Connection settings</h3>
|
|
||||||
<form role="form">
|
|
||||||
<div class="alert alert-danger" ng-show="errorMessage">
|
|
||||||
<strong>Oh no!</strong> We cannot connect!
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label" for="hostport">Hostname and port</label>
|
|
||||||
<input type="text" class="form-control" id="hostport" ng-model="hostport" placeholder="Hostport">
|
|
||||||
<p class="help-block">Enter the hostname and the port to the WeeChat relay, separated by a :</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">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>
|
|
||||||
<button class="btn btn-lg btn-primary" ng-click="connect()">Connect!</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content" ng-show="connected">
|
<h3>Connection settings</h3>
|
||||||
<nav class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
|
<form role="form">
|
||||||
<div class="navbar-header">
|
<div class="alert alert-danger" ng-show="errorMessage">
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
<strong>Oh no!</strong> We cannot connect!
|
||||||
<span class="sr-only">Toggle navigation</span>
|
</div>
|
||||||
<span class="icon-bar"></span>
|
<div class="form-group">
|
||||||
<span class="icon-bar"></span>
|
<label class="control-label" for="hostport">Hostname and port</label>
|
||||||
<span class="icon-bar"></span>
|
<input type="text" class="form-control" id="hostport" ng-model="hostport" placeholder="Hostport">
|
||||||
</button>
|
<p class="help-block">Enter the hostname and the port to the WeeChat relay, separated by a :</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-collapse collapse">
|
<div class="form-group">
|
||||||
<ul class="nav navbar-nav ">
|
<label class="control-label" for="password">WeeChat relay password</label>
|
||||||
<li class="label" ng-class="{'active': content.active }" ng-repeat="(key, content) in buffers | toArray | orderBy:'content.number':true">
|
<input type="password" class="form-control" id="password" ng-model="password" placeholder="Password">
|
||||||
<a ng-click="setActiveBuffer(content.id)" title="{{ content.full_name }}">{{ content.short_name }} <span class="badge" ng-class="{'danger': content.highlight }" ng-bind="content.unread"></span></a>
|
<p class="help-block">Password will be stored in your browser session</p>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
<div class="form-group">
|
||||||
</div>
|
<label class="control-label" for="proto">Encryption</label>
|
||||||
</nav>
|
<input type="checkbox" class="form-control" id="ssl" ng-model="ssl">
|
||||||
<div class="bufferlines">
|
<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="bufferline" ng-repeat="bufferline in activeBuffer.lines">
|
</div>
|
||||||
<span class="date text-muted">
|
<button class="btn btn-lg btn-primary" ng-click="connect()">Connect!</button>
|
||||||
{{ bufferline.date | date:'HH:mm' }}
|
</form>
|
||||||
</span>
|
</div>
|
||||||
|
<div class="content" ng-show="connected">
|
||||||
|
<div class="bufferlines">
|
||||||
|
<div class="bufferline" ng-repeat="bufferline in activeBuffer().lines">
|
||||||
|
<span class="date text-muted">
|
||||||
|
{{ bufferline.date | date:'HH:mm' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<span ng-repeat="part in bufferline.message" class="text" style="{{ part.fg }}">
|
<span ng-repeat="part in bufferline.content" class="text" style="{{ part.fg }}">
|
||||||
{{ part.text }}
|
{{ part.text }}
|
||||||
</span>
|
</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">
|
||||||
<a ng-click="metadata.visible = false">Hide additional content</a>
|
<a ng-click="metadata.visible = false">Hide additional content</a>
|
||||||
<div ng-bind-html-unsafe="metadata.content"></div>
|
<div ng-bind-html-unsafe="metadata.content"></div>
|
||||||
|
|
||||||
</div>
|
|
||||||
<div ng-hide="metadata.visible">
|
|
||||||
<a ng-click="metadata.visible = true">Show additional content</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div ng-hide="metadata.visible">
|
||||||
|
<a ng-click="metadata.visible = true">Show additional content</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="navbar navbar-inverse navbar-fixed-bottom">
|
</div>
|
||||||
<form class="form form-horizontal" ng-submit="sendMessage()">
|
<div id="footer" ng-show="connected">
|
||||||
<div class="input-group">
|
<div class="navbar navbar-inverse navbar-fixed-bottom">
|
||||||
<input type="text" class="form-control" ng-model="command"></input>
|
<form class="form form-horizontal" ng-submit="sendMessage()">
|
||||||
<span class="input-group-btn">
|
<div class="input-group">
|
||||||
<button class="btn btn-default btn-primary">Send</button>
|
<input id="sendMessage" type="text" class="form-control" ng-model="command">
|
||||||
</span>
|
<span class="input-group-btn">
|
||||||
</div>
|
<button class="btn btn-default btn-primary">Send</button>
|
||||||
</form>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* This file contains the weechat models and various
|
||||||
|
* helper methods to work with them.
|
||||||
|
*/
|
||||||
|
var models = angular.module('weechatModels', []);
|
||||||
|
|
||||||
|
models.service('models', ['colors', function(colors) {
|
||||||
|
/*
|
||||||
|
* Buffer class
|
||||||
|
*/
|
||||||
|
this.Buffer = function(message) {
|
||||||
|
// weechat properties
|
||||||
|
var fullName = message['full_name']
|
||||||
|
var shortName = message['short_name']
|
||||||
|
var title = message['title']
|
||||||
|
var number = message['number']
|
||||||
|
var pointer = message['pointers'][0]
|
||||||
|
var lines = []
|
||||||
|
var active = false;
|
||||||
|
var notification = false;
|
||||||
|
var unread = '';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds a line to this buffer
|
||||||
|
*
|
||||||
|
* @param line the BufferLine object
|
||||||
|
* @return undefined
|
||||||
|
*/
|
||||||
|
var addLine = function(line) {
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: pointer,
|
||||||
|
fullName: fullName,
|
||||||
|
shortName: shortName,
|
||||||
|
number: number,
|
||||||
|
title: title,
|
||||||
|
lines: lines,
|
||||||
|
addLine: addLine
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BufferLine class
|
||||||
|
*/
|
||||||
|
this.BufferLine = function(message) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the text elements from the buffer line added
|
||||||
|
*
|
||||||
|
* @param message weechat message
|
||||||
|
*/
|
||||||
|
function parseLineAddedTextElements(message) {
|
||||||
|
var prefix = colors.parse(message['prefix']);
|
||||||
|
|
||||||
|
var buffer = message['buffer'];
|
||||||
|
text_elements = _.union(prefix, text);
|
||||||
|
text_elements =_.map(text_elements, function(text_element) {
|
||||||
|
if (text_element && ('fg' in text_element)) {
|
||||||
|
text_element['fg'] = colors.prepareCss(text_element['fg']);
|
||||||
|
}
|
||||||
|
// TODO: parse background as well
|
||||||
|
|
||||||
|
return text_element;
|
||||||
|
});
|
||||||
|
return text_elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var buffer = message['buffer'];
|
||||||
|
var date = message['date'];
|
||||||
|
var text = colors.parse(message['message']);
|
||||||
|
var tags_array = message['tags_array'];
|
||||||
|
var displayed = message['displayed'];
|
||||||
|
var highlight = message['highlight'];
|
||||||
|
var content = parseLineAddedTextElements(message);
|
||||||
|
var text = "";
|
||||||
|
if(text[0] != undefined) {
|
||||||
|
text = text[0]['text'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: content,
|
||||||
|
date: date,
|
||||||
|
buffer: buffer,
|
||||||
|
tags: tags_array,
|
||||||
|
highlight: highlight,
|
||||||
|
displayed: displayed,
|
||||||
|
text: text,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var BufferList = []
|
||||||
|
activeBuffer = null;
|
||||||
|
|
||||||
|
this.model = { 'buffers': {} }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds a buffer to the list
|
||||||
|
*
|
||||||
|
* @param buffer buffer object
|
||||||
|
* @return undefined
|
||||||
|
*/
|
||||||
|
this.addBuffer = function(buffer) {
|
||||||
|
BufferList[buffer.id] = buffer;
|
||||||
|
if (BufferList.length == 1) {
|
||||||
|
activeBuffer = buffer.id;
|
||||||
|
}
|
||||||
|
this.model.buffers[buffer.id] = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the current active buffer
|
||||||
|
*
|
||||||
|
* @return active buffer object
|
||||||
|
*/
|
||||||
|
this.getActiveBuffer = function() {
|
||||||
|
return activeBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the buffer specifiee by bufferId as active.
|
||||||
|
* Deactivates the previous current buffer.
|
||||||
|
*
|
||||||
|
* @param bufferId id of the new active buffer
|
||||||
|
* @return undefined
|
||||||
|
*/
|
||||||
|
this.setActiveBuffer = function(bufferId) {
|
||||||
|
|
||||||
|
if (this.getActiveBuffer()) {
|
||||||
|
this.getActiveBuffer().active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeBuffer = _.find(this.model['buffers'], function(buffer) {
|
||||||
|
if (buffer['id'] == bufferId) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
activeBuffer.notification = false;
|
||||||
|
activeBuffer.active = true;
|
||||||
|
activeBuffer.unread = '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the buffer list
|
||||||
|
*/
|
||||||
|
this.getBuffers = function() {
|
||||||
|
return BufferList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a specific buffer object
|
||||||
|
*
|
||||||
|
* @param bufferId id of the buffer
|
||||||
|
* @return the buffer object
|
||||||
|
*/
|
||||||
|
this.getBuffer = function(bufferId) {
|
||||||
|
return _.find(this.model['buffers'], function(buffer) {
|
||||||
|
if (buffer['id'] == bufferId) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Closes a weechat buffer. Sets the first buffer
|
||||||
|
* as active.
|
||||||
|
*
|
||||||
|
* @param bufferId id of the buffer to close
|
||||||
|
* @return undefined
|
||||||
|
*/
|
||||||
|
this.closeBuffer = function(bufferId) {
|
||||||
|
|
||||||
|
delete(this.model['buffers'][bufferId.id]);
|
||||||
|
var firstBuffer = _.keys(this.model['buffers'])[0];
|
||||||
|
this.setActiveBuffer(firstBuffer);
|
||||||
|
}
|
||||||
|
}]);
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* This file contains the plugin definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins = angular.module('plugins', []);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definition of a user provided plugin with sensible default values
|
||||||
|
*
|
||||||
|
* User plugins are created by providing a contentForMessage function
|
||||||
|
* that parses a string and return any additional content.
|
||||||
|
*/
|
||||||
|
var Plugin = function(contentForMessage) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
contentForMessage: contentForMessage,
|
||||||
|
exclusive: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This service provides access to the plugin manager
|
||||||
|
*
|
||||||
|
* The plugin manager is where the various user provided plugins
|
||||||
|
* are registered. It is responsible for finding additional content
|
||||||
|
* to display when messages are received.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
plugins.service('plugins', ['userPlugins', function(userPlugins) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Defines the plugin manager object
|
||||||
|
*/
|
||||||
|
var PluginManagerObject = function() {
|
||||||
|
|
||||||
|
var plugins = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register the user provides plugins
|
||||||
|
*
|
||||||
|
* @param userPlugins user provided plugins
|
||||||
|
*/
|
||||||
|
var registerPlugins = function(userPlugins) {
|
||||||
|
for (var i = 0; i < userPlugins.length; i++) {
|
||||||
|
plugins.push(userPlugins[i]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterates through all the registered plugins
|
||||||
|
* and run their contentForMessage function.
|
||||||
|
*/
|
||||||
|
var contentForMessage = function(message) {
|
||||||
|
|
||||||
|
var content = [];
|
||||||
|
for (var i = 0; i < plugins.length; i++) {
|
||||||
|
var pluginContent = plugins[i].contentForMessage(message);
|
||||||
|
if (pluginContent) {
|
||||||
|
var pluginContent = {'visible': false,
|
||||||
|
'content': pluginContent }
|
||||||
|
content.push(pluginContent);
|
||||||
|
|
||||||
|
if (plugins[i].exclusive) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
registerPlugins: registerPlugins,
|
||||||
|
contentForMessage: contentForMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instanciates and registers the plugin manager.
|
||||||
|
this.PluginManager = new PluginManagerObject();
|
||||||
|
this.PluginManager.registerPlugins(userPlugins.plugins);
|
||||||
|
|
||||||
|
}]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This factory exposes the collection of user provided plugins.
|
||||||
|
*
|
||||||
|
* To create your own plugin, you need to:
|
||||||
|
*
|
||||||
|
* 1. Define it's contentForMessage function. The contentForMessage
|
||||||
|
* function takes a string as a parameter and returns a HTML string.
|
||||||
|
*
|
||||||
|
* 2. Instanciate a Plugin object with contentForMessage function as it's
|
||||||
|
* argument.
|
||||||
|
*
|
||||||
|
* 3. Add it to the plugins array.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
plugins.factory('userPlugins', function() {
|
||||||
|
|
||||||
|
var youtubePlugin = new Plugin(function(message) {
|
||||||
|
|
||||||
|
if (message.indexOf('youtube.com') != -1) {
|
||||||
|
var index = message.indexOf("?v=");
|
||||||
|
var token = message.substr(index+3);
|
||||||
|
return '<iframe width="560" height="315" src="http://www.youtube.com/embed/' + token + '" frameborder="0" allowfullscreen></iframe>'
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
var urlPlugin = new Plugin(function(message) {
|
||||||
|
var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/;
|
||||||
|
var url = message.match(urlPattern);
|
||||||
|
if (url) {
|
||||||
|
return '<a href="' + url[0] + '">' + message + '</a>';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var imagePlugin = new Plugin(function(message) {
|
||||||
|
var urls = message.match(/https?:\/\/[^\s]*\.(jpg|png|gif)\b/)
|
||||||
|
if (urls != null) {
|
||||||
|
var url = urls[0]; /* Actually parse one url per message */
|
||||||
|
return '<img src="' + url + '" height="300">';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugins: [youtubePlugin, urlPlugin, imagePlugin]
|
||||||
|
}
|
||||||
|
});
|
180
js/protocol.js
180
js/protocol.js
|
@ -1,180 +0,0 @@
|
||||||
var Protocol = function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var getInfo = function() {
|
|
||||||
var info = {};
|
|
||||||
info.key = getString();
|
|
||||||
info.value = getString();
|
|
||||||
return info;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getHdata = function() {
|
|
||||||
var paths;
|
|
||||||
var count;
|
|
||||||
var objs = [];
|
|
||||||
var hpath = getString();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
keys = getString().split(',');
|
|
||||||
paths = hpath.split('/');
|
|
||||||
count = getInt();
|
|
||||||
|
|
||||||
keys = keys.map(function(key) {
|
|
||||||
return key.split(':');
|
|
||||||
});
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
var tmp = {};
|
|
||||||
|
|
||||||
tmp.pointers = paths.map(function(path) {
|
|
||||||
return getPointer();
|
|
||||||
});
|
|
||||||
|
|
||||||
keys.forEach(function(key) {
|
|
||||||
tmp[key[0]] = runType(key[1]);
|
|
||||||
});
|
|
||||||
objs.push(tmp);
|
|
||||||
};
|
|
||||||
return objs;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getPointer() {
|
|
||||||
var l = getChar();
|
|
||||||
|
|
||||||
var pointer = getSlice(l)
|
|
||||||
var parsed_data = new Uint8Array(pointer);
|
|
||||||
return _uiatos(parsed_data);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
var _uiatos =function(uia) {
|
|
||||||
var _str = [];
|
|
||||||
for (var c = 0; c < uia.length; c++) {
|
|
||||||
_str[c] = String.fromCharCode(uia[c]);
|
|
||||||
}
|
|
||||||
return decodeURIComponent(escape(_str.join("")));
|
|
||||||
};
|
|
||||||
|
|
||||||
var getInt = function() {
|
|
||||||
var parsed_data = new Uint8Array(getSlice(4));
|
|
||||||
var i = ((parsed_data[0] & 0xff) << 24) | ((parsed_data[1] & 0xff) << 16) | ((parsed_data[2] & 0xff) << 8) | (parsed_data[3] & 0xff);
|
|
||||||
return i;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
var getChar = function() {
|
|
||||||
var parsed_data = new Uint8Array(getSlice(1));
|
|
||||||
return parsed_data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
var getString = function() {
|
|
||||||
var l = getInt();
|
|
||||||
if (l > 0) {
|
|
||||||
var s = getSlice(l);
|
|
||||||
var parsed_data = new Uint8Array(s);
|
|
||||||
return _uiatos(parsed_data);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
var getSlice = function(length) {
|
|
||||||
var slice = self.data.slice(0,length);
|
|
||||||
self.data = self.data.slice(length);
|
|
||||||
return slice;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getType = function() {
|
|
||||||
var t = getSlice(3);
|
|
||||||
return _uiatos(new Uint8Array(t));
|
|
||||||
};
|
|
||||||
|
|
||||||
var runType = function(type) {
|
|
||||||
if (type in types) {
|
|
||||||
return types[type]();
|
|
||||||
}
|
|
||||||
0;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getHeader = function() {
|
|
||||||
return {
|
|
||||||
length: getInt(),
|
|
||||||
compression: getChar(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var getId = function() {
|
|
||||||
return getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
var getObject = function() {
|
|
||||||
var type = getType();
|
|
||||||
if (type) {
|
|
||||||
return object = {
|
|
||||||
type: type,
|
|
||||||
content: runType(type),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.parse = function(data) {
|
|
||||||
self.setData(data);
|
|
||||||
var header = getHeader();
|
|
||||||
var id = getId();
|
|
||||||
var objects = [];
|
|
||||||
var object = getObject();
|
|
||||||
while(object) {
|
|
||||||
objects.push(object);
|
|
||||||
object = getObject();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
header: header,
|
|
||||||
id: id,
|
|
||||||
objects: objects,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setData = function (data) {
|
|
||||||
self.data = data;
|
|
||||||
};
|
|
||||||
|
|
||||||
function array() {
|
|
||||||
var type;
|
|
||||||
var count;
|
|
||||||
var values;
|
|
||||||
|
|
||||||
type = getType();
|
|
||||||
count = getInt();
|
|
||||||
values = [];
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
values.push(runType(type));
|
|
||||||
};
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
var types = {
|
|
||||||
chr: getChar,
|
|
||||||
"int": getInt,
|
|
||||||
str: getString,
|
|
||||||
inf: getInfo,
|
|
||||||
hda: getHdata,
|
|
||||||
ptr: getPointer,
|
|
||||||
lon: getPointer,
|
|
||||||
tim: getPointer,
|
|
||||||
buf: getString,
|
|
||||||
arr: array
|
|
||||||
};
|
|
||||||
//TODO: IMPLEMENT THIS STUFF
|
|
||||||
// chr: this.getChar,
|
|
||||||
// 'int': getInt,
|
|
||||||
// hacks
|
|
||||||
|
|
||||||
// hacks
|
|
||||||
// htb: getHashtable,
|
|
||||||
// inf: Protocol.getInfo,
|
|
||||||
// inl: getInfolist,
|
|
||||||
|
|
||||||
// },
|
|
||||||
|
|
||||||
}
|
|
308
js/websockets.js
308
js/websockets.js
|
@ -1,4 +1,5 @@
|
||||||
var weechat = angular.module('weechat', ['localStorage']);
|
var weechat = angular.module('weechat', ['localStorage', 'weechatModels', 'plugins']);
|
||||||
|
|
||||||
weechat.filter('toArray', function () {
|
weechat.filter('toArray', function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ weechat.factory('colors', [function($scope) {
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
setAttrs: setAttrs,
|
setAttrs: setAttrs,
|
||||||
getColor: getColor,
|
getColor: getColor,
|
||||||
prepareCss: prepareCss,
|
prepareCss: prepareCss,
|
||||||
|
@ -177,142 +178,39 @@ weechat.factory('colors', [function($scope) {
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
weechat.factory('pluginManager', ['youtubePlugin', 'urlPlugin', 'imagePlugin', function(youtubePlugin, urlPlugin, imagePlugin) {
|
weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', function($rootScope, colors, models, plugins) {
|
||||||
|
|
||||||
var plugins = [youtubePlugin, urlPlugin, imagePlugin]
|
|
||||||
|
|
||||||
var hookPlugin = function(plugin) {
|
|
||||||
plugins.push(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
var contentForMessage = function(message) {
|
|
||||||
|
|
||||||
console.log('Message: ', message);
|
|
||||||
var content = [];
|
|
||||||
for (var i = 0; i < plugins.length; i++) {
|
|
||||||
var pluginContent = plugins[i].contentForMessage(message);
|
|
||||||
if (pluginContent) {
|
|
||||||
var pluginContent = {'visible': false, 'content': pluginContent }
|
|
||||||
content.push(pluginContent);
|
|
||||||
|
|
||||||
if (plugins[i].exclusive) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Content: ', content);
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
hookPlugin: hookPlugin,
|
|
||||||
contentForMessage: contentForMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
||||||
weechat.factory('youtubePlugin', [function() {
|
|
||||||
|
|
||||||
var contentForMessage = function(message) {
|
|
||||||
if (message.indexOf('youtube.com') != -1) {
|
|
||||||
var index = message.indexOf("?v=");
|
|
||||||
var token = message.substr(index+3);
|
|
||||||
return '<iframe width="560" height="315" src="http://www.youtube.com/embed/' + token + '" frameborder="0" allowfullscreen></iframe>'
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
contentForMessage: contentForMessage,
|
|
||||||
exclusive: true
|
|
||||||
}
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
||||||
weechat.factory('urlPlugin', [function() {
|
|
||||||
var contentForMessage = function(message) {
|
|
||||||
var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/;
|
|
||||||
var url = message.match(urlPattern);
|
|
||||||
if (url) {
|
|
||||||
return '<a target="_blank" href="' + url[0] + '">' + message + '</a>';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
contentForMessage: contentForMessage,
|
|
||||||
exclusive: false
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
weechat.factory('imagePlugin', [function() {
|
|
||||||
var contentForMessage = function(message) {
|
|
||||||
var urls = message.match(/https?:\/\/[^\s]*\.(jpg|png|gif)\b/)
|
|
||||||
if (urls != null) {
|
|
||||||
var url = urls[0]; /* Actually parse one url per message */
|
|
||||||
return '<img src="' + url + '" height="300">';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
contentForMessage: contentForMessage
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
weechat.factory('handlers', ['$rootScope', 'colors', 'pluginManager', function($rootScope, colors, pluginManager) {
|
|
||||||
|
|
||||||
var handleBufferClosing = function(message) {
|
var handleBufferClosing = function(message) {
|
||||||
var buffer_pointer = message['objects'][0]['content'][0]['pointers'][0];
|
var bufferMessage = message['objects'][0]['content'][0];
|
||||||
$rootScope.closeBuffer(buffer_pointer);
|
var buffer = new models.Buffer(bufferMessage);
|
||||||
|
models.closeBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
var handleLine = function(line, initial) {
|
var handleLine = function(line, initial) {
|
||||||
var buffer_line = {}
|
var message = new models.BufferLine(line);
|
||||||
var date = line['date']*1000;
|
|
||||||
var prefix = colors.parse(line['prefix']);
|
|
||||||
var text = colors.parse(line['message']);
|
|
||||||
var buffer = line['buffer'];
|
|
||||||
var tags_array = line['tags_array'];
|
|
||||||
var displayed = line['displayed'];
|
|
||||||
var highlight = line['highlight'];
|
|
||||||
var message = _.union(prefix, text);
|
|
||||||
message =_.map(message, function(message) {
|
|
||||||
if (message != "" && 'fg' in message) {
|
|
||||||
message['fg'] = colors.prepareCss(message['fg']);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
});
|
|
||||||
// Only react to line if its displayed
|
// Only react to line if its displayed
|
||||||
if (displayed) {
|
if(message.displayed) {
|
||||||
buffer_line['message'] = message;
|
var buffer = models.getBuffer(message.buffer);
|
||||||
|
message.metadata = plugins.PluginManager.contentForMessage(message.text);
|
||||||
|
buffer.addLine(message);
|
||||||
|
|
||||||
|
if (buffer.active) {
|
||||||
|
$rootScope.scrollToBottom();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_isActiveBuffer(buffer) && !initial && !_.contains(tags_array, 'notify_none')) {
|
if (!initial) {
|
||||||
|
if (!buffer.active && _.contains(message.tags, 'notify_message') && !_.contains(message.tags, 'notify_none')) {
|
||||||
if ($rootScope.buffers[buffer]['unread'] == '') {
|
if (buffer.unread == '' || buffer.unread == undefined) {
|
||||||
$rootScope.buffers[buffer]['unread'] = 1;
|
buffer.unread = 1;
|
||||||
}else {
|
}else {
|
||||||
$rootScope.buffers[buffer]['unread'] = parseInt($rootScope.buffers[buffer]['unread']) + 1;
|
buffer.unread++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (text[0] != undefined) {
|
if(message.highlight || _.contains(message.tags, 'notify_private') ) {
|
||||||
var additionalContent = pluginManager.contentForMessage(text[0]['text']);
|
$rootScope.createHighlight(buffer, message);
|
||||||
|
buffer.notification = true;
|
||||||
if (additionalContent) {
|
}
|
||||||
buffer_line['metadata'] = additionalContent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$rootScope.addLine(buffer, buffer_line);
|
|
||||||
|
|
||||||
buffer_line['date'] = date;
|
|
||||||
|
|
||||||
if(!initial && (highlight || _.contains(tags_array, 'notify_private')) ) {
|
|
||||||
$rootScope.createHighlight(prefix, text, message, buffer, additionalContent);
|
|
||||||
$rootScope.buffers[buffer]['highlight'] = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,26 +221,10 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'pluginManager', function($
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns whether or not this buffer is the active buffer
|
|
||||||
*/
|
|
||||||
var _isActiveBuffer = function(buffer) {
|
|
||||||
if ($rootScope.activeBuffer['id'] == buffer) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var handleBufferOpened = function(message) {
|
var handleBufferOpened = function(message) {
|
||||||
var obj = message['objects'][0]['content'][0];
|
var bufferMessage = message['objects'][0]['content'][0];
|
||||||
var fullName = obj['full_name'];
|
var buffer = new models.Buffer(bufferMessage);
|
||||||
var buffer = obj['pointers'][0];
|
models.addBuffer(buffer);
|
||||||
var short_name = obj['short_name'];
|
|
||||||
var title = obj['title'];
|
|
||||||
|
|
||||||
$rootScope.buffers[buffer] = { 'id': buffer, 'lines':[], 'full_name':fullName, 'short_name':short_name, 'title':title, 'unread':'' }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var handleBufferTitleChanged = function(message) {
|
var handleBufferTitleChanged = function(message) {
|
||||||
|
@ -371,21 +253,10 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'pluginManager', function($
|
||||||
// buffer info from message
|
// buffer info from message
|
||||||
var bufferInfos = message['objects'][0]['content'];
|
var bufferInfos = message['objects'][0]['content'];
|
||||||
// buffers objects
|
// buffers objects
|
||||||
var buffers = {};
|
|
||||||
for (var i = 0; i < bufferInfos.length ; i++) {
|
for (var i = 0; i < bufferInfos.length ; i++) {
|
||||||
var bufferInfo = bufferInfos[i];
|
var buffer = new models.Buffer(bufferInfos[i]);
|
||||||
var pointer = bufferInfo['pointers'][0];
|
models.addBuffer(buffer);
|
||||||
bufferInfo['id'] = pointer;
|
|
||||||
bufferInfo['lines'] = [];
|
|
||||||
bufferInfo['unread'] = '';
|
|
||||||
buffers[pointer] = bufferInfo
|
|
||||||
if (i == 0) {
|
|
||||||
// first buffer is active buffer by default
|
|
||||||
$rootScope.activeBuffer = buffers[pointer];
|
|
||||||
$rootScope.activeBuffer['active'] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$rootScope.buffers = buffers;
|
|
||||||
|
|
||||||
// Request latest buffer lines for each buffer
|
// Request latest buffer lines for each buffer
|
||||||
$rootScope.getLines();
|
$rootScope.getLines();
|
||||||
|
@ -403,7 +274,7 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'pluginManager', function($
|
||||||
handleLine(l, true);
|
handleLine(l, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var handleEvent = function(event) {
|
var handleEvent = function(event) {
|
||||||
if (_.has(eventHandlers, event['id'])) {
|
if (_.has(eventHandlers, event['id'])) {
|
||||||
eventHandlers[event['id']](event);
|
eventHandlers[event['id']](event);
|
||||||
|
@ -411,15 +282,6 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'pluginManager', function($
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var findMetaData = function(message) {
|
|
||||||
if (message.indexOf('youtube.com') != -1) {
|
|
||||||
var index = message.indexOf("?v=");
|
|
||||||
var token = message.substr(index+3);
|
|
||||||
return '<iframe width="560" height="315" src="http://www.youtube.com/embed/' + token + '" frameborder="0" allowfullscreen></iframe>'
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventHandlers = {
|
var eventHandlers = {
|
||||||
bufinfo: handleBufferInfo,
|
bufinfo: handleBufferInfo,
|
||||||
lineinfo: handleLineInfo,
|
lineinfo: handleLineInfo,
|
||||||
|
@ -437,12 +299,12 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'pluginManager', function($
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
weechat.factory('connection', ['$rootScope', '$log', 'handlers', 'colors', function($rootScope, $log, handlers, colors) {
|
weechat.factory('connection', ['$rootScope', '$log', 'handlers', 'colors', 'models', function($rootScope, $log, handlers, colors, models) {
|
||||||
protocol = new Protocol();
|
protocol = new WeeChatProtocol();
|
||||||
var websocket = null;
|
var websocket = null;
|
||||||
|
|
||||||
|
|
||||||
// Sanitizes messages to be sent to the weechat relay
|
// Sanitizes messages to be sent to the weechat relay
|
||||||
var doSend = function(message) {
|
var doSend = function(message) {
|
||||||
msgs = message.replace(/[\r\n]+$/g, "").split("\n");
|
msgs = message.replace(/[\r\n]+$/g, "").split("\n");
|
||||||
for (var i = 0; i < msgs.length; i++) {
|
for (var i = 0; i < msgs.length; i++) {
|
||||||
|
@ -451,23 +313,26 @@ weechat.factory('connection', ['$rootScope', '$log', 'handlers', 'colors', funct
|
||||||
}
|
}
|
||||||
websocket.send(message);
|
websocket.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes care of the connection and websocket hooks
|
// Takes care of the connection and websocket hooks
|
||||||
var connect = function (hostport, password, ssl) {
|
var connect = function (hostport, passwd, ssl) {
|
||||||
var proto = ssl ? 'wss':'ws';
|
var proto = ssl ? 'wss':'ws';
|
||||||
websocket = new WebSocket(proto+"://" + hostport + "/weechat");
|
websocket = new WebSocket(proto+"://" + hostport + "/weechat");
|
||||||
websocket.binaryType = "arraybuffer"
|
websocket.binaryType = "arraybuffer"
|
||||||
|
|
||||||
websocket.onopen = function (evt) {
|
websocket.onopen = function (evt) {
|
||||||
var send = "";
|
doSend(WeeChatProtocol.formatInit({
|
||||||
if (password) {
|
password: passwd,
|
||||||
send += "init compression=off,password=" + password + "\n";
|
compression: 'off'
|
||||||
}
|
}));
|
||||||
|
doSend(WeeChatProtocol.formatHdata({
|
||||||
|
id: 'bufinfo',
|
||||||
|
path: 'buffer:gui_buffers(*)',
|
||||||
|
keys: ['number,full_name,short_name,title']
|
||||||
|
}));
|
||||||
|
doSend(WeeChatProtocol.formatSync({}));
|
||||||
|
|
||||||
send += "(bufinfo) hdata buffer:gui_buffers(*) number,full_name,short_name,title\n";
|
|
||||||
send += "sync\n";
|
|
||||||
$log.info("Connected to relay");
|
$log.info("Connected to relay");
|
||||||
doSend(send);
|
|
||||||
$rootScope.connected = true;
|
$rootScope.connected = true;
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
}
|
}
|
||||||
|
@ -496,13 +361,18 @@ weechat.factory('connection', ['$rootScope', '$log', 'handlers', 'colors', funct
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendMessage = function(message) {
|
var sendMessage = function(message) {
|
||||||
message = "input " + $rootScope.activeBuffer['full_name'] + " " + message + "\n"
|
doSend(WeeChatProtocol.formatInput({
|
||||||
doSend(message);
|
buffer: models.getActiveBuffer()['fullName'],
|
||||||
|
data: message
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
var getLines = function(count) {
|
var getLines = function(count) {
|
||||||
var message = "(lineinfo) hdata buffer:gui_buffers(*)/own_lines/last_line(-"+count+")/data\n";
|
doSend(WeeChatProtocol.formatHdata({
|
||||||
doSend(message)
|
id: 'lineinfo',
|
||||||
|
path: "buffer:gui_buffers(*)/own_lines/last_line(-"+count+")/data",
|
||||||
|
keys: []
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -513,8 +383,8 @@ weechat.factory('connection', ['$rootScope', '$log', 'handlers', 'colors', funct
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', 'connection', function ($rootScope, $scope, $store, connection) {
|
weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', 'models', 'connection', function ($rootScope, $scope, $store, models, connection, testService) {
|
||||||
|
|
||||||
// Request notification permission
|
// Request notification permission
|
||||||
Notification.requestPermission(function (status) {
|
Notification.requestPermission(function (status) {
|
||||||
console.log('Notification permission status:',status);
|
console.log('Notification permission status:',status);
|
||||||
|
@ -529,30 +399,38 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', 'connection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$scope.buffers = models.model.buffers;
|
||||||
|
$scope.activeBuffer = models.getActiveBuffer
|
||||||
|
|
||||||
|
$scope.incrementAge = function () {
|
||||||
|
models.model.age++;
|
||||||
|
models.model.cats.push('nouveau chat');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$scope.clickS = function () {
|
||||||
|
$scope.countS = testService.incrementCount();
|
||||||
|
};
|
||||||
|
|
||||||
$rootScope.commands = []
|
$rootScope.commands = []
|
||||||
|
|
||||||
|
$rootScope.models = models;
|
||||||
|
|
||||||
$rootScope.buffer = []
|
$rootScope.buffer = []
|
||||||
$rootScope.buffers = {}
|
|
||||||
$rootScope.activeBuffer = null;
|
|
||||||
$store.bind($scope, "hostport", "localhost:9001");
|
$store.bind($scope, "hostport", "localhost:9001");
|
||||||
$store.bind($scope, "proto", "weechat");
|
$store.bind($scope, "proto", "weechat");
|
||||||
$store.bind($scope, "password", "");
|
$store.bind($scope, "password", "");
|
||||||
|
$store.bind($scope, "ssl", false);
|
||||||
// TODO checkbox for saving password or not?
|
// TODO checkbox for saving password or not?
|
||||||
// $scope.password = "";
|
// $scope.password = "";
|
||||||
|
|
||||||
$rootScope.closeBuffer = function(buffer_pointer) {
|
|
||||||
delete($rootScope.buffers[buffer_pointer]);
|
|
||||||
var first_buffer = _.keys($rootScope.buffers)[0];
|
|
||||||
$scope.setActiveBuffer(first_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.setActiveBuffer = function(key) {
|
$scope.setActiveBuffer = function(key) {
|
||||||
$rootScope.activeBuffer['active'] = false;
|
models.setActiveBuffer(key);
|
||||||
$rootScope.buffers[key]['active'] = true;
|
var ab = models.getActiveBuffer();
|
||||||
$rootScope.buffers[key]['highlight'] = false;
|
$rootScope.pageTitle = ab.shortName + ' | ' + ab.title;
|
||||||
$rootScope.buffers[key]['unread'] = '';
|
|
||||||
$rootScope.activeBuffer = $rootScope.buffers[key];
|
|
||||||
$rootScope.pageTitle = $rootScope.activeBuffer['short_name'] + ' | ' + $rootScope.activeBuffer['title'];
|
|
||||||
$rootScope.scrollToBottom();
|
$rootScope.scrollToBottom();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -562,14 +440,6 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', 'connection
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$rootScope.addLine = function(buffer, line) {
|
|
||||||
$rootScope.buffers[buffer]['lines'].push(line);
|
|
||||||
// Scroll if needed
|
|
||||||
if ($rootScope.activeBuffer['id'] == buffer) {
|
|
||||||
$rootScope.scrollToBottom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$rootScope.scrollToBottom = function() {
|
$rootScope.scrollToBottom = function() {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
window.scrollTo(0, window.scrollMaxY);
|
window.scrollTo(0, window.scrollMaxY);
|
||||||
|
@ -590,22 +460,18 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', 'connection
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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(prefix, text, message, buffer, additionalContent) {
|
$rootScope.createHighlight = function(buffer, message) {
|
||||||
var prefixs = "";
|
|
||||||
prefixs += prefix[0].text;
|
|
||||||
if(prefix[1] != undefined) {
|
|
||||||
prefixs += prefix[1].text;
|
|
||||||
}
|
|
||||||
var messages = "";
|
var messages = "";
|
||||||
messages += text[0].text;
|
message.content.forEach(function(part) {
|
||||||
|
if (part.text != undefined)
|
||||||
|
messages += part.text + " ";
|
||||||
|
});
|
||||||
|
|
||||||
var buffers = $rootScope.buffers[buffer];
|
var title = buffer.fullName;
|
||||||
|
var content = messages;
|
||||||
var title = buffers.full_name;
|
|
||||||
var content = "<"+prefixs+">"+messages;
|
|
||||||
|
|
||||||
var timeout = 15*1000;
|
var timeout = 15*1000;
|
||||||
console.log('Displaying notification:',title,',with timeout:',timeout);
|
console.log('Displaying notification:buffer:',buffer,',message:',message,',with timeout:',timeout);
|
||||||
var notification = new Notification(title, {body:content, icon:'img/favicon.png'});
|
var notification = new Notification(title, {body:content, icon:'img/favicon.png'});
|
||||||
// Cancel notification automatically
|
// Cancel notification automatically
|
||||||
notification.onshow = function() {
|
notification.onshow = function() {
|
||||||
|
|
|
@ -0,0 +1,655 @@
|
||||||
|
/**
|
||||||
|
* WeeChat protocol handling.
|
||||||
|
*
|
||||||
|
* This object parses messages and formats commands for the WeeChat
|
||||||
|
* protocol. It's independent from the communication layer and thus
|
||||||
|
* may be used with any network mechanism.
|
||||||
|
*/
|
||||||
|
var WeeChatProtocol = function() {
|
||||||
|
// specific parsing for each message type
|
||||||
|
this._types = {
|
||||||
|
'chr': this._getChar,
|
||||||
|
'int': this._getInt,
|
||||||
|
'str': this._getString,
|
||||||
|
'inf': this._getInfo,
|
||||||
|
'hda': this._getHdata,
|
||||||
|
'ptr': this._getPointer,
|
||||||
|
'lon': this._getStrNumber,
|
||||||
|
'tim': this._getTime,
|
||||||
|
'buf': this._getString,
|
||||||
|
'arr': this._getArray,
|
||||||
|
'htb': this._getHashTable,
|
||||||
|
'inl': function() {
|
||||||
|
this._warnUnimplemented('infolist');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// string value for some message types
|
||||||
|
this._typesStr = {
|
||||||
|
'chr': this._strDirect,
|
||||||
|
'str': this._strDirect,
|
||||||
|
'int': this._strToString,
|
||||||
|
'tim': this._strToString,
|
||||||
|
'ptr': this._strDirect
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsigned integer array to string.
|
||||||
|
*
|
||||||
|
* @param uia Unsigned integer array
|
||||||
|
* @return Decoded string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol._uia2s = function(uia) {
|
||||||
|
var str = [];
|
||||||
|
|
||||||
|
for (var c = 0; c < uia.length; c++) {
|
||||||
|
str.push(String.fromCharCode(uia[c]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodeURIComponent(escape(str.join('')));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges default parameters with overriding parameters.
|
||||||
|
*
|
||||||
|
* @param defaults Default parameters
|
||||||
|
* @param override Overriding parameters
|
||||||
|
* @return Merged parameters
|
||||||
|
*/
|
||||||
|
WeeChatProtocol._mergeParams = function(defaults, override) {
|
||||||
|
for (var v in override) {
|
||||||
|
defaults[v] = override[v];
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a command.
|
||||||
|
*
|
||||||
|
* @param id Command ID (null for no ID)
|
||||||
|
* @param name Command name
|
||||||
|
* @param parts Command parts
|
||||||
|
* @return Formatted command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol._formatCmd = function(id, name, parts) {
|
||||||
|
var cmdIdName;
|
||||||
|
var cmd;
|
||||||
|
|
||||||
|
cmdIdName = (id !== null) ? '(' + id + ') ' : '';
|
||||||
|
cmdIdName += name;
|
||||||
|
parts.unshift(cmdIdName);
|
||||||
|
cmd = parts.join(' ');
|
||||||
|
cmd += '\n';
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats an init command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* password: password (optional)
|
||||||
|
* compression: compression ('off' or 'zlib') (optional)
|
||||||
|
* @return Formatted init command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatInit = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
password: null,
|
||||||
|
compression: 'off'
|
||||||
|
};
|
||||||
|
var keys = [];
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
keys.push('compression=' + params.compression);
|
||||||
|
if (params.password !== null) {
|
||||||
|
keys.push('password=' + params.password);
|
||||||
|
}
|
||||||
|
parts.push(keys.join(','));
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(null, 'init', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats an hdata command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* path: hdata path (mandatory)
|
||||||
|
* keys: array of keys (optional)
|
||||||
|
* @return Formatted hdata command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatHdata = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null,
|
||||||
|
keys: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
parts.push(params.path);
|
||||||
|
if (params.keys !== null) {
|
||||||
|
parts.push(params.keys.join(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'hdata', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats an info command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* name: info name (mandatory)
|
||||||
|
* @return Formatted info command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatInfo = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
parts.push(params.name);
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'info', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a nicklist command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* buffer: buffer name (optional)
|
||||||
|
* @return Formatted nicklist command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatNicklist = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null,
|
||||||
|
buffer: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
if (params.buffer !== null) {
|
||||||
|
parts.push(params.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'nicklist', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats an input command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* buffer: target buffer (mandatory)
|
||||||
|
* data: input data (mandatory)
|
||||||
|
* @return Formatted input command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatInput = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
parts.push(params.buffer);
|
||||||
|
parts.push(params.data);
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'input', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a sync or a desync command.
|
||||||
|
*
|
||||||
|
* @param params Parameters (see _formatSync and _formatDesync)
|
||||||
|
* @return Formatted sync/desync command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol._formatSyncDesync = function(cmdName, params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null,
|
||||||
|
buffers: null,
|
||||||
|
options: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
if (params.buffers !== null) {
|
||||||
|
parts.push(params.buffers.join(','));
|
||||||
|
if (params.options !== null) {
|
||||||
|
parts.push(params.options.join(','));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, cmdName, parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a sync command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* buffers: array of buffers to sync (optional)
|
||||||
|
* options: array of options (optional)
|
||||||
|
* @return Formatted sync command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatSync = function(params) {
|
||||||
|
return WeeChatProtocol._formatSyncDesync('sync', params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a desync command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* buffers: array of buffers to desync (optional)
|
||||||
|
* options: array of options (optional)
|
||||||
|
* @return Formatted desync command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatDesync = function(params) {
|
||||||
|
return WeeChatProtocol._formatSyncDesync('desync', params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a test command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* @return Formatted test command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatTest = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'test', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a quit command.
|
||||||
|
*
|
||||||
|
* @return Formatted quit command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatQuit = function() {
|
||||||
|
return WeeChatProtocol._formatCmd(null, 'quit', []);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a ping command.
|
||||||
|
*
|
||||||
|
* @param params Parameters:
|
||||||
|
* id: command ID (optional)
|
||||||
|
* args: array of custom arguments (optional)
|
||||||
|
* @return Formatted ping command string
|
||||||
|
*/
|
||||||
|
WeeChatProtocol.formatPing = function(params) {
|
||||||
|
var defaultParams = {
|
||||||
|
id: null,
|
||||||
|
args: null
|
||||||
|
};
|
||||||
|
var parts = [];
|
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params);
|
||||||
|
if (params.args !== null) {
|
||||||
|
parts.push(params.args.join(' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'ping', parts);
|
||||||
|
};
|
||||||
|
|
||||||
|
WeeChatProtocol.prototype = {
|
||||||
|
/**
|
||||||
|
* Warns that message parsing is not implemented for a
|
||||||
|
* specific type.
|
||||||
|
*
|
||||||
|
* @param type Message type to display
|
||||||
|
*/
|
||||||
|
_warnUnimplemented: function(type) {
|
||||||
|
console.log('Warning: ' + type + ' message parsing is not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a 3-character message type token value from current
|
||||||
|
* set data.
|
||||||
|
*
|
||||||
|
* @return Type
|
||||||
|
*/
|
||||||
|
_getType: function() {
|
||||||
|
var t = this._getSlice(3);
|
||||||
|
|
||||||
|
if (!t) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WeeChatProtocol._uia2s(new Uint8Array(t));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the appropriate read routine for the specified message type.
|
||||||
|
*
|
||||||
|
* @param type Message type
|
||||||
|
* @return Data value
|
||||||
|
*/
|
||||||
|
_runType: function(type) {
|
||||||
|
var cb = this._types[type];
|
||||||
|
var boundCb = cb.bind(this);
|
||||||
|
|
||||||
|
return boundCb();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a "number as a string" token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Number as a string
|
||||||
|
*/
|
||||||
|
_getStrNumber: function() {
|
||||||
|
var len = this._getByte();
|
||||||
|
var str = this._getSlice(len);
|
||||||
|
|
||||||
|
return WeeChatProtocol._uia2s(new Uint8Array(str));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the passed object.
|
||||||
|
*
|
||||||
|
* @param obj Object
|
||||||
|
* @return Passed object
|
||||||
|
*/
|
||||||
|
_strDirect: function(obj) {
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls toString() on the passed object and returns the value.
|
||||||
|
*
|
||||||
|
* @param obj Object to call toString() on
|
||||||
|
* @return String value of object
|
||||||
|
*/
|
||||||
|
_strToString: function(obj) {
|
||||||
|
return obj.toString();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string value of an object representing the message
|
||||||
|
* value for a specified type.
|
||||||
|
*
|
||||||
|
* @param obj Object for which to get the string value
|
||||||
|
* @param type Message type
|
||||||
|
* @return String value of object
|
||||||
|
*/
|
||||||
|
_objToString: function(obj, type) {
|
||||||
|
var cb = this._typesStr[type];
|
||||||
|
var boundCb = cb.bind(this);
|
||||||
|
|
||||||
|
return boundCb(obj);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an info token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Info object
|
||||||
|
*/
|
||||||
|
_getInfo: function() {
|
||||||
|
var info = {};
|
||||||
|
info.key = this._getString();
|
||||||
|
info.value = this._getString();
|
||||||
|
|
||||||
|
return info;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an hdata token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Hdata object
|
||||||
|
*/
|
||||||
|
_getHdata: function() {
|
||||||
|
var self = this;
|
||||||
|
var paths;
|
||||||
|
var count;
|
||||||
|
var objs = [];
|
||||||
|
var hpath = this._getString();
|
||||||
|
|
||||||
|
keys = this._getString().split(',');
|
||||||
|
paths = hpath.split('/');
|
||||||
|
count = this._getInt();
|
||||||
|
|
||||||
|
keys = keys.map(function(key) {
|
||||||
|
return key.split(':');
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
var tmp = {};
|
||||||
|
|
||||||
|
tmp.pointers = paths.map(function(path) {
|
||||||
|
return self._getPointer();
|
||||||
|
});
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
tmp[key[0]] = self._runType(key[1]);
|
||||||
|
});
|
||||||
|
objs.push(tmp);
|
||||||
|
};
|
||||||
|
|
||||||
|
return objs;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a pointer token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Pointer value
|
||||||
|
*/
|
||||||
|
_getPointer: function() {
|
||||||
|
return this._getStrNumber();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a time token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Time value (Date)
|
||||||
|
*/
|
||||||
|
_getTime: function() {
|
||||||
|
var str = this._getStrNumber();
|
||||||
|
|
||||||
|
return new Date(parseInt(str) * 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an integer token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Integer value
|
||||||
|
*/
|
||||||
|
_getInt: function() {
|
||||||
|
var parsedData = new Uint8Array(this._getSlice(4));
|
||||||
|
|
||||||
|
return ((parsedData[0] & 0xff) << 24) |
|
||||||
|
((parsedData[1] & 0xff) << 16) |
|
||||||
|
((parsedData[2] & 0xff) << 8) |
|
||||||
|
(parsedData[3] & 0xff);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a byte from current set data.
|
||||||
|
*
|
||||||
|
* @return Byte value (integer)
|
||||||
|
*/
|
||||||
|
_getByte: function() {
|
||||||
|
var parsedData = new Uint8Array(this._getSlice(1));
|
||||||
|
|
||||||
|
return parsedData[0];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a character token value from current set data.
|
||||||
|
*
|
||||||
|
* @return Character (string)
|
||||||
|
*/
|
||||||
|
_getChar: function() {
|
||||||
|
return this._getByte();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a string token value from current set data.
|
||||||
|
*
|
||||||
|
* @return String value
|
||||||
|
*/
|
||||||
|
_getString: function() {
|
||||||
|
var l = this._getInt();
|
||||||
|
|
||||||
|
if (l > 0) {
|
||||||
|
var s = this._getSlice(l);
|
||||||
|
var parsedData = new Uint8Array(s);
|
||||||
|
|
||||||
|
return WeeChatProtocol._uia2s(parsedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a message header from current set data.
|
||||||
|
*
|
||||||
|
* @return Header object
|
||||||
|
*/
|
||||||
|
_getHeader: function() {
|
||||||
|
var len = this._getInt();
|
||||||
|
var comp = this._getByte();
|
||||||
|
|
||||||
|
return {
|
||||||
|
length: len,
|
||||||
|
compression: comp,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a message header ID from current set data.
|
||||||
|
*
|
||||||
|
* @return Message ID (string)
|
||||||
|
*/
|
||||||
|
_getId: function() {
|
||||||
|
return this._getString();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an arbitrary object token from current set data.
|
||||||
|
*
|
||||||
|
* @return Object value
|
||||||
|
*/
|
||||||
|
_getObject: function() {
|
||||||
|
var self = this;
|
||||||
|
var type = this._getType();
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
content: self._runType(type),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an hash table token from current set data.
|
||||||
|
*
|
||||||
|
* @return Hash table
|
||||||
|
*/
|
||||||
|
_getHashTable: function() {
|
||||||
|
var self = this;
|
||||||
|
var typeKeys, typeValues, count;
|
||||||
|
var dict = {};
|
||||||
|
|
||||||
|
typeKeys = this._getType();
|
||||||
|
typeValues = this._getType();
|
||||||
|
count = this._getInt();
|
||||||
|
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
var key = self._runType(typeKeys);
|
||||||
|
var keyStr = self._objToString(key, typeKeys);
|
||||||
|
var value = self._runType(typeValues);
|
||||||
|
dict[keyStr] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an array token from current set data.
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
_getArray: function() {
|
||||||
|
var self = this;
|
||||||
|
var type;
|
||||||
|
var count;
|
||||||
|
var values;
|
||||||
|
|
||||||
|
type = this._getType();
|
||||||
|
count = this._getInt();
|
||||||
|
values = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
values.push(self._runType(type));
|
||||||
|
};
|
||||||
|
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a specified number of bytes from current set data.
|
||||||
|
*
|
||||||
|
* @param length Number of bytes to read
|
||||||
|
* @return Sliced array
|
||||||
|
*/
|
||||||
|
_getSlice: function(length) {
|
||||||
|
if (this.dataAt + length > this._data.byteLength) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var slice = this._data.slice(this._dataAt, this._dataAt + length);
|
||||||
|
|
||||||
|
this._dataAt += length;
|
||||||
|
|
||||||
|
return slice;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current data.
|
||||||
|
*
|
||||||
|
* @param data Current data
|
||||||
|
*/
|
||||||
|
_setData: function (data) {
|
||||||
|
this._data = data;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a WeeChat message.
|
||||||
|
*
|
||||||
|
* @param data Message data (ArrayBuffer)
|
||||||
|
* @return Message value
|
||||||
|
*/
|
||||||
|
parse: function(data) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this._setData(data);
|
||||||
|
this._dataAt = 0;
|
||||||
|
|
||||||
|
var header = this._getHeader();
|
||||||
|
var id = this._getId();
|
||||||
|
var objects = [];
|
||||||
|
var object = this._getObject();
|
||||||
|
|
||||||
|
while (object) {
|
||||||
|
objects.push(object);
|
||||||
|
object = self._getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
header: header,
|
||||||
|
id: id,
|
||||||
|
objects: objects,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue