Интерфейс на основе candy

This commit is contained in:
Alexander Yakovlev 2016-02-20 11:14:40 +07:00
commit 6c69cdffcc
114 changed files with 2637 additions and 0 deletions

View File

@ -0,0 +1,30 @@
# Chat recall plugin
This plugin will allow the user to navigate through historical messages they've typed using the up and down keys
## Usage
Include the JavaScript file:
```HTML
<script type="text/javascript" src="path_to_plugins/chatrecall/candy.js"></script>
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
CandyShop.ChatRecall.init();
Candy.Core.connect();
```
## Configuration options
`messagesToKeep` - Integer - The number of messages to store in history. Defaults to 10
## Example configurations
```JavaScript
// Store 25 messages for the user to scroll through
CandyShop.ChatRecall.init({
messagesToKeep: 25
});
```

View File

@ -0,0 +1,116 @@
/** File: candy.js
* Candy - Chats are not dead yet.
*
* Authors:
* - Troy McCabe <troy.mccabe@geeksquad.com>
*
* Copyright:
* (c) 2012 Geek Squad. All rights reserved.
*/
/* global document, Candy, jQuery */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
/** Class: CandyShop.ChatRecall
* Remembers the last {x} messages the user types and allows up and down key recollection
*/
CandyShop.ChatRecall = (function(self, Candy, $) {
/** Object: _options
* Options:
* (Integer) messagesToKeep - How many messages to keep in memory
*/
var _options = {
messagesToKeep: 10
};
/** Array: _messages
* The messages that the user sent
*/
var _messages = [];
/** Integer: _currentMessageIndex
* The current index of the message the user went back to
*/
var _currentMessageIndex = 0;
/** Function: init
* Initialize the ChatRecall plugin
*
* Parameters:
* (Object) options - An options packet to apply to this plugin
*/
self.init = function(options) {
// apply the supplied options to the defaults specified
$.extend(true, _options, options);
// Listen for keydown in the field
$(document).on('keydown', 'input[name="message"]', function(e) {
// switch on the key code
switch (e.which) {
// up arrow
case 38:
// if we're under the cap of max messages and the cap of the messages currently stored, recall
if (_currentMessageIndex < _options.messagesToKeep && _currentMessageIndex < _messages.length) {
// if we're at blank (the bottom), move it up to 0
if (_currentMessageIndex === -1) {
_currentMessageIndex++;
}
// set the value to what we stored
$(this).val(_messages[_currentMessageIndex]);
// if we're under the limits, go ahead and move the tracked position up
if (_currentMessageIndex < _options.messagesToKeep - 1 && _currentMessageIndex < _messages.length - 1) {
_currentMessageIndex++;
}
}
break;
// down arrow
case 40:
// if we're back to the bottom, clear the field
// else move it down
if (_currentMessageIndex === -1) {
$(this).val('');
} else {
// if we're at the cap already, move it down initially (don't want to have to hit it twice)
if (_currentMessageIndex === _options.messagesToKeep - 1 || _currentMessageIndex === _messages.length - 1) {
_currentMessageIndex--;
}
// set the value to the one that's stored
$(this).val(_messages[_currentMessageIndex]);
if (_currentMessageIndex > -1) {
// move the tracked position down
_currentMessageIndex--;
}
}
break;
}
});
// listen before send and add it to the stack
$(Candy).on('candy:view.message.before-send', function(e, data) {
// remove, in case there is the colors plugin, the |c:number| prefix
self.addMessage(data.message.replace(/\|c:\d+\|/i, ''));
});
};
/** Function: addMessage
* Add a message to the front of the stack
* This is stored New[0] -> Old[N]
*
* Parameters:
* (String) message - The message to store
*/
self.addMessage = function(message) {
// pop one off the end if it's too many
if (_messages.length === _options.messagesToKeep) {
_messages.pop();
}
// put the message at pos 0 and move everything else
_messages.unshift(message);
};
return self;
}(CandyShop.ChatRecall || {}, Candy, jQuery));

View File

@ -0,0 +1,43 @@
# Colors using XHTML formatted messages
Send and receive colored messages.
This plugin is based on the [colors](https://github.com/candy-chat/candy-plugins/tree/master/colors) and, contrary
to the `colors` plugin, ensures that third party clients see the colors as well.
![Color Picker](screenshot.png)
## Usage
To enable *Colors* you have to include its JavaScript code and stylesheet
```HTML
<script type="text/javascript" src="candyshop/colors-xhtml/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/colors-xhtml/candy.css" />
```
Call its `init()` method after Candy has been initialized:
```javascript
Candy.init('/http-bind/', {
view: {
// make sure you enabled XHTML in order to display it properly.
enableXHTML: true
}
});
// enable Colors-XHTML plugin (default: 8 colors)
CandyShop.ColorsXhtml.init();
Candy.Core.connect();
```
To enable less or more colors enable it with e.g.:
```javascript
var colors = [
'#333', '#fff'
// etc, use as many as you'd like to
];
CandyShop.ColorsXhtml.init(colors);
```
**Please note**: you can't use the `colors` and the `colors-xhtml` plugin together.

View File

@ -0,0 +1,33 @@
#colors-control {
background: no-repeat url('colors-control.png');
position: relative;
}
#colors-control-indicator {
display: inline-block;
height: 6px;
width: 6px;
border: 1px solid white;
position: absolute;
top: 100%;
left: 100%;
margin: -8px 0 0 -8px;
}
#context-menu .colors {
padding-left: 5px;
width: 89px;
white-space: normal;
}
#context-menu .colors:hover {
background-color: inherit;
}
#context-menu .colors span {
display: inline-block;
width: 14px;
height: 14px;
border: 1px solid white;
margin: 3px;
}

View File

@ -0,0 +1,96 @@
/* global Candy, jQuery */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.ColorsXhtml = (function(self, Candy, $) {
var _numColors,
_currentColor = '',
_colors = [
'#333',
'#c4322b',
'#37991e',
'#1654c9',
'#66379b',
'#ba7318',
'#32938a',
'#9e2274'
];
self.init = function(colors) {
if(colors && colors.length) {
_colors = colors;
}
_numColors = _colors.length;
self.applyTranslations();
$(Candy).on('candy:view.message.before-send', function(e, args) {
if(_currentColor !== '' && $.trim(args.message) !== '') {
args.xhtmlMessage = '<span style="color:' + _currentColor + '">' + Candy.Util.Parser.escape(args.message) + '</span>';
}
});
if(Candy.Util.cookieExists('candyshop-colors-xhtml-current')) {
var color = Candy.Util.getCookie('candyshop-colors-xhtml-current');
if(_colors.indexOf(color) !== -1) {
_currentColor = color;
}
}
var html = '<li id="colors-control" data-tooltip="' + $.i18n._('candyshopColorsXhtmlMessagecolor') + '"><span style="color:' + _currentColor + ';background-color:' + _currentColor +'" id="colors-control-indicator"></span></li>';
$('#emoticons-icon').after(html);
$('#colors-control').click(function() {
CandyShop.ColorsXhtml.showPicker(this);
});
};
self.showPicker = function(elem) {
elem = $(elem);
var pos = elem.offset(),
menu = $('#context-menu'),
content = $('ul', menu),
colors = '',
i;
$('#tooltip').hide();
for(i = _numColors-1; i >= 0; i--) {
colors = '<span style="color:' + _colors[i] + ';background-color:' + _colors[i] + ';" data-color="' + _colors[i] + '"></span>' + colors;
}
content.html('<li class="colors">' + colors + '</li>');
content.find('span').click(function() {
_currentColor = $(this).attr('data-color');
$('#colors-control-indicator').attr('style', 'color:' + _currentColor + ';background-color:' + _currentColor);
Candy.Util.setCookie('candyshop-colors-xhtml-current', _currentColor, 365);
Candy.View.Pane.Room.setFocusToForm(Candy.View.getCurrent().roomJid);
menu.hide();
});
var posLeft = Candy.Util.getPosLeftAccordingToWindowBounds(menu, pos.left),
posTop = Candy.Util.getPosTopAccordingToWindowBounds(menu, pos.top);
menu.css({'left': posLeft.px, 'top': posTop.px, backgroundPosition: posLeft.backgroundPositionAlignment + ' ' + posTop.backgroundPositionAlignment});
menu.fadeIn('fast');
return true;
};
self.applyTranslations = function() {
var translations = {
'en' : 'Message Color',
'ru' : 'Цвет сообщения',
'de' : 'Farbe für Nachrichten',
'fr' : 'Couleur des messages',
'nl' : 'Berichtkleur',
'es' : 'Color de los mensajes'
};
$.each(translations, function(k, v) {
if(Candy.View.Translation[k]) {
Candy.View.Translation[k].candyshopColorsXhtmlMessagecolor = v;
}
});
};
return self;
}(CandyShop.ColorsXhtml || {}, Candy, jQuery));

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

View File

