Merge pull request #68 from eepp/weechat-js-full-styling

Full styling
with-route-provider
David Cormier 12 years ago
commit c1612f4c46
  1. 12
      css/glowingbear.css
  2. 1929
      css/style.css
  3. 32
      index.html
  4. 62
      js/models.js
  5. 15
      js/websockets.js
  6. 695
      js/weechat.js

@ -49,6 +49,9 @@ table {
tr { tr {
line-height: 100%; line-height: 100%;
} }
tr:hover {
background-color: #222222;
}
td.time { td.time {
padding-right: 5px; padding-right: 5px;
vertical-align: top; vertical-align: top;
@ -59,6 +62,7 @@ td.prefix {
vertical-align: top; vertical-align: top;
padding-right: 5px; padding-right: 5px;
white-space: pre; white-space: pre;
border-right: 1px solid #444;
} }
td.message { td.message {
word-wrap: break-word; word-wrap: break-word;
@ -85,7 +89,7 @@ hr {
body { body {
color: #ddd; color: #ddd;
background-color: #222; background-color: #181818;
padding-left: 0; padding-left: 0;
padding-right: 5px; padding-right: 5px;
padding-bottom:70px; padding-bottom:70px;
@ -175,13 +179,14 @@ input[type=text], input[type=password], .badge {
} }
#bufferlines { #bufferlines {
font-family: 'Terminus', 'Inconsolata', 'Consolas', 'Monaco', 'Ubuntu Mono', monospace; font-family: 'Terminus', 'Consolas', 'Monaco', 'Inconsolata', 'Ubuntu Mono', monospace;
position: relative; position: relative;
height: 99%; height: 99%;
overflow-y: auto; overflow-y: auto;
margin-left: 14%; margin-left: 14%;
width: auto; width: auto;
top: 25px; /* topbar */ top: 25px; /* topbar */
padding-bottom: 10px;
} }
#bufferlines .btn { #bufferlines .btn {
font-family: sans-serif; font-family: sans-serif;
@ -190,6 +195,9 @@ input[type=text], input[type=password], .badge {
.navbar-fixed-bottom { .navbar-fixed-bottom {
margin: 0 5px 0 14%; margin: 0 5px 0 14%;
} }
.navbar-inverse {
background-color: #181818;
}
@media (max-width: 968px) { @media (max-width: 968px) {
#sidebar, #bufferlines { #sidebar, #bufferlines {
position: relative; position: relative;

File diff suppressed because it is too large Load Diff

@ -7,6 +7,7 @@
<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/style.css" rel="stylesheet" media="screen">
<link href="css/glowingbear.css" rel="stylesheet" media="screen"> <link href="css/glowingbear.css" rel="stylesheet" media="screen">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular-sanitize.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular-sanitize.min.js"></script>
@ -89,9 +90,10 @@
<div id="collapseTwo" class="panel-collapse collapse"> <div id="collapseTwo" class="panel-collapse collapse">
<div class="panel-body"> <div class="panel-body">
<div>To start using, please enable relay in your WeeChat client: <div>To start using, please enable relay in your WeeChat client:
<pre> <pre>
/set relay.network.password yourpassword /set relay.network.password yourpassword
/relay add weechat 9001</pre> /relay add weechat 9001
</pre>
<span class="label label-warning">WeeChat version 0.4.2 or higher is required.</span><br> <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. 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.
@ -112,16 +114,16 @@
If you check the encryption box, communication between browser and WeeChat will be encrypted.<br> 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> <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: If you want to use encrypted session you first have to set up the relay using SSL like this:
<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> </div>
</div> </div>
</div> </div>
@ -217,12 +219,12 @@
<tr class="bufferline" ng-repeat-start="bufferline in activeBuffer().lines"> <tr class="bufferline" ng-repeat-start="bufferline in activeBuffer().lines">
<td ng-hide="notimestamp" class="time"> <td ng-hide="notimestamp" class="time">
<span class="date text-muted"> <span class="date text-muted">
{{ bufferline.date | date:'HH:mm' }} <span class="cof-chat_time cob-chat_time coa-chat_time">{{ bufferline.date | date:'HH' }}</span><span class="cof-chat_time_delimiters cob-chat_time_delimiters coa-chat_time_delimiters">:</span><span class="cof-chat_time cob-chat_time coa-chat_time">{{ bufferline.date | date:'mm' }}</span>
</span> </span>
</td> </td>
<td class="prefix vertical-line"><span ng-repeat="part in bufferline.prefix" style="{{ part.fg }}">{{ part.text }}</span></td> <td class="prefix"><span ng-repeat="part in bufferline.prefix" ng-class="{{ part.classes }}">{{ part.text }}</span></td>
<td class="message"> <td class="message">
<span ng-repeat="part in bufferline.content" class="text" style="{{ part.fg }}" ng-bind-html="part.text"></span> <span ng-repeat="part in bufferline.content" class="text" ng-class="{{ part.classes }}" 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">

@ -4,7 +4,7 @@
*/ */
var models = angular.module('weechatModels', []); var models = angular.module('weechatModels', []);
models.service('models', ['$rootScope', 'colors', function($rootScope, colors) { models.service('models', ['$rootScope', function($rootScope) {
/* /*
* Buffer class * Buffer class
*/ */
@ -59,36 +59,55 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
* BufferLine class * BufferLine class
*/ */
this.BufferLine = function(message) { this.BufferLine = function(message) {
var buffer = message['buffer'];
var date = message['date'];
/* function addClasses(textElements) {
* Parse the text elements from the buffer line added var typeToClassPrefixFg = {
* 'option': 'cof-',
* @param message weechat message 'weechat': 'cwf-',
*/ 'ext': 'cef-'
function parseLineAddedTextElements(message) { };
var text = colors.parse(message); var typeToClassPrefixBg = {
text_elements =_.map(text, function(text_element) { 'option': 'cob-',
if (text_element && ('fg' in text_element)) { 'weechat': 'cwb-',
text_element['fg'] = colors.prepareCss(text_element['fg']); 'ext': 'ceb-'
};
textElements.forEach(function(textEl) {
textEl.classes = [];
// foreground color
var prefix = typeToClassPrefixFg[textEl.fgColor.type];
textEl.classes.push(prefix + textEl.fgColor.name);
// background color
prefix = typeToClassPrefixBg[textEl.bgColor.type];
textEl.classes.push(prefix + textEl.bgColor.name);
// attributes
if (textEl.attrs.name !== null) {
textEl.classes.push('coa-' + textEl.attrs.name);
}
for (var attr in textEl.attrs.override) {
val = textEl.attrs.override[attr];
if (val) {
textEl.classes.push('a-' + attr);
} else {
textEl.classes.push('a-no-' + attr);
}
} }
// TODO: parse background as well
return text_element;
}); });
return text_elements;
} }
var buffer = message['buffer']; var prefix = weeChat.Protocol.rawText2Rich(message['prefix']);
var date = message['date']; addClasses(prefix);
var prefix = parseLineAddedTextElements(message['prefix']);
var tags_array = message['tags_array']; var tags_array = message['tags_array'];
var displayed = message['displayed']; var displayed = message['displayed'];
var highlight = message['highlight']; var highlight = message['highlight'];
var content = parseLineAddedTextElements(message['message']); var content = weeChat.Protocol.rawText2Rich(message['message']);
addClasses(content);
var rtext = ""; var rtext = "";
if(content[0] != undefined) { if(content[0] != undefined) {
@ -104,6 +123,7 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
highlight: highlight, highlight: highlight,
displayed: displayed, displayed: displayed,
text: rtext, text: rtext,
} }
} }

@ -14,16 +14,7 @@ weechat.filter('toArray', function () {
} }
}); });
weechat.factory('colors', [function($scope) { weechat.factory('handlers', ['$rootScope', 'models', 'plugins', function($rootScope, models, plugins) {
return {
prepareCss: weeChat.color.prepareCss,
parse: weeChat.color.parse
};
}]);
weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', function($rootScope, colors, models, plugins) {
var handleBufferClosing = function(message) { var handleBufferClosing = function(message) {
var bufferMessage = message['objects'][0]['content'][0]; var bufferMessage = message['objects'][0]['content'][0];
@ -147,7 +138,7 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
}]); }]);
weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'colors', 'models', function($q, $rootScope, $log, storage, handlers, colors, models) { weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'models', function($q, $rootScope, $log, storage, handlers, models) {
protocol = new weeChat.Protocol(); protocol = new weeChat.Protocol();
var websocket = null; var websocket = null;
@ -570,4 +561,4 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
} }
}] }]
); );