@ -0,0 +1,29 @@
# Colors
Send and receive colored messages.
This plugin uses an own format of messages (`foobar` becomes e.g. `|c:1|foobar`).
If you'd like to use XHTML for formatting messages (this ensures third-party clients could also
display it properly), please use [colors-html](https://github.com/candy-chat/candy-plugins/tree/master/colors-xhtml).
![Color Picker](screenshot.png)
## Usage
To enable *Colors* you have to include its JavaScript code and stylesheet
```HTML
<script type="text/javascript" src="candyshop/colors/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/colors/candy.css" />
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
// enable Colors plugin (default: 8 colors)
CandyShop.Colors.init();
Candy.Core.connect();
```
To enable less or more colors just call `CandyShop.Colors.init(<number-of-colors>)`.

View File

@ -0,0 +1,97 @@
#colors-control {
background: no-repeat url('colors-control.png');
position: relative;
}
#colors-control-indicator {
display: inline-block;
height: 6px;
width: 6px;
border: 1px solid white;
position: absolute;
top: 100%;
left: 100%;
margin: -8px 0 0 -8px;
}
#context-menu .colors {
padding-left: 5px;
width: 89px;
white-space: normal;
}
#context-menu .colors:hover {
background-color: inherit;
}
#context-menu .colors span {
display: inline-block;
width: 14px;
height: 14px;
border: 1px solid white;
margin: 3px;
}
.message-pane span.colored {
background-color: transparent !important;
}
.color-0 {
color: #333;
background-color: #333;
}
.color-1 {
color: #c4322b;
background-color: #c4322b;
}
.color-2 {
color: #37991e;
background-color: #37991e;
}
.color-3 {
color: #1654c9;
background-color: #1654c9;
}
.color-4 {
color: #66379b;
background-color: #66379b;
}
.color-5 {
color: #ba7318;
background-color: #ba7318;
}
.color-6 {
color: #32938a;
background-color: #32938a;
}
.color-7 {
color: #9e2274;
background-color: #9e2274;
}
.color-8 {
color: #4C82E4;
background-color: #4C82E4;
}
.color-9 {
color: #7F140E;
background-color: #7F140E;
}
.color-10 {
color: #1C630A;
background-color: #1C630A;
}
.color-11 {
color: #CF55A4;
background-color: #CF55A4;
}

View File

@ -0,0 +1,87 @@
/* global Candy, jQuery */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Colors = (function(self, Candy, $) {
var _numColors,
_currentColor = 0;
self.init = function(numColors) {
_numColors = numColors ? numColors : 8;
self.applyTranslations();
$(Candy).on('candy:view.message.before-send', function(e, args) {
if(_currentColor > 0 && $.trim(args.message) !== '') {
args.message = '|c:'+ _currentColor +'|' + args.message;
}
});
$(Candy).on('candy:view.message.before-render', function(e, args) {
args.templateData.message = args.templateData.message.replace(/^\|c:([0-9]{1,2})\|(.*)/gm, '<span class="colored color-$1">$2</span>');
});
if(Candy.Util.cookieExists('candyshop-colors-current')) {
var color = parseInt(Candy.Util.getCookie('candyshop-colors-current'), 10);
if(color > 0 && color < _numColors) {
_currentColor = color;
}
}
var html = '<li id="colors-control" data-tooltip="' + $.i18n._('candyshopColorsMessagecolor') + '"><span class="color-' + _currentColor + '" id="colors-control-indicator"></span></li>';
$('#emoticons-icon').after(html);
$('#colors-control').click(function() {
CandyShop.Colors.showPicker(this);
});
};
self.showPicker = function(elem) {
elem = $(elem);
var pos = elem.offset(),
menu = $('#context-menu'),
content = $('ul', menu),
colors = '',
i;
$('#tooltip').hide();
for(i = _numColors-1; i >= 0; i--) {
colors = '<span class="color-' + i + '" data-color="' + i + '"></span>' + colors;
}
content.html('<li class="colors">' + colors + '</li>');
content.find('span').click(function() {
_currentColor = $(this).attr('data-color');
$('#colors-control-indicator').attr('class', 'color-' + _currentColor);
Candy.Util.setCookie('candyshop-colors-current', _currentColor, 365);
Candy.View.Pane.Room.setFocusToForm(Candy.View.getCurrent().roomJid);
menu.hide();
});
var posLeft = Candy.Util.getPosLeftAccordingToWindowBounds(menu, pos.left),
posTop = Candy.Util.getPosTopAccordingToWindowBounds(menu, pos.top);
menu.css({'left': posLeft.px, 'top': posTop.px, backgroundPosition: posLeft.backgroundPositionAlignment + ' ' + posTop.backgroundPositionAlignment});
menu.fadeIn('fast');
return true;
};
self.applyTranslations = function() {
var translations = {
'en' : 'Message Color',
'ru' : 'Цвет сообщения',
'de' : 'Farbe für Nachrichten',
'fr' : 'Couleur des messages',
'nl' : 'Berichtkleur',
'es' : 'Color de los mensajes'
};
$.each(translations, function(k, v) {
if(Candy.View.Translation[k]) {
Candy.View.Translation[k].candyshopColorsMessagecolor = v;
}
});
};
return self;
}(CandyShop.Colors || {}, Candy, jQuery));

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

View File

@ -0,0 +1,78 @@
# Emphasis
Basic message formatting, with xhtml conversion, compatible with XEP-0071. Standard messages are converted to Textile-style formatting.
Textile, BBCode, and Html Variants are supported:
**bold**
```
*bold*
[b]bold[/b]
<b>bold</b>
<strong>bold</strong>
```
_italic_
```
_italic_
[i]italic[/i]
<i>italic</i>
<em>italic</em>
```
<ins>underlined</ins>
```
+underlined+
[u]underlined[/u]
<u>underlined</u>
<ins>underlined</ins>
```
~~strikethrough~~
```
-strikethrough-
[s]strikethrough[/s]
<s>strinkethough</s>
<del>strikethrough</del>
```
Textile can be escaped like so:
```
==-strikethrough-==
```
This plugin is compatible with colors-xhtml.
## Usage
Include the JavaScript file:
```HTML
<script type="text/javascript" src="candyshop/emphasis/candy.js"></script>
```
Call its `init()` method after Candy has been initialized:
```javascript
Candy.init('/http-bind/', {});
// enable basic textile/BBCode/Html handling
CandyShop.Emphasis.init();
Candy.Core.connect();
```
Optionally, different formats can be disabled.
```javascript
CandyShop.Emphasis.init({ textile: false, bbcode: true, html: true });
```
Or just
```javascript
CandyShop.Emphasis.init({ textile: false });
```

View File

@ -0,0 +1,86 @@
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Emphasis = (function(self, Candy, $) {
// textile, bbcode, old html, escaped old html, new html, escaped new html
var _styles = {
textile: [
{ plain: '==*bold*==', regex: /((^|\s|\>)==\*(.*?)\*==(\s|\<|$))/gm, plain: "$2*$3*$4", xhtml: "$2*$3*$4" },
{ plain: '==_italic_==', regex: /((^|\s|\>)==\_(.*?)\_==(\s|\<|$))/gm, plain: "$2_$3_$4", xhtml: "$2_$3_$4" },
{ plain: '==-strikethrough-==', regex: /((^|\s|\>)==\-(.*?)\-==(\s|\<|$))/gm, plain: "$2-$3-$4", xhtml: "$2-$3-$4" },
{ plain: '==+underline+==', regex: /((^|\s|\>)==\+(.*?)\+==(\s|\<|$))/gm, plain: "$2+$3+$4", xhtml: "$2+$3+$4" },
{ plain: '*bold*', regex: /((^|\s|\>)\*(.*?)\*(\s|\<|$))/gm, plain: "$2*$3*$4", xhtml: "$2<strong>$3</strong>$4" },
{ plain: '_italic_', regex: /((^|\s|\>)\_(.*?)\_(\s|\<|$))/gm, plain: "$2_$3_$4", xhtml: "$2<em>$3</em>$4" },
{ plain: '-strikethrough-', regex: /((^|\s|\>)\-(.*?)\-(\s|\<|$))/gm, plain: "$2-$3-$4", xhtml: "$2<span style='text-decoration: line-through;'>$3</span>$4" },
{ plain: '+underline+', regex: /((^|\s|\>)\+(.*?)\+(\s|\<|$))/gm, plain: "$2+$3+$4", xhtml: "$2<span style='text-decoration: underline;'>$3</span>$4" }
],
bbcode: [
{ plain: '[b]bold[/b]', regex: /(\[b\](.*?)\[\/b\])/igm, plain: "*$2*", xhtml: "<strong>$2</strong>" },
{ plain: '[i]italic[/i]', regex: /(\[i\](.*?)\[\/i\])/igm, plain: "_$2_", xhtml: "<em>$2</em>" },
{ plain: '[s]strikethrough[/s]', regex: /(\[s\](.*?)\[\/s\])/igm, plain: "-$2-", xhtml: "<span style='text-decoration: line-through;'>$2</span>" },
{ plain: '[u]underline[/u]', regex: /(\[u\](.*?)\[\/u\])/igm, plain: "+$2+", xhtml: "<span style='text-decoration: underline;'>$2</span>" }
],
html: [
//handling both escaped an unescaped, just in case.
{ plain: '&lt;b&gt;bold&lt;/b&gt;', regex: /(\&lt;b\&gt;(.*?)\&lt;\/b\&gt;)/igm, plain: "*$2*", xhtml: "<strong>$2</strong>" },
{ plain: '&lt;strong&gt;bold&lt;/strong&gt;', regex: /(\&lt;strong\&gt;(.*?)\&lt;\/strong\&gt;)/igm, plain: "*$2*", xhtml: "<strong>$2</strong>" },
{ plain: '&lt;i&gt;italic&lt;/i&gt;', regex: /(\&lt;i\&gt;(.*?)\&lt;\/i\&gt;)/igm, plain: "_$2_", xhtml: "<em>$2</em>" },
{ plain: '&lt;em&gt;italic&lt;/em&gt;', regex: /(\&lt;em\&gt;(.*?)\&lt;\/em\&gt;)/igm, plain: "_$2_", xhtml: "<em>$2</em>" },
{ plain: '&lt;s&gt;strikethrough&lt;/s&gt;', regex: /(\&lt;s\&gt;(.*?)\&lt;\/s\&gt;)/igm, plain: "-$2-", xhtml: "<span style='text-decoration: line-through;'>$2</span>" },
{ plain: '&lt;del&gt;strikethrough&lt;/del&gt;', regex: /(\&lt;del\&gt;(.*?)\&lt;\/del\&gt;)/igm, plain: "-$2-", xhtml: "<span style='text-decoration: line-through;'>$2</span>" },
{ plain: '&lt;u&gt;underline&lt;/u&gt;', regex: /(\&lt;u\&gt;(.*?)\&lt;\/u\&gt;)/igm, plain: "+$2+", xhtml: "<span style='text-decoration: underline;'>$2</span>" },
{ plain: '&lt;ins&gt;underline&lt;/ins&gt;', regex: /(\&lt;ins\&gt;(.*?)\&lt;\/ins\&gt;)/igm, plain: "+$2+", xhtml: "<span style='text-decoration: underline;'>$2</span>" },
{ plain: '<b>bold</b>', regex: /(\<b\>(.*?)\<\/b\>)/igm, plain: "*$2*", xhtml: "<strong>$2</strong>" },
{ plain: '<strong>bold</strong>', regex: /(\<strong\>(.*?)\<\/strong\>)/igm, plain: "*$2*", xhtml: "<strong>$2</strong>" },
{ plain: '<i>italic</i>', regex: /(\<i\>(.*?)\<\/i\>)/igm, plain: "_$2_", xhtml: "<em>$2</em>" },
{ plain: '<em>italic</em>', regex: /(\<em\>(.*?)\<\/em\>)/igm, plain: "_$2_", xhtml: "<em>$2</em>" },
{ plain: '<s>strikethrough</s>', regex: /(\<s\>(.*?)\<\/s\>)/igm, plain: "-$2-", xhtml: "<span style='text-decoration: line-through;'>$2</span>" },
{ plain: '<del>strikethrough</del>', regex: /(\<del\>(.*?)\<\/del\>)/igm, plain: "-$2-", xhtml: "<span style='text-decoration: line-through;'>$2</span>" },
{ plain: '<u>underline</u>', regex: /(\<u\>(.*?)\<\/u\>)/igm, plain: "+$2+", xhtml: "<span style='text-decoration: underline;'>$2</span>" },
{ plain: '<ins>underline</ins>', regex: /(\<ins\>(.*?)\<\/ins\>)/igm, plain: "+$2+", xhtml: "<span style='text-decoration: underline;'>$2</span>" }
]
};
var _options = {
textile: true,
bbcode: true,
html: true
};
self.init = function( options ) {
// apply the supplied options to the defaults specified
$.extend( true, _options, options );
$(Candy).on( 'candy:view.message.before-send', function(e, args) {
var workingPlainMessage = args.message;
var workingXhtmlMessage = args.message;
if( args.xhtmlMessage ) {
var workingXhtmlMessage = args.xhtmlMessage;
}
$.each( _options, function( optionIndex, optionValue ){
if( optionValue === true ){
$.each( _styles[optionIndex], function( styleIndex, styleValue ){
workingPlainMessage = workingPlainMessage.replace( styleValue.regex, styleValue.plain );
workingXhtmlMessage = workingXhtmlMessage.replace( styleValue.regex, styleValue.xhtml );
});
}
});
if( workingPlainMessage != workingXhtmlMessage) {
// strophe currently requires that xhtml have a root element. Apparently.
// Force one node, with no external text
if( !workingXhtmlMessage.match( /^<.*>$/ ) || $( workingXhtmlMessage ).length != 1 ) {
workingXhtmlMessage = "<span>" + workingXhtmlMessage + "</span>";
}
args.message = workingPlainMessage;
args.xhtmlMessage = workingXhtmlMessage;
}
});
};
return self;
}(CandyShop.Emphasis || {}, Candy, jQuery));

View File

@ -0,0 +1,24 @@
# Left Tabs + Bootstrap3 Icons
A plugin for Candy Chat to enable left tabs with simple Bootstrap3 theme elements.
![Left Tabs + Bootstrap3](screenshot.png)
## Usage
Include the JavaScript and CSS files:
```HTML
<script type="text/javascript" src="candyshop/lefttabs/lefttabs.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/lefttabs/lefttabs.css" />
```
Remember to include your Bootstrap3 CSS/JS files! They are not included in this plugin. ;)
To enable this Left Tabs plugin, add its `init` method _before_ you `init` Candy:
```JavaScript
CandyShop.LeftTabs.init();
Candy.init('/http-bind', { ...
```
## Compatibility with other plugins
Make sure to `init` it after all other plugins, but before the Candy `init`.
1. CreateRoom

View File

@ -0,0 +1,239 @@
/**
* LeftTabs CSS
*
* @author Melissa Adamaitis <melissa@melissanoelle.com>
*/
/* Message pane/body CSS. */
#chat-rooms {
display: inline-block;
float: right;
margin-left: 50%;
margin-right: 14.6%;
width: 30.5%;
}
.message-pane-wrapper {
float:right;
height: auto;
margin: 0;
position: relative;
width: 100%;
}
.message-pane {
height: 100%;
padding-top: 1px;
width: 69.8%;
overflow-y: scroll;
position: fixed;
}
.message-pane .label {
padding-top: 7px;
}
/* Input form CSS. */
.message-form-wrapper {
float: left;
margin-right:auto;
position: relative;
width: 100%;
}
.message-form {
margin: 0;
position: relative;
width: 100%;
}
.message-form input.submit {
margin: 2px 3px;
position: absolute;
}
/* Roster (right) menu CSS. */
.roster-pane {
background-color: initial;
border: 0;
box-shadow: none;
float:right;
margin: 0;
padding-right: 3px;
padding-top: 2px;
position: fixed;
right: 0;
width: 14%;
}
.roster-pane .label {
color: #555;
font-size: 0.85em;
line-height: 1em;
padding-left: 0;
text-shadow: none;
width: auto;
}
.roster-pane .user {
border: 0;
box-sizing: initial;
box-shadow: none;
font-size: 14px;
padding: 0;
}
.roster-pane .user ul {
float: right;
margin: 0;
position: relative;
}
.roster-pane .user:hover {
background-color: initial;
}
.roster-pane .user:hover .label {
color: #33bbfc;
}
/* Toolbar CSS. (Below roster.) */
#chat-toolbar {
height: 30px;
margin-bottom: 0;
width: 14.5%;
}
#chat-toolbar li {
background-image: none !important;
font-size: 1.25em;
line-height: 1em;
}
#emoticons-icon {
color: #F3E43C;
}
/* Volume. */
#chat-sound-control, #chat-autoscroll-control {
color: #ccc;
}
#chat-sound-control .glyphicon {
display: none;
}
#chat-sound-control .glyphicon.glyphicon-volume-off {
display: initial;
color: #9b1414;
}
#chat-sound-control.checked .glyphicon.glyphicon-volume-off {
display: none;
}
#chat-sound-control.checked .glyphicon.glyphicon-volume-up {
display: block;
}
/* Scroll */
#chat-autoscroll-control {
position: relative;
}
#chat-autoscroll-control .glyphicon.glyphicon-ban-circle {
display: initial;
color: #9b1414;
position: absolute;
left: 0;
}
#chat-autoscroll-control.checked .glyphicon.glyphicon-ban-circle {
display: none;
}
/* Status message */
#chat-statusmessage-control {
position: relative;
color: #6EAEFF;
}
#chat-statusmessage-control .glyphicon.glyphicon-ban-circle {
display: initial;
color: #9b1414;
left: 0;
position: absolute;
}
#chat-statusmessage-control.checked .glyphicon.glyphicon-ban-circle {
display: none;
}
/* Users icon */
.usercount span.glyphicon {
background-color: initial;
}
/* Left menu CSS. */
#left-menu-wrapper {
display: inline-block;
float: left;
position: fixed;
width: 50%;
}
#chat-tabs {
margin: 0;
float: right;
width: 99%;
}
#chat-tabs > li {
margin: 0;
margin-top: 2px;
width: 100% !important;
}
#chat-tabs > li:first-of-type {
margin-top: 0;
}
#chat-tabs a.transition {
display: none;
}
#chat-tabs a.label {
border-radius: 3px 0 0 3px;
text-align: left;
width: 100%;
}
#chat-tabs a.close {
right: -5px;
top: -7px;
}
/* Extra details (badges, non-specific hovers, background colors, etc...) */
#chat-tabs small.unread {
border-radius: 50%;
cursor: default;
height: 17px;
padding: 0;
top: 3px;
text-align: center;
width: 17px;
}
.label[href]:hover, .label[href]:focus {
color: #858585;
}
#chat-pane, #roster-pane {
background: #b0e1f2; /* Old browsers */
background: -moz-linear-gradient(top, #b0e1f2 26%, #81bfe2 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(26%,#b0e1f2), color-stop(100%,#81bfe2)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #b0e1f2 26%,#81bfe2 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #b0e1f2 26%,#81bfe2 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #b0e1f2 26%,#81bfe2 100%); /* IE10+ */
background: linear-gradient(to bottom, #b0e1f2 26%,#81bfe2 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b0e1f2', endColorstr='#81bfe2',GradientType=0 ); /* IE6-9 */
}
/* Compatibility with CreateRoom plugin. */
#create-group {
background: #eee;
border-radius: 3px 0 0 3px;
cursor: pointer !important;
float: right;
height: 18px !important;
margin-right: 1px;
margin-top: 9px;
position: initial;
width: 99%;
}
#create-group .click {
font-size: 75%;
font-weight: 700;
line-height: 1;
vertical-align: baseline;
position: initial;
text-align: left;
}
.row {
margin: 0 !important;
}
/* Align tooltip context menu properly in the roster. */
#context-menu {
margin-top: 48px !important;
}