@ -1,203 +1,563 @@
(function(exports) {// http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings (function(exports) {// http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings
/**
* 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.
*/
(function() { (function() {
// http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings var WeeChatProtocol = function() {
var part, fg, bg, attrs; // specific parsing for each object type
this._types = {
// XTerm 8-bit pallete 'chr': this._getChar,
var colors = [ 'int': this._getInt,
'#666666', '#AA0000', '#00AA00', '#AA5500', '#0000AA', 'str': this._getString,
'#AA00AA', '#00AAAA', '#AAAAAA', '#555555', '#FF5555', 'inf': this._getInfo,
'#55FF55', '#FFFF55', '#5555FF', '#FF55FF', '#55FFFF', 'hda': this._getHdata,
'#FFFFFF', '#666666', '#00005F', '#000087', '#0000AF', 'ptr': this._getPointer,
'#0000D7', '#0000FF', '#005F00', '#005F5F', '#005F87', 'lon': this._getStrNumber,
'#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F', 'tim': this._getTime,
'#008787', '#0087AF', '#0087D7', '#00AF00', '#00AF5F', 'buf': this._getString,
'#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', 'arr': this._getArray,
'#00D75F', '#00D787', '#00D7AF', '#00D7D7', '#00D7FF', 'htb': this._getHashTable,
'#00FF00', '#00FF5F', '#00FF87', '#00FFAF', '#00FFD7', 'inl': function() {
'#00FFFF', '#5F0000', '#5F005F', '#5F0087', '#5F00AF', this._warnUnimplemented('infolist');
'#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F', '#5F5F87', }
'#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F', };
'#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00',
'#5FAF5F', '#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', // string value for some object types
'#5FD700', '#5FD75F', '#5FD787', '#5FD7AF', '#5FD7D7', this._typesStr = {
'#5FD7FF', '#5FFF00', '#5FFF5F', '#5FFF87', '#5FFFAF', 'chr': this._strDirect,
'#5FFFD7', '#5FFFFF', '#870000', '#87005F', '#870087', 'str': this._strDirect,
'#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F', 'int': this._strToString,
'#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', 'tim': this._strToString,
'#87875F', '#878787', '#8787AF', '#8787D7', '#8787FF', 'ptr': this._strDirect
'#87AF00', '#87AF5F', '#87AF87', '#87AFAF', '#87AFD7', };
'#87AFFF', '#87D700', '#87D75F', '#87D787', '#87D7AF', };
'#87D7D7', '#87D7FF', '#87FF00', '#87FF5F', '#87FF87',
'#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F', /**
'#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', * WeeChat colors names.
'#AF5F5F', '#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', */
'#AF8700', '#AF875F', '#AF8787', '#AF87AF', '#AF87D7', WeeChatProtocol._weeChatColorsNames = [
'#AF87FF', '#AFAF00', '#AFAF5F', '#AFAF87', '#AFAFAF', 'default',
'#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F', '#AFD787', 'black',
'#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F', 'darkgray',
'#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', 'darkred',
'#D7005F', '#D70087', '#D700AF', '#D700D7', '#D700FF', 'lightred',
'#D75F00', '#D75F5F', '#D75F87', '#D75FAF', '#D75FD7', 'darkgreen',
'#D75FFF', '#D78700', '#D7875F', '#D78787', '#D787AF', 'lightgreen',
'#D787D7', '#D787FF', '#D7AF00', '#D7AF5F', '#D7AF87', 'brown',
'#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F', 'yellow',
'#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', 'darkblue',
'#D7FF5F', '#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', 'lightblue',
'#FF0000', '#FF005F', '#FF0087', '#FF00AF', '#FF00D7', 'darkmagenta',
'#FF00FF', '#FF5F00', '#FF5F5F', '#FF5F87', '#FF5FAF', 'lightmagenta',
'#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F', '#FF8787', 'darkcyan',
'#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F', 'lightcyan',
'#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', 'gray',
'#FFD75F', '#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', 'white'
'#FFFF00', '#FFFF5F', '#FFFF87', '#FFFFAF', '#FFFFD7', ];
'#FFFFFF', '#080808', '#121212', '#1C1C1C', '#262626',
'#303030', '#3A3A3A', '#444444', '#4E4E4E', '#585858', /**
'#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A', * Style options names.
'#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', */
'#C6C6C6', '#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE' WeeChatProtocol._colorsOptionsNames = [
'separator',
'chat',
'chat_time',
'chat_time_delimiters',
'chat_prefix_error',
'chat_prefix_network',
'chat_prefix_action',
'chat_prefix_join',
'chat_prefix_quit',
'chat_prefix_more',
'chat_prefix_suffix',
'chat_buffer',
'chat_server',
'chat_channel',
'chat_nick',
'chat_nick_self',
'chat_nick_other',
'invalid',
'invalid',
'invalid',
'invalid',
'invalid',
'invalid',
'invalid',
'invalid',
'invalid',
'invalid',
'chat_host',
'chat_delimiters',
'chat_highlight',
'chat_read_marker',
'chat_text_found',
'chat_value',
'chat_prefix_buffer',
'chat_tags',
'chat_inactive_window',
'chat_inactive_buffer',
'chat_prefix_buffer_inactive_buffer',
'chat_nick_offline',
'chat_nick_offline_highlight',
'chat_nick_prefix',
'chat_nick_suffix',
'emphasis',
'chat_day_change'
]; ];
// Push the basic color list on top of the extended color list /**
// and then when weechat requests a basic color (0-15) we rewrite * Gets the default color.
// it to be a number in the extended color table *
colors.push.apply(colors, ['', 'black', 'darkgray', 'darkred', 'red', 'darkgreen', 'lightgreen', 'brown', * @return Default color
'yellow', 'darkblue', 'lightblue', 'darkmagenta', 'magenta', 'darkcyan', 'lightcyan', 'gray', 'white' */
]); WeeChatProtocol._getDefaultColor = function() {
return {
type: 'weechat',
name: 'default'
};
}
function setAttrs() { /**
while (part.match(/^[\*\/\_\|]/)) { * Gets the default attributes.
attrs.push(part.charAt(0)); *
part = part.slice(1); * @return Default attributes
*/
WeeChatProtocol._getDefaultAttributes = function() {
return {
name: null,
override: {
'bold': false,
'reverse': false,
'italic': false,
'underline': false
} }
};
} }
function getColor() { /**
var c; * Gets the default style (default colors and attributes).
if (part.match(/^@/)) { *
c = part.slice(1, 6); * @return Default style
part = part.slice(6); */
WeeChatProtocol._getDefaultStyle = function() {
return {
fgColor: WeeChatProtocol._getDefaultColor(),
bgColor: WeeChatProtocol._getDefaultColor(),
attrs: WeeChatProtocol._getDefaultAttributes()
};
}
/**
* Clones a color object.
*
* @param color Color object to clone
* @return Cloned color object
*/
WeeChatProtocol._cloneColor = function(color) {
var clone = {};
for (var key in color) {
clone[key] = color[key];
}
return clone;
}
/**
* Clones an attributes object.
*
* @param attrs Attributes object to clone
* @return Cloned attributes object
*/
WeeChatProtocol._cloneAttrs = function(attrs) {
var clone = {};
clone.name = attrs.name;
clone.override = {};
for (var attr in attrs.override) {
clone.override[attr] = attrs.override[attr];
}
return clone;
}
/**
* Gets the name of an attribute from its character.
*
* @param ch Character of attribute
* @return Name of attribute
*/
WeeChatProtocol._attrNameFromChar = function(ch) {
var chars = {
'*': 'bold',
'!': 'reverse',
'/': 'italic',
'_': 'underline'
};
if (ch in chars) {
return chars[ch];
}
return null;
}
/**
* Gets an attributes object from a string of attribute characters.
*
* @param str String of attribute characters
* @return Attributes object (null if unchanged)
*/
WeeChatProtocol._attrsFromStr = function(str) {
var attrs = WeeChatProtocol._getDefaultAttributes();
for (var i = 0; i < str.length; ++i) {
var ch = str.charAt(i);
if (ch == '|') {
// means keep attributes, so unchanged
return null;
}
var attrName = WeeChatProtocol._attrNameFromChar(ch);
if (attrName === null) {
// ignore invalid attribute
continue;
}
attrs.override[attrName] = true;
}
return attrs;
}
/**
* Gets a single color from a string representing its index (WeeChat and
* extended colors only, NOT colors options).
*
* @param str Color string (e.g., "05" or "00134")
* @return Color object
*/
WeeChatProtocol._getColorObj = function(str) {
if (str.length == 2) {
var code = parseInt(str);
if (code > 16) {
// should never happen
return WeeChatProtocol._getDefaultColor();
} else { } else {
c = part.slice(0, 2); return {
// Rewrite the basic color value to the part in the extended type: 'weechat',
// palette where we store the basic colors name: WeeChatProtocol._weeChatColorsNames[code]
c = parseInt(c, 10) + 255; };
part = part.slice(2); }
} else {
var codeStr = str.substring(1);
return {
type: 'ext',
name: parseInt(codeStr).toString()
};
} }
return c;
} }
function prepareCss(color) { /**
/* * Gets colors and attributes of text element.
* Translates a weechat color to CSS *
* See <http://www.weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings>.
*
* @param txt Text element
* @return Colors, attributes and plain text of this text element:
* fgColor: Foreground color (null if unchanged)
* bgColor: Background color (null if unchanged)
* attrs: Attributes (null if unchanged)
* text: Plain text element
*/ */
return 'color: ' + color; WeeChatProtocol._getStyle = function(txt) {
var matchers = [
{
// color option
// STD
regex: /^(\d{2})/,
fn: function(m) {
var ret = {};
var optionCode = parseInt(m[1]);
if (optionCode > 43) {
// should never happen
return {
fgColor: null,
bgColor: null,
attrs: null
};
}
var optionName = WeeChatProtocol._colorsOptionsNames[optionCode];
ret.fgColor = {
type: 'option',
name: optionName
};
ret.bgColor = WeeChatProtocol._cloneColor(ret.fgColor);
ret.attrs = {
name: optionName,
override: {}
};
return ret;
} }
},
{
// ncurses pair
// EXT
regex: /^@(\d{5})/,
fn: function(m) {
// unimplemented case
return {
fgColor: null,
bgColor: null,
attrs: null
};
}
},
{
// foreground color with F
// "F" + (A)STD
// "F" + (A)EXT
regex: /^F(?:([*!\/_|]*)(\d{2})|@([*!\/_|]*)(\d{5}))/,
fn: function(m) {
var ret = {
bgColor: null
};
var prefixes = { if (m[2]) {
'\x19': function() { ret.attrs = WeeChatProtocol._attrsFromStr(m[1]);
if (part.match(/^F/)) { ret.fgColor = WeeChatProtocol._getColorObj(m[2]);
part = part.slice(1);
setAttrs();
fg = getColor();
} else if (part.match(/^B/)) {
part = part.slice(1);
setAttrs();
bg = getColor();
} else { } else {
setAttrs(); ret.attrs = WeeChatProtocol._attrsFromStr(m[3]);
fg = getColor(); ret.fgColor = WeeChatProtocol._getColorObj(m[4]);
if (part.match(/^,/)) {
part = part.slice(1);
bg = getColor();
} }
return ret;
} }
}, },
'\x1A': function() { {
// Don't know what to do // background color (no attributes)
// "B" + STD
// "B" + EXT
regex: /^B(\d{2}|@\d{5})/,
fn: function(m) {
return {
fgColor: null,
bgColor: WeeChatProtocol._getColorObj(m[1]),
attrs: null
};
}
}, },
'\x1B': function() { {
attrs = []; // foreground, background (+ attributes)
// "*" + (A)STD + "," + STD
// "*" + (A)STD + "," + EXT
// "*" + (A)EXT + "," + STD
// "*" + (A)EXT + "," + EXT
regex: /^\*(?:([*!\/_|]*)(\d{2})|@([*!\/_|]*)(\d{5})),(\d{2}|@\d{5})/,
fn: function(m) {
var ret = {};
if (m[2]) {
ret.attrs = WeeChatProtocol._attrsFromStr(m[1]);
ret.fgColor = WeeChatProtocol._getColorObj(m[2]);
} else {
ret.attrs = WeeChatProtocol._attrsFromStr(m[3]);
ret.fgColor = WeeChatProtocol._getColorObj(m[4]);
}
ret.bgColor = WeeChatProtocol._getColorObj(m[5]);
return ret;
}
}, },
'\x1C': function() { {
fg = ''; // foreground color with * (+ attributes) (fall back, must be checked before previous case)
bg = ''; // "*" + (A)STD
// "*" + (A)EXT
regex: /^\*([*!\/_|]*)(\d{2}|@\d{5})/,
fn: function(m) {
return {
fgColor: WeeChatProtocol._getColorObj(m[2]),
bgColor: null,
attrs: WeeChatProtocol._attrsFromStr(m[1])
};
} }
},
{
// emphasis
// "E"
regex: /^E/,
fn: function(m) {
var ret = {};
ret.fgColor = {
type: 'option',
name: 'emphasis'
};
ret.bgColor = WeeChatProtocol._cloneColor(ret.fgColor);
ret.attrs = {
name: 'emphasis',
override: {}
}; };
function parse(text) { return ret;
if (!text) {
return text;
} }
var f, parts = text.split(/(\x19|\x1A|\x1B|\x1C)/); }
if (parts.length === 1) return [{ ];
text: parts[0]
}];
attrs = [];
return parts.map(function(p) { // parse
var res, tmp = prefixes[p.charAt(0)]; var ret = {
if (f) { fgColor: null,
part = p; bgColor: null,
f(); attrs: null,
res = { text: txt
text: part, };
fg: colors[parseInt(fg, 10)], matchers.some(function(matcher) {
bg: colors[parseInt(bg, 10)], var m = txt.match(matcher.regex);
attrs: attrs if (m) {
}; ret = matcher.fn(m);
if (!res.fg) res.fg = fg; ret.text = txt.substring(m[0].length);
if (!res.bg) res.bg = bg; return true;
} }
f = tmp;
return res; return false;
}).filter(function(p) {
return p;
}); });
return ret;
} }
exports.color = { /**
prepareCss: prepareCss, * Transforms a raw text into an array of text elements with integrated
parse: parse * colors and attributes.
};
})();
;/**
* WeeChat protocol handling.
* *
* This object parses messages and formats commands for the WeeChat * @param rawText Raw text to transform
* protocol. It's independent from the communication layer and thus * @return Array of text elements
* may be used with any network mechanism.
*/ */
WeeChatProtocol.rawText2Rich = function(rawText) {
/* This is subtle, but JavaScript adds the token to the output list
* when it's surrounded by capturing parentheses.
*/
var parts = rawText.split(/(\x19|\x1a|\x1b|\x1c)/);
// no colors/attributes
if (parts.length == 1) {
return [
{
attrs: WeeChatProtocol._getDefaultAttributes(),
fgColor: WeeChatProtocol._getDefaultColor(),
bgColor: WeeChatProtocol._getDefaultColor(),
text: parts[0]
}
];
}
(function() { // find the style of every part
var WeeChatProtocol = function() { var curFgColor = WeeChatProtocol._getDefaultColor();
// specific parsing for each message type var curBgColor = WeeChatProtocol._getDefaultColor();
this._types = { var curAttrs = WeeChatProtocol._getDefaultAttributes();
'chr': this._getChar, var curSpecialToken = null;
'int': this._getInt, var curAttrsOnlyFalseOverrides = true;
'str': this._getString,
'inf': this._getInfo, return parts.map(function(p) {
'hda': this._getHdata, if (p.length == 0) {
'ptr': this._getPointer, return null;
'lon': this._getStrNumber, }
'tim': this._getTime, var firstCharCode = p.charCodeAt(0);
'buf': this._getString, var firstChar = p.charAt(0);
'arr': this._getArray,
'htb': this._getHashTable, if (firstCharCode >= 0x19 && firstCharCode <= 0x1c) {
'inl': function() { // special token
this._warnUnimplemented('infolist'); if (firstCharCode == 0x1c) {
// always reset colors
curFgColor = WeeChatProtocol._getDefaultColor();
curBgColor = WeeChatProtocol._getDefaultColor();
if (curSpecialToken != 0x19) {
// also reset attributes
curAttrs = WeeChatProtocol._getDefaultAttributes();
}
}
curSpecialToken = firstCharCode;
return null;
} }
};
// string value for some message types var text = p;
this._typesStr = { if (curSpecialToken == 0x19) {
'chr': this._strDirect, // get new style
'str': this._strDirect, var style = WeeChatProtocol._getStyle(p);
'int': this._strToString,
'tim': this._strToString, // set foreground color if changed
'ptr': this._strDirect if (style.fgColor !== null) {
curFgColor = style.fgColor;
}
// set background color if changed
if (style.bgColor !== null) {
curBgColor = style.bgColor;
}
// set attibutes if changed
if (style.attrs !== null) {
curAttrs = style.attrs;
}
// set plain text
text = style.text;
} else if (curSpecialToken == 0x1a || curSpecialToken == 0x1b) {
// set/reset attribute
var orideVal = (curSpecialToken == 0x1a);
// set attribute override if we don't have to keep all of them
if (firstChar != '|') {
var orideName = WeeChatProtocol._attrNameFromChar(firstChar);
if (orideName) {
// known attribute
curAttrs.override[orideName] = orideVal;
text = p.substring(1);
}
}
}
// reset current special token
curSpecialToken = null;
// if text is empty, don't bother returning it
if (text.length == 0) {
return null;
}
/* As long as attributes are only false overrides, without any option
* name, it's safe to remove them.
*/
if (curAttrsOnlyFalseOverrides && curAttrs.name === null) {
var allReset = true;
for (var attr in curAttrs.override) {
if (curAttrs.override[attr]) {
allReset = false;
break;
}
}
if (allReset) {
curAttrs.override = {};
} else {
curAttrsOnlyFalseOverrides = false;
}
}
// parsed text element
return {
fgColor: WeeChatProtocol._cloneColor(curFgColor),
bgColor: WeeChatProtocol._cloneColor(curBgColor),
attrs: WeeChatProtocol._cloneAttrs(curAttrs),
text: text
}; };
}).filter(function(p) {
return p !== null;
});
}; };
/** /**
@ -800,7 +1160,7 @@
* @param data Message data (ArrayBuffer) * @param data Message data (ArrayBuffer)
* @return Message value * @return Message value
*/ */
parse: function(data) { parse: function(data, optionsValues) {
var self = this; var self = this;
this._setData(data); this._setData(data);
@ -815,12 +1175,13 @@
objects.push(object); objects.push(object);
object = self._getObject(); object = self._getObject();
} }
var msg = {
return {
header: header, header: header,
id: id, id: id,
objects: objects, objects: objects,
}; };
return msg;
} }
}; };

Loading…
Cancel
Save