View File

@ -0,0 +1,104 @@
/** File: lefttabs.js
* Candy Plugin Left Tabs + Bootstrap3 Layout
* Author: Melissa Adamaitis <madamei@mojolingo.com>
*/
/* global window, Candy, jQuery */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.LeftTabs = (function(self, Candy, $) {
/**
* Initializes the LeftTabs plugin with the default settings.
*/
self.init = function(){
Candy.View.Template.Chat = {
pane: '<div class="row" id="chat-pane">{{> tabs}}{{> toolbar}}{{> rooms}}</div>{{> modal}}',
rooms: '<div id="chat-rooms" class="rooms"></div>',
tabs: '<div id="left-menu-wrapper"><iframe width="100%" height="510" src="https://www.youtube.com/embed/yG0oBPtyNb0" frameborder="0" allowfullscreen autoplay="1"></iframe></div>',
tab: '<li class="roomtype-{{roomType}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}">' +
'<a href="#" class="label">{{#privateUserChat}}<span class="glyphicon glyphicon-user"></span> {{/privateUserChat}}{{name}}</a>' +
'<a href="#" class="transition"></a><a href="#" class="close">\u00D7</a>' +
'<small class="unread"></small></li>',
modal: '<div id="chat-modal"><a id="admin-message-cancel" class="close" href="#">\u00D7</a>' +
'<span id="chat-modal-body"></span>' +
'<img src="{{resourcesPath}}img/modal-spinner.gif" id="chat-modal-spinner" />' +
'</div><div id="chat-modal-overlay"></div>',
adminMessage: '<li><small>{{time}}</small><div class="adminmessage">' +
'<span class="label">{{sender}}</span>' +
'<span class="spacer">▸</span>{{subject}} {{message}}</div></li>',
infoMessage: '<li><small>{{time}}</small><div class="infomessage">' +
'<span class="spacer">•</span>{{subject}} {{message}}</div></li>',
toolbar: '<ul id="chat-toolbar">' +
'<li id="emoticons-icon" data-tooltip="{{tooltipEmoticons}}"><span class="glyphicon glyphicon-asterisk"></span></li>' +
'<li id="chat-sound-control" class="checked" data-tooltip="{{tooltipSound}}"><span class="glyphicon glyphicon-volume-up"></span><span class="glyphicon glyphicon-volume-off"></span>{{> soundcontrol}}</li>' +
'<li id="chat-autoscroll-control" class="checked" data-tooltip="{{tooltipAutoscroll}}"><span class="glyphicon glyphicon-arrow-down"></span><span class="glyphicon glyphicon-ban-circle"></span></li>' +
'<li class="checked" id="chat-statusmessage-control" data-tooltip="{{tooltipStatusmessage}}"><span class="glyphicon glyphicon-info-sign"></span><span class="glyphicon glyphicon-ban-circle"></span></li>' +
'<li class="context" data-tooltip="{{tooltipAdministration}}"></li>' +
'<li class="usercount" data-tooltip="{{tooltipUsercount}}"><span class="glyphicon glyphicon-user"></span>' +
'<span id="chat-usercount"></span></li></ul>',
soundcontrol: '<script type="text/javascript">var audioplayerListener = new Object();' +
' audioplayerListener.onInit = function() { };' +
'</script><object id="chat-sound-player" type="application/x-shockwave-flash" data="{{resourcesPath}}audioplayer.swf"' +
' width="0" height="0"><param name="movie" value="{{resourcesPath}}audioplayer.swf" /><param name="AllowScriptAccess"' +
' value="always" /><param name="FlashVars" value="listener=audioplayerListener&amp;mp3={{resourcesPath}}notify.mp3" />' +
'</object>',
Context: {
menu: '<div id="context-menu"><i class="arrow arrow-top"></i>' +
'<ul></ul><i class="arrow arrow-bottom"></i></div>',
menulinks: '<li class="{{class}}" id="context-menu-{{id}}">{{label}}</li>',
contextModalForm: '<form action="#" id="context-modal-form">' +
'<label for="context-modal-label">{{_label}}</label>' +
'<input type="text" name="contextModalField" id="context-modal-field" />' +
'<input type="submit" class="button" name="send" value="{{_submit}}" /></form>',
adminMessageReason: '<a id="admin-message-cancel" class="close" href="#">×</a>' +
'<p>{{_action}}</p>{{#reason}}<p>{{_reason}}</p>{{/reason}}'
},
tooltip: '<div id="tooltip"><i class="arrow arrow-top"></i>' +
'<div></div><i class="arrow arrow-bottom"></i></div>'
};
// Make the message pane the full height of the window.
self.heights();
// Make sure that the window heights are the right size after the window is resized.
$(window).resize(function() {
self.heights();
});
// Make sure that the window heights are the right size after a new room is added.
$(Candy).on('candy:view.room.after-add', function() {
self.heights();
if(typeof CandyShop.CreateRoom === "object") {
self.createRoomPluginCompatibility();
}
});
$(Candy).on('candy:view.message.after-show', function(ev, obj) {
if(Candy.View.Pane.Window.autoscroll) {
$('div[data-roomjid="' + obj.roomJid + '"] .message-pane').scrollTop($('div[data-roomjid="' + obj.roomJid + '"] .message-pane').prop('scrollHeight') + $('div[data-roomjid="' + obj.roomJid + '"] .message-form-wrapper').height());
}
});
};
self.heights = function() {
var barless_height = $(window).height() - $('.message-form-wrapper').height();
var message_pane_height = barless_height;
var message_pane_wrapper_height = (barless_height - parseInt($('.message-pane-wrapper').css('padding-bottom')));
if(CandyShop.RoomBar) {
message_pane_height = barless_height - parseInt($('.roombar').css('height'));
$('.message-pane').css('margin-top', parseInt($('.roombar').css('height')) + 'px');
}
$('.message-pane-wrapper').height(message_pane_wrapper_height + 'px');
$('.message-pane').height(message_pane_height + 'px');
$('.roster-pane').height(barless_height + 'px');
};
self.createRoomPluginCompatibility = function() {
$('#create-group-form button').addClass('btn');
$('#create-group-form .close-button').html('<span class="glyphicon glyphicon-remove"></span>');
};
return self;
}(CandyShop.LeftTabs || {}, Candy, jQuery));

View File

@ -0,0 +1,31 @@
# /me Does
Format /me messages, implementing XEP-0245
## Usage
Include the JavaScript file:
```HTML
<script type="text/javascript" src="candyshop/me-does/candy.js"></script>
```
Call its `init()` method after Candy has been initialized:
```javascript
Candy.init('/http-bind/', {});
// enable /me handling
CandyShop.MeDoes.init();
Candy.Core.connect();
```
Now all messages starting with '/me 'will use infoMessage formatting.
```
/me takes screenshot
```
![Color Picker](me-does-screenshot.png)
**Please note**: As `me-does` reroutes message output, it's call to `init()` should happen after the `init()` of most other plugins, including, `inline-images`.

View File

@ -0,0 +1,47 @@
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.MeDoes = (function(self, Candy, $) {
// CandyShop.Timeago
self.init = function() {
$(Candy).on("candy:view.message.before-show", function(e, args) {
if (args && args.message && args.message.match(/^\/me /i)) {
var message = args.message.match(/^\/([^\s]+)(?:\s+(.*))?$/m)[2];
self.userInfoMessage(args.roomJid, args.name, message);
return false;
}
});
};
if(CandyShop.Timeago === undefined) {
Candy.View.Template.Chat.userInfoMessage = '<li><small>{{time}}</small><div class="infomessage">' +
'<span class="spacer">•</span>&nbsp;<span><strong>{{name}}</strong>&nbsp;{{{message}}}</span></div></li>';
}
else {
Candy.View.Template.Chat.userInfoMessage = '<li><small><abbr title="{{time}}">{{time}}</abbr></small><div class="infomessage">' +
'<span class="spacer">•</span>&nbsp;<span><strong>{{name}}</strong>&nbsp;{{{message}}}</span></div></li>';
}
//Using logic from real infoMessage function and inserting custom template
self.userInfoMessage = function (roomJid, name, message){
if(Candy.View.getCurrent().roomJid) {
var html = Mustache.to_html(Candy.View.Template.Chat.userInfoMessage, {
name: name,
message: message,
time: Candy.Util.localizedTime(new Date().toGMTString())
});
Candy.View.Pane.Room.appendToMessagePane(roomJid, html);
if (Candy.View.getCurrent().roomJid === roomJid) {
Candy.View.Pane.Room.scrollToBottom(Candy.View.getCurrent().roomJid);
}
$(Candy).triggerHandler('candy:view.message.after-show', {
'message' : message
});
}
};
return self;
}(CandyShop.MeDoes || {}, Candy, jQuery));

View File

@ -0,0 +1,29 @@
# Modify role
Adds **add moderator** and **remove moderator** privilege links to context menu.
![Modify role screenshot](screenshot.png)
## Usage
To enable *Modify role* you have to include its JavaScript code and stylesheet:
```HTML
<script type="text/javascript" src="candyshop/modify-role/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/modify-role/candy.css" />
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
// enable ModifyRole plugin
CandyShop.ModifyRole.init();
Candy.Core.connect();
```
## Credits
Thanks to [famfamfam silk icons](http://www.famfamfam.com/lab/icons/silk/) for the icons.
## License
MIT

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,6 @@
#context-menu .add-moderator {
background-image: url(add-moderator.png);
}
#context-menu .remove-moderator {
background-image: url(remove-moderator.png);
}

View File

@ -0,0 +1,97 @@
/** File: candy.js
* Plugin for modifying roles. Currently implemented: op & deop
*
* Authors:
* - Michael Weibel <michael.weibel@gmail.com>
*
* License: MIT
*
* Copyright:
* (c) 2014 Michael Weibel. All rights reserved.
*/
/* global Candy, jQuery, Strophe, $iq */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
/** Class: CandyShop.ModifyRole
* Remove the ignore option in the roster
*/
CandyShop.ModifyRole = (function(self, Candy, $) {
var modifyRole = function modifyRole(role, roomJid, user) {
var conn = Candy.Core.getConnection(),
nick = user.getNick(),
iq = $iq({
'to': Candy.Util.escapeJid(roomJid),
'type': 'set'
});
iq.c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
.c('item', {'nick': nick, 'role': role});
conn.sendIQ(iq.tree());
};
var applyTranslations = function applyTranslations() {
var addModeratorActionLabel = {
'en' : 'Grant moderator status',
'de' : 'Moderator status geben'
};
var removeModeratorActionLabel = {
'en' : 'Remove moderator status',
'de' : 'Moderator status nehmen'
};
$.each(addModeratorActionLabel, function(k, v) {
if(Candy.View.Translation[k]) {
Candy.View.Translation[k].addModeratorActionLabel = v;
}
});
$.each(removeModeratorActionLabel, function(k, v) {
if(Candy.View.Translation[k]) {
Candy.View.Translation[k].removeModeratorActionLabel = v;
}
});
};
var isOwnerOrAdmin = function(user) {
return ['owner', 'admin'].indexOf(user.getAffiliation()) !== -1;
};
var isModerator = function(user) {
return user.getRole() === 'moderator';
};
/** Function: init
* Initializes the plugin by adding an event which modifies
* the contextmenu links.
*/
self.init = function init() {
applyTranslations();
$(Candy).bind('candy:view.roster.context-menu', function(e, args) {
args.menulinks.addModerator = {
requiredPermission: function(user, me) {
return me.getNick() !== user.getNick() && isOwnerOrAdmin(me) && !isOwnerOrAdmin(user) && !isModerator(user);
},
'class' : 'add-moderator',
'label' : $.i18n._('addModeratorActionLabel'),
'callback' : function(e, roomJid, user) {
modifyRole('moderator', roomJid, user);
}
};
args.menulinks.removeModerator = {
requiredPermission: function(user, me) {
return me.getNick() !== user.getNick() && isOwnerOrAdmin(me) && !isOwnerOrAdmin(user) && isModerator(user);
},
'class' : 'remove-moderator',
'label' : $.i18n._('removeModeratorActionLabel'),
'callback' : function(e, roomJid, user) {
modifyRole('participant', roomJid, user);
}
};
});
};
return self;
}(CandyShop.ModifyRole || {}, Candy, jQuery));

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,31 @@
# Name completion plugin
This plugin will complete the names of users in the room when a specified key is pressed.
### Usage
<script type="text/javascript" src="path_to_plugins/namecomplete/candy.js"></script>
<link rel="stylesheet" type="text/css" href="path_to_plugins/namecomplete/candy.css" />
...
CandyShop.NameComplete.init();
### Configuration options
`nameIdentifier` - String - The identifier to look for in a string. Defaults to `'@'`
`completeKeyCode` - Integer - The key code of the key to use. Defaults to `9` (tab)
### Example configurations
// complete the name when the user types +nick and hits the right arrow
// +troymcc -> +troymccabe
CandyShop.NameComplete.init({
nameIdentifier: '+',
completeKeyCode: '39'
});
// complete the name when the user types -nick and hits the up arrow
// +troymcc ^ +troymccabe
CandyShop.NameComplete.init({
nameIdentifier: '-',
completeKeyCode: '38'
});

View File

@ -0,0 +1,7 @@
#context-menu li.selected {
background-color: #ccc;
}
#context-menu li.candy-namecomplete-option {
padding: 3px 5px;
}

View File

@ -0,0 +1,260 @@
/** File: candy.js
* Candy - Chats are not dead yet.
*
* Authors:
* - Troy McCabe <troy.mccabe@geeksquad.com>
* - Ben Klang <bklang@mojolingo.com>
*
* Copyright:
* (c) 2012 Geek Squad. All rights reserved.
* (c) 2014 Power Home Remodeling Group. All rights reserved.
*/
/* global document, Candy, jQuery */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
/** Class: CandyShop.NameComplete
* Allows for completion of a name in the roster
*/
CandyShop.NameComplete = (function(self, Candy, $) {
/** Object: _options
* Options:
* (String) nameIdentifier - Prefix to append to a name to look for. '@' now looks for '@NICK', '' looks for 'NICK', etc. Defaults to '@'
* (Integer) completeKeyCode - Which key to use to complete
*/
var _options = {
nameIdentifier: '@',
completeKeyCode: 9
};
/** Array: _nicks
* An array of nicks to complete from
* Populated after 'candy:core.presence'
*/
var _nicks = [];
/** String: _selector
* The selector for the visible message box
*/
var _selector = 'input[name="message"]:visible';
/** Boolean:_autocompleteStarted
* Keeps track of whether we're in the middle of autocompleting a name
*/
var _autocompleteStarted = false;
/** Function: init
* Initialize the NameComplete plugin
* Show options for auto completion of names
*
* Parameters:
* (Object) options - Options to apply to this plugin
*/
self.init = function(options) {
// apply the supplied options to the defaults specified
$.extend(true, _options, options);
// listen for keydown when autocomplete options exist
$(document).on('keypress', _selector, function(e) {
if (e.which === _options.nameIdentifier.charCodeAt()) {
_autocompleteStarted = true;
}
if (_autocompleteStarted) {
// update the list of nicks to grab
self.populateNicks();
// set up the vars for this method
// break it on spaces, and get the last word in the string
var field = $(this);
var msgParts = field.val().split(' ');
var lastWord = new RegExp( "^" + msgParts[msgParts.length - 1] + String.fromCharCode(e.which), "i");
var matches = [];
// go through each of the nicks and compare it
$(_nicks).each(function(index, item) {
// if we have results
if (item.match(lastWord) !== null) {
matches.push(item);
}
});
// if we only have one match, no need to show the picker, just replace it
// else show the picker of the name matches
if (matches.length === 1) {
self.replaceName(matches[0]);
// Since the name will be autocompleted, throw away the last character
e.preventDefault();
} else if (matches.length > 1) {
self.showPicker(matches, field);
}
}
});
};
/** Function: keyDown
* The listener for keydown in the menu
*/
self.keyDown = function(e) {
// get the menu and the content element
var menu = $('#context-menu');
var content = menu.find('ul');
var selected = content.find('li.selected');
if(menu.css('display') === 'none') {
$(document).unbind('keydown', self.keyDown);
return;
}
// switch the key code
switch (e.which) {
// up arrow
case 38:
// down arrow
case 40:
var newEl;
if (e.which === 38) {
// move the selected thing up
newEl = selected.prev();
} else {
// move the selected thing down
newEl = selected.next();
}
// Prevent going off either end of the list
if ($(newEl).length > 0) {
selected.removeClass('selected');
newEl.addClass('selected');
}
// don't perform any key actions
e.preventDefault();
break;
// esc key
case 27:
// delete Key
case 8:
case 46:
self.endAutocomplete();
break;
// the key code for completion
case _options.completeKeyCode:
case 13:
// get the text of the selected item
var val = content.find('li.selected').text();
// replace the last item with the selected item
self.replaceName(val);
// don't perform any key actions
e.preventDefault();
break;
}
};
/** Function: endAutocomplete
* Disables autocomplete mode, hiding the context menu
*/
self.endAutocomplete = function() {
_autocompleteStarted = false;
$(_selector).unbind('keydown', self.keyDown);
$('#context-menu').hide();
};
/** Function: selectOnClick
* The listener for click on decision in the menu
*
* Parameters:
* (Event) e - The click event
*/
self.selectOnClick = function(e) {
self.replaceName($(e.currentTarget).text());
$(_selector).focus();
e.preventDefault();
};
/** Function: populateNicks
* Populate the collection of nicks to autocomplete from
*/
self.populateNicks = function() {
// clear the nick collection
_nicks = [];
// grab the roster in the current room
var room = Candy.Core.getRoom(Candy.View.getCurrent().roomJid);
if (room !== null) {
var roster = room.getRoster().getAll();
// iterate and add the nicks to the collection
$.each(roster, function(index, item) {
_nicks.push(_options.nameIdentifier + item.getNick());
});
}
};
/** Function: replaceName
*
*/
self.replaceName = function(replaceText) {
// get the parts of the message
var $msgBox = $(_selector);
var msgParts = $msgBox.val().split(' ');
// If the name is the first word, add a colon to the end
if (msgParts.length === 1) {
replaceText += ": ";
} else {
replaceText += " ";
}
// replace the last part with the item
msgParts[msgParts.length - 1] = replaceText;
// put the string back together on spaces
$msgBox.val(msgParts.join(' '));
self.endAutocomplete();
};
/** Function: showPicker
* Show the picker for the list of names that match
*/
self.showPicker = function(matches, elem) {
// get the element
elem = $(elem);
// get the necessary items
var pos = elem.offset(),
menu = $('#context-menu'),
content = $('ul', menu),
i;
// clear the content if needed
content.empty();
// add the matches to the list
for(i = 0; i < matches.length; i++) {
content.append('<li class="candy-namecomplete-option">' + matches[i] + '</li>');
}
// select the first item
$(content.find('li')[0]).addClass('selected');
content.find('li').click(self.selectOnClick);
// bind the keydown to move around the menu
$(_selector).bind('keydown', self.keyDown);
var posLeft = elem.val().length * 7,
posTop = Candy.Util.getPosTopAccordingToWindowBounds(menu, pos.top);
// show it
menu.css({'left': posLeft, 'top': posTop.px, backgroundPosition: posLeft.backgroundPositionAlignment + ' ' + posTop.backgroundPositionAlignment});
menu.fadeIn('fast');
return true;
};
return self;
}(CandyShop.NameComplete || {}, Candy, jQuery));

View File

@ -0,0 +1,26 @@
# Nickchange
Enable your users to change the nick using a toolbar icon.
![Nickchange Icon](screenshot.png)
## Usage
To enable *Nickchange* you have to include its JavaScript code and stylesheet:
```HTML
<script type="text/javascript" src="candyshop/nickchange/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/nickchange/candy.css" />
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
// enable Nickchange plugin
CandyShop.Nickchange.init();
Candy.Core.connect();
```
## Credits
Thanks to [famfamfam silk icons](http://www.famfamfam.com/lab/icons/silk/) for the rename icon.

View File

@ -0,0 +1,3 @@
#nickchange-control {
background: no-repeat url('nickchange-control.png');
}

View File

@ -0,0 +1,63 @@
/**
* Nickchange plugin for Candy
*
* Copyright 2014 Michael Weibel <michael.weibel@gmail.com>
*
* License: MIT
*/
/* global Candy, jQuery, Mustache */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Nickchange = (function(self, Candy, $) {
self.init = function() {
self.applyTranslations();
var html = '<li id="nickchange-control" data-tooltip="' + $.i18n._('candyshopNickchange') + '"></li>';
$('#emoticons-icon').after(html);
$('#nickchange-control').click(function() {
self.showModal();
});
};
self.showModal = function() {
Candy.View.Pane.Chat.Modal.show(Mustache.to_html(self.nicknameChangeForm, {
_labelNickname: $.i18n._('labelNickname'),
_label: $.i18n._('candyshopNickchange')
}));
$('#nickname').focus();
// register submit handler
$('#nickname-change-form').submit(self.changeNickname);
};
self.changeNickname = function() {
var nickname = $('#nickname').val();
Candy.View.Pane.Chat.Modal.hide(function() {
Candy.Core.Action.Jabber.SetNickname(nickname);
});
return false;
};
self.nicknameChangeForm = '<strong>{{_label}}</strong>' +
'<form method="post" id="nickname-change-form" class="nickname-change-form">' +
'<label for="nickname">{{_labelNickname}}</label><input type="text" id="nickname" name="nickname" />' +
'<input type="submit" class="button" value="{{_label}}" /></form>';
self.applyTranslations = function() {
var translations = {
'en' : 'Change nickname',
'de' : 'Spitzname ändern'
};
$.each(translations, function(k, v) {
if(Candy.View.Translation[k]) {
Candy.View.Translation[k].candyshopNickchange = v;
}
});
};
return self;
}(CandyShop.Nickchange || {}, Candy, jQuery));

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

View File

@ -0,0 +1,29 @@
# Notifications
Send HTML5 Notifications when a message is received and the window is not in focus. This only works with webkit browsers.
## Usage
To enable *Notifications* you have to include its JavaScript code and stylesheet:
```HTML
<script type="text/javascript" src="candyshop/notifications/candy.js"></script>
```
Call its `init()` method after Candy has been initialized:
```JavaScript
Candy.init('/http-bind/');
CandyShop.Notifications.init();
Candy.Core.connect();
```
It is possible to configure the Plugin.
```JavaScript
CandyShop.Notifications.init({
notifyNormalMessage: false, // Send a notification for every message. Defaults to false
notifyPersonalMessage: true, // Send a notification if the user is mentioned. (Requires NotfiyMe Plugin) Defaults to true
closeTime: 3000 // Close notification after X milliseconds. Zero means it doesn't close automaticly. Defaults to 3000
});
```

View File

@ -0,0 +1,111 @@
/*
* HTML5 Notifications
* @version 1.0
* @author Jonatan Männchen <jonatan@maennchen.ch>
* @author Melissa Adamaitis <madamei@mojolingo.com>
*
* Notify user if new messages come in.
*/
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Notifications = (function(self, Candy, $) {
/** Object: _options
* Options for this plugin's operation
*
* Options:
* (Boolean) notifyNormalMessage - Notification on normalmessage. Defaults to false
* (Boolean) notifyPersonalMessage - Notification for private messages. Defaults to true
* (Boolean) notifyMention - Notification for mentions. Defaults to true
* (Integer) closeTime - Time until closing the Notification. (0 = Don't close) Defaults to 3000
* (String) title - Title to be used in notification popup. Set to null to use the contact's name.
* (String) icon - Path to use for image/icon for notification popup.
*/
var _options = {
notifyNormalMessage: false,
notifyPersonalMessage: true,
notifyMention: true,
closeTime: 3000,
title: null,
icon: window.location.origin + '/' + Candy.View.getOptions().assets + '/img/favicon.png'
};
/** Function: init
* Initializes the notifications plugin.
*
* Parameters:
* (Object) options - The options to apply to this plugin
*
* @return void
*/
self.init = function(options) {
// apply the supplied options to the defaults specified
$.extend(true, _options, options);
// Just init if notifications are supported
if (window.Notification) {
// Setup Permissions (has to be kicked on with some user-events)
jQuery(document).one('click keydown', self.setupPermissions);
// Add Listener for Notifications
$(Candy).on('candy:view.message.notify', self.handleNotification);
}
};
/** Function: checkPermissions
* Check if the plugin has permission to send notifications.
*
* @return boid
*/
self.setupPermissions = function() {
// Check if permissions is given
if (window.Notification !== 0) { // 0 is PERMISSION_ALLOWED
// Request for it
window.Notification.requestPermission();
}
};
/** Function: handleNotification
* Descriptions
*
* Parameters:
* (Array) args
*
* @return void
*/
self.handleNotification = function(e, args) {
// Check if window has focus, so no notification needed
if (!document.hasFocus()) {
if(_options.notifyNormalMessage ||
(self.mentionsMe(args.message) && _options.notifyMention) ||
(_options.notifyPersonalMessage && Candy.View.Pane.Chat.rooms[args.roomJid].type === 'chat')) {
// Create the notification.
var title = !_options.title ? args.name : _options.title ,
notification = new window.Notification(title, {
icon: _options.icon,
body: args.message
});
// Close it after 3 Seconds
if(_options.closeTime) {
window.setTimeout(function() { notification.close(); }, _options.closeTime);
}
}
}
};
self.mentionsMe = function(message) {
var message = message.toLowerCase(),
nick = Candy.Core.getUser().getNick().toLowerCase(),
cid = Strophe.getNodeFromJid(Candy.Core.getUser().getJid()).toLowerCase(),
jid = Candy.Core.getUser().getJid().toLowerCase();
if (message.indexOf(nick) === -1 &&
message.indexOf(cid) === -1 &&
message.indexOf(jid) === -1) {
return false;
}
return true;
};
return self;
}(CandyShop.Notifications || {}, Candy, jQuery));

View File

@ -0,0 +1,29 @@
# Reply Highlighting
To better support conversations in high-activity rooms, this plugin highlights any message that contains "@yourusername" by default.
## Usage
```HTML
<script type="text/javascript" src="candyshop/replies/candy.js"></script>
<link rel="stylesheet" type="text/css" href="candyshop/replies/candy.css" />
```
```JavaScript
CandyShop.Replies.init();
```
```Options
boolean - default true - require @ if true
prefix - strip a prefix while searching
suffix - strip a suffix while searching
```
Prefix & suffix assume generated user names for an anonymous user. For example, say your generated nick is _user533_ , and they change their nickname to _jimbob_. With the options:
```JavaScript
CandyShop.Replies.init(false,'user','');
```
This would highlight lines with _user533_, _533_, and _jimbob_ in them.

View File

@ -0,0 +1,4 @@
.message-pane li.mention,
.message-pane li.mention small {
background-color: #FFF7DE;
}

View File

@ -0,0 +1,50 @@
/*
* candy-replies-plugin
* @version 0.4 (2015-02-05)
* @author Drew Harry (drew.harry@gmail.com)
* Contributors:
* - Sudrien <_+github@sudrien.net>
*
* Adds @reply highlighting to chat messages to help with high velocity
* conversations.
*/
/* global Candy, jQuery */
var CandyShop = (function(self) { return self; }(CandyShop || {}));
CandyShop.Replies = (function(self, Candy, $) {
var requireAt = true,
prefix = '',
suffix = '';
self.init = function( requireAtValue, prefixValue, suffixValue ) {
requireAt = typeof requireAtValue !== 'undefined' ? requireAtValue : true;
prefix = prefixValue !== undefined ? prefixValue : '';
suffix = suffixValue !== undefined ? suffixValue : '';
$(Candy).on('candy:view.message.after-show', handleOnShow);
return self;
};
var handleOnShow = function(e, args) {
var possibleNicks = $('.me').map(function(){ return $(this).attr('data-nick'); });
possibleNicks.push(Candy.Core.getUser().getNick());
$.unique(possibleNicks).each(function(key,nick) {
if( RegExp("(\\W|^)" + ( requireAt ? '@' : '' ) + nick + "(\\W|$)" , "im").test(args.message) ) {
$(args.element).addClass("mention");
}
if( prefix !== '' || suffix !== '') {
var shortNick = nick.replace( RegExp("^" + prefix), "").replace( RegExp( suffix + "$"), "");
if( RegExp("(\\W|^)" + ( requireAt ? '@' : '' ) + shortNick + "(\\W|$)" , "im").test(args.message) ) {
$(args.element).addClass("mention");
}
}
});
}
return self;
}(CandyShop.Replies || {}, Candy, jQuery));

4
candy.min.js vendored Normal file

File diff suppressed because one or more lines are too long

69
index.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>IF XMPP chat</title>
<link rel="shortcut icon" href="res/img/favicon.png" type="image/gif" />
<link rel="stylesheet" type="text/css" href="res/default.css" />
<!-- Plugins -->
<link rel="stylesheet" type="text/css" href="candy-plugins/colors-xhtml/candy.css" />
<link rel="stylesheet" type="text/css" href="candy-plugins/inline-images/candy.css" />
<link rel="stylesheet" type="text/css" href="candy-plugins/modify-role/candy.css" />
<link rel="stylesheet" type="text/css" href="candy-plugins/namecomplete/candy.css" />
<link rel="stylesheet" type="text/css" href="candy-plugins/nickchange/candy.css" />
<link rel="stylesheet" type="text/css" href="candy-plugins/replies/candy.css" />
<link rel="stylesheet" type="text/css" href="candy-plugins/lefttabs/lefttabs.css" />
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="libs.min.js"></script>
<script type="text/javascript" src="candy.min.js"></script>
<!-- Plugins -->
<script type="text/javascript" src="candy-plugins/colors-xhtml/candy.js"></script>
<script type="text/javascript" src="candy-plugins/chatrecall/candy.js"></script>
<script type="text/javascript" src="candy-plugins/emphasis/candy.js"></script>
<script type="text/javascript" src="candy-plugins/me-does/candy.js"></script>
<script type="text/javascript" src="candy-plugins/modify-role/candy.js"></script>
<script type="text/javascript" src="candy-plugins/namecomplete/candy.js"></script>
<script type="text/javascript" src="candy-plugins/nickchange/candy.js"></script>
<script type="text/javascript" src="candy-plugins/notifications/candy.js"></script>
<script type="text/javascript" src="candy-plugins/replies/candy.js"></script>
<script type="text/javascript" src="candy-plugins/lefttabs/lefttabs.js"></script>
<script type="text/javascript">
$(document).ready(function() {
CandyShop.LeftTabs.init();
Candy.init('https://oreolek.ru:5281/http-bind/', {
core: {
debug: false,
autojoin: ['webinar@conference.oreolek.ru'],
},
view: {
assets: 'res/',
language: 'ru',
// enable XHTML for colors plugin
enableXHTML: true
}
});
// enable Colors-XHTML plugin (default: 8 colors)
CandyShop.ColorsXhtml.init();
CandyShop.ChatRecall.init();
// enable basic textile/BBCode/Html handling
CandyShop.Emphasis.init();
CandyShop.NameComplete.init();
CandyShop.Replies.init();
// enable /me handling
CandyShop.MeDoes.init();
CandyShop.ModifyRole.init();
CandyShop.Nickchange.init();
CandyShop.Notifications.init();
Candy.Core.connect("guest.oreolek.ru");
});
</script>
</head>
<body>
<div id="candy"></div>
</body>
</html>

3
libs.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
res/audioplayer.swf Normal file

Binary file not shown.

674
res/default.css Normal file
View File

@ -0,0 +1,674 @@
/**
* Chat CSS
*
* @author Michael <michael.weibel@gmail.com>
* @author Patrick <patrick.stadler@gmail.com>
* @copyright 2011 Amiado Group AG, All rights reserved.
* @copyright 2012-2014 Patrick Stadler & Michael Weibel. All rights reserved.
*/
html, body {
margin: 0;
padding: 0;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
}
#candy {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background-color: #444;
color: #333;
overflow: hidden;
}
a {
color: #333;
text-decoration: none;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
#chat-tabs {
list-style: none;
margin: 0 200px 0 0;
padding: 0;
overflow: auto;
overflow-y: hidden;
}
#chat-tabs li {
margin: 0;
float: left;
position: relative;
white-space: nowrap;
margin: 3px 0 0 3px;
}
#chat-tabs a {
padding: 4px 50px 4px 10px;
display: inline-block;
color: #ccc;
height: 20px;
background-color: #666;
border-radius: 3px 3px 0 0;
}
#chat-tabs .active a {
background-color: #eee;
color: black;
}
#chat-tabs .transition {
position: absolute;
top: 0;
right: 0;
padding: 0;
width: 35px;
height: 30px;
background: url(img/tab-transitions.png) repeat-y left;
border-radius: 0 3px 0 0;
}
#chat-tabs a.close {
background-color: transparent;
position: absolute;
right: -2px;
top: -3px;
height: auto;
padding: 5px;
margin: 0 5px 0 2px;
color: #999;
}
#chat-tabs .active .transition {
background: url(img/tab-transitions.png) repeat-y -50px;
}
#chat-tabs .close:hover {
color: black;
}
#chat-tabs .unread {
color: white;
background-color: #9b1414;
padding: 2px 4px;
font-weight: bold;
font-size: 10px;
position: absolute;
top: 5px;
right: 22px;
border-radius: 3px;
}
#chat-tabs .offline .label {
text-decoration: line-through;
}
#chat-toolbar {
position: fixed;
bottom: 0;
right: 0;
font-size: 11px;
color: #666;
width: 200px;
height: 24px;
padding-top: 7px;
background-color: #444;
display: none;
border-top: 1px solid black;
box-shadow: 0 1px 0 0 #555 inset;
}
#chat-toolbar li {
width: 16px;
height: 16px;
margin-left: 5px;
float: left;
display: inline-block;
cursor: pointer;
background-position: top left;
background-repeat: no-repeat;
}
#chat-toolbar #emoticons-icon {
background-image: url(img/action/emoticons.png);
}
#chat-toolbar .context {
background-image: url(img/action/settings.png);
display: none;
}
.role-moderator #chat-toolbar .context, .affiliation-owner #chat-toolbar .context {
display: inline-block;
}
#chat-sound-control {
background-image: url(img/action/sound-off.png);
}
#chat-sound-control.checked {
background-image: url(img/action/sound-on.png);
}
#chat-autoscroll-control {
background-image: url(img/action/autoscroll-off.png);
}
#chat-autoscroll-control.checked {
background-image: url(img/action/autoscroll-on.png);
}
#chat-statusmessage-control {
background: url(img/action/statusmessage-off.png);
}
#chat-statusmessage-control.checked {
background: url(img/action/statusmessage-on.png);
}
#chat-toolbar .usercount {
background-image: url(img/action/usercount.png);
cursor: default;
padding-left: 20px;
width: auto;
margin-right: 5px;
float: right;
}
.usercount span {
display: inline-block;
padding: 1px 3px;
background-color: #666;
font-weight: bold;
border-radius: 3px;
color: #ccc;
}
.room-pane {
display: none;
}
.roster-pane {
position: absolute;
overflow: auto;
top: 0;
right: 0;
bottom: 0;
width: 200px;
margin: 30px 0 32px 0;
background-color: #333;
border-top: 1px solid black;
box-shadow: inset 0 1px 0 0 #555;
}
.roster-pane .user {
cursor: pointer;
padding: 7px 10px;
font-size: 12px;
opacity: 0;
display: none;
color: #ccc;
clear: both;
height: 14px;
border-bottom: 1px solid black;
box-shadow: 0 1px 0 0 #555;
}
.roster-pane .user:hover {
background-color: #222;
}
.roster-pane .user.status-ignored {
cursor: default;
}
.roster-pane .user.me {
font-weight: bold;
cursor: default;
}
.roster-pane .user.me:hover {
background-color: transparent;
}
.roster-pane .label {
float: left;
width: 110px;
overflow: hidden;
white-space: nowrap;
text-shadow: 1px 1px black;
}
.roster-pane li {
width: 16px;
height: 16px;
float: right;
display: block;
margin-left: 3px;
background-repeat: no-repeat;
background-position: center;
}
.roster-pane li.role {
cursor: default;
display: none;
}
.roster-pane li.role-moderator {
background-image: url(img/roster/role-moderator.png);
display: block;
}
.roster-pane li.affiliation-owner {
background-image: url(img/roster/affiliation-owner.png);
display: block;
}
.roster-pane li.ignore {
background-image: url(img/roster/ignore.png);
display: none;
}
.roster-pane .status-ignored li.ignore {
display: block;
}
.roster-pane li.context {
color: #999;
text-align: center;
cursor: pointer;
}
.roster-pane li.context:hover {
background-color: #666;
border-radius: 4px;
}
.roster-pane .me li.context {
display: none;
}
.message-pane-wrapper {
clear: both;
overflow: auto;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: auto;
width: auto;
margin: 30px 200px 31px 0;
background-color: #eee;
font-size: 13px;
padding: 0 5px;
}
.message-pane {
padding-top: 1px;
}
.message-pane li {
cursor: default;
border-bottom: 1px solid #ccc;
box-shadow: 0 1px 0 0 white;
}
.message-pane small {
display: none;
color: #a00;
font-size: 10px;
position: absolute;
background-color: #f7f7f7;
text-align: center;
line-height: 20px;
margin: 4px 0;
padding: 0 5px;
right: 5px;
}
.message-pane li:hover {
background-color: #f7f7f7;
}
.message-pane li:hover small {
display: block;
}
.message-pane li>div {
overflow: auto;
padding: 2px 0 2px 130px;
line-height: 24px;
white-space: -o-pre-wrap; /* Opera */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.message-pane li>div p {
margin: 0;
}
.message-pane .label {
font-weight: bold;
white-space: nowrap;
display: block;
margin-left: -130px;
width: 110px;
float: left;
overflow: hidden;
text-align: right;
color: black;
}
.message-pane .spacer {
color: #aaa;
font-weight: bold;
margin-left: -14px;
float: left;
}
.message-pane .subject, .message-pane .subject .label {
color: #a00;
font-weight: bold;
}
.message-pane .adminmessage {
color: #a00;
font-weight: bold;
}
.message-pane .infomessage {
color: #888;
font-style: italic;
}
.message-pane div>a {
color: #a00;
}
.message-pane a:hover {
text-decoration: underline;
}
.message-pane .emoticon {
vertical-align: text-bottom;
height: 15px;
width: 15px;
}
.message-form-wrapper {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: auto;
margin-right: 200px;
border-top: 1px solid #ccc;
background-color: white;
height: 31px;
}
.message-form {
position: fixed;
bottom: 0;
left: 0;
right: 0;
margin-right: 320px;
padding: 0;
}
.message-form input {
border: 0 none;
padding: 5px 10px;
font-size: 14px;
width: 100%;
display: block;
outline-width: 0;
background-color: white;
}
.message-form input.submit {
cursor: pointer;
background-color: #ccc;
color: #666;
position: fixed;
bottom: 0;
right: 0;
margin: 3px 203px 3px 3px;
padding: 5px 7px;
width: auto;
font-size: 12px;
line-height: 12px;
height: 25px;
font-weight: bold;
border-radius: 3px;
}
#tooltip {
position: absolute;
z-index: 10;
display: none;
margin: 13px -18px -3px -2px;
color: #333;
font-size: 11px;
padding: 5px 0;
}
#tooltip div {
background-color: #f7f7f7;
padding: 2px 5px;
zoom: 1;
box-shadow: 0 1px 2px rgba(0, 0, 0, .75);
}
.arrow {
background: url(img/tooltip-arrows.gif) no-repeat left bottom;
height: 5px;
display: block;
position: relative;
z-index: 11;
}
.right-bottom .arrow-bottom {
background-position: right bottom;
}
.arrow-top {
display: none;
background-position: left top;
}
.right-top .arrow-top {
display: block;
background-position: right top;
}
.left-top .arrow-top {
display: block;
}
.left-top .arrow-bottom,
.right-top .arrow-bottom {
display: none;
}
#context-menu {
position: absolute;
z-index: 10;
display: none;
padding: 5px 10px;
margin: 13px -28px -3px -12px;
}
#context-menu ul {
background-color: #f7f7f7;
color: #333;
font-size: 12px;
padding: 2px;
zoom: 1;
box-shadow: 0 1px 2px rgba(0, 0, 0, .75);
}
#context-menu li {
padding: 3px 5px 3px 20px;
line-height: 12px;
cursor: pointer;
margin-bottom: 2px;
background: 1px no-repeat;
white-space: nowrap;
}
#context-menu li:hover {
background-color: #ccc;
}
#context-menu li:last-child {
margin-bottom: 0;
}
#context-menu .private {
background-image: url(img/action/private.png);
}
#context-menu .ignore {
background-image: url(img/action/ignore.png);
}
#context-menu .unignore {
background-image: url(img/action/unignore.png);
}
#context-menu .kick {
background-image: url(img/action/kick.png);
}
#context-menu .ban {
background-image: url(img/action/ban.png);
}
#context-menu .subject {
background-image: url(img/action/subject.png);
}
#context-menu .emoticons {
padding-left: 5px;
width: 85px;
white-space: normal;
}
#context-menu .emoticons:hover {
background-color: transparent;
}
#context-menu .emoticons img {
cursor: pointer;
margin: 3px;
height: 15px;
width: 15px;
}
#chat-modal {
background: #eee;
width: 300px;
padding: 20px 5px;
color: #333;
font-size: 16px;
position: fixed;
left: 50%;
top: 50%;
margin-left: -160px;
margin-top: -45px;
text-align: center;
display: none;
z-index: 100;
border: 5px solid #888;
border-radius: 5px;
box-shadow: 0 0 5px black;
}
#chat-modal-overlay {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 90;
background-image: url(img/overlay.png);
}
#chat-modal.modal-login {
display: block;
margin-top: -100px;
}
#chat-modal-spinner {
display: none;
margin-left: 15px;
}
#chat-modal form {
margin: 15px 0;
}
#chat-modal label, #chat-modal input, #chat-modal select {
display: block;
float: left;
line-height: 26px;
font-size: 16px;
margin: 5px 0;
}
#chat-modal input, #chat-modal select {
padding: 2px;
line-height: 16px;
width: 150px;
}
#chat-modal input[type='text'],
#chat-modal input[type='password'] {
background-color: white;
border: 1px solid #ccc;
padding: 4px;
font-size: 14px;
color: #333;
}
#chat-modal label {
text-align: right;
padding-right: 1em;
clear: both;
width: 100px;
}
#chat-modal input.button {
float: none;
display: block;
margin: 5px auto;
clear: both;
position: relative;
top: 10px;
width: 200px;
}
#chat-modal .close {
position: absolute;
right: 0;
display: none;
padding: 0 5px;
margin: -17px 3px 0 0;
color: #999;
border-radius: 3px;
}
#chat-modal .close:hover {
color: #333;
background-color: #aaa;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

BIN
res/img/action/ban.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

BIN
res/img/action/ignore.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

BIN
res/img/action/kick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

BIN
res/img/action/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
res/img/action/private.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

BIN
res/img/action/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
res/img/action/sound-on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

BIN
res/img/action/subject.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

BIN
res/img/action/unignore.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

BIN
res/img/emoticons/Angel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
res/img/emoticons/Angry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
res/img/emoticons/Aww.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/img/emoticons/Aww_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B

BIN
res/img/emoticons/Cute.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/img/emoticons/Devil.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
res/img/emoticons/Gah.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/img/emoticons/Gah_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/img/emoticons/Happy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/img/emoticons/Heart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
res/img/emoticons/Huh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/img/emoticons/Huh_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

2
res/img/emoticons/README Normal file
View File

@ -0,0 +1,2 @@
Simple Smileys is a set of 49 clean, free as in freedom, Public Domain smileys.
For more packages or older versions, visit http://simplesmileys.org

BIN
res/img/emoticons/Sick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

BIN
res/img/emoticons/Tired.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Some files were not shown because too many files have changed in this diff Show More