commit 6c69cdffcca0e15d4f372950688f3f5a460a9c89 Author: Alexander Yakovlev Date: Sat Feb 20 11:14:40 2016 +0700 Интерфейс на основе candy diff --git a/candy-plugins/chatrecall/README.md b/candy-plugins/chatrecall/README.md new file mode 100644 index 0000000..66534a7 --- /dev/null +++ b/candy-plugins/chatrecall/README.md @@ -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 + +``` + +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 +}); +``` \ No newline at end of file diff --git a/candy-plugins/chatrecall/candy.js b/candy-plugins/chatrecall/candy.js new file mode 100644 index 0000000..2e2e1d7 --- /dev/null +++ b/candy-plugins/chatrecall/candy.js @@ -0,0 +1,116 @@ +/** File: candy.js + * Candy - Chats are not dead yet. + * + * Authors: + * - Troy McCabe + * + * 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)); diff --git a/candy-plugins/colors-xhtml/README.md b/candy-plugins/colors-xhtml/README.md new file mode 100644 index 0000000..da86a1f --- /dev/null +++ b/candy-plugins/colors-xhtml/README.md @@ -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 + + +``` + +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. \ No newline at end of file diff --git a/candy-plugins/colors-xhtml/candy.css b/candy-plugins/colors-xhtml/candy.css new file mode 100644 index 0000000..4d45c16 --- /dev/null +++ b/candy-plugins/colors-xhtml/candy.css @@ -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; +} \ No newline at end of file diff --git a/candy-plugins/colors-xhtml/candy.js b/candy-plugins/colors-xhtml/candy.js new file mode 100644 index 0000000..90531b6 --- /dev/null +++ b/candy-plugins/colors-xhtml/candy.js @@ -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 = '' + Candy.Util.Parser.escape(args.message) + ''; + } + }); + + 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 = '
  • '; + $('#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 = '' + colors; + } + content.html('
  • ' + colors + '
  • '); + 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)); diff --git a/candy-plugins/colors-xhtml/colors-control.png b/candy-plugins/colors-xhtml/colors-control.png new file mode 100644 index 0000000..bc2ef7b Binary files /dev/null and b/candy-plugins/colors-xhtml/colors-control.png differ diff --git a/candy-plugins/colors/README.md b/candy-plugins/colors/README.md new file mode 100644 index 0000000..868b73b --- /dev/null +++ b/candy-plugins/colors/README.md @@ -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 + + +``` + +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()`. diff --git a/candy-plugins/colors/candy.css b/candy-plugins/colors/candy.css new file mode 100644 index 0000000..1b6ec8f --- /dev/null +++ b/candy-plugins/colors/candy.css @@ -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; +} \ No newline at end of file diff --git a/candy-plugins/colors/candy.js b/candy-plugins/colors/candy.js new file mode 100644 index 0000000..8361c39 --- /dev/null +++ b/candy-plugins/colors/candy.js @@ -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, '$2'); + }); + + 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 = '
  • '; + $('#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 = '' + colors; + } + content.html('
  • ' + colors + '
  • '); + 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)); diff --git a/candy-plugins/colors/colors-control.png b/candy-plugins/colors/colors-control.png new file mode 100644 index 0000000..bc2ef7b Binary files /dev/null and b/candy-plugins/colors/colors-control.png differ diff --git a/candy-plugins/emphasis/README.md b/candy-plugins/emphasis/README.md new file mode 100644 index 0000000..b330352 --- /dev/null +++ b/candy-plugins/emphasis/README.md @@ -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] +bold +bold +``` + +_italic_ +``` +_italic_ +[i]italic[/i] +italic +italic +``` + +underlined +``` ++underlined+ +[u]underlined[/u] +underlined +underlined +``` + +~~strikethrough~~ +``` +-strikethrough- +[s]strikethrough[/s] +strinkethough +strikethrough +``` + +Textile can be escaped like so: + +``` +==-strikethrough-== +``` + +This plugin is compatible with colors-xhtml. + + + +## Usage +Include the JavaScript file: + +```HTML + +``` + +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 }); +``` diff --git a/candy-plugins/emphasis/candy.js b/candy-plugins/emphasis/candy.js new file mode 100644 index 0000000..dcaa80e --- /dev/null +++ b/candy-plugins/emphasis/candy.js @@ -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$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" } + ], + bbcode: [ + { plain: '[b]bold[/b]', regex: /(\[b\](.*?)\[\/b\])/igm, plain: "*$2*", xhtml: "$2" }, + { plain: '[i]italic[/i]', regex: /(\[i\](.*?)\[\/i\])/igm, plain: "_$2_", xhtml: "$2" }, + { plain: '[s]strikethrough[/s]', regex: /(\[s\](.*?)\[\/s\])/igm, plain: "-$2-", xhtml: "$2" }, + { plain: '[u]underline[/u]', regex: /(\[u\](.*?)\[\/u\])/igm, plain: "+$2+", xhtml: "$2" } + ], + html: [ + //handling both escaped an unescaped, just in case. + { plain: '<b>bold</b>', regex: /(\<b\>(.*?)\<\/b\>)/igm, plain: "*$2*", xhtml: "$2" }, + { plain: '<strong>bold</strong>', regex: /(\<strong\>(.*?)\<\/strong\>)/igm, plain: "*$2*", xhtml: "$2" }, + { plain: '<i>italic</i>', regex: /(\<i\>(.*?)\<\/i\>)/igm, plain: "_$2_", xhtml: "$2" }, + { plain: '<em>italic</em>', regex: /(\<em\>(.*?)\<\/em\>)/igm, plain: "_$2_", xhtml: "$2" }, + { plain: '<s>strikethrough</s>', regex: /(\<s\>(.*?)\<\/s\>)/igm, plain: "-$2-", xhtml: "$2" }, + { plain: '<del>strikethrough</del>', regex: /(\<del\>(.*?)\<\/del\>)/igm, plain: "-$2-", xhtml: "$2" }, + { plain: '<u>underline</u>', regex: /(\<u\>(.*?)\<\/u\>)/igm, plain: "+$2+", xhtml: "$2" }, + { plain: '<ins>underline</ins>', regex: /(\<ins\>(.*?)\<\/ins\>)/igm, plain: "+$2+", xhtml: "$2" }, + { plain: 'bold', regex: /(\(.*?)\<\/b\>)/igm, plain: "*$2*", xhtml: "$2" }, + { plain: 'bold', regex: /(\(.*?)\<\/strong\>)/igm, plain: "*$2*", xhtml: "$2" }, + { plain: 'italic', regex: /(\(.*?)\<\/i\>)/igm, plain: "_$2_", xhtml: "$2" }, + { plain: 'italic', regex: /(\(.*?)\<\/em\>)/igm, plain: "_$2_", xhtml: "$2" }, + { plain: 'strikethrough', regex: /(\(.*?)\<\/s\>)/igm, plain: "-$2-", xhtml: "$2" }, + { plain: 'strikethrough', regex: /(\(.*?)\<\/del\>)/igm, plain: "-$2-", xhtml: "$2" }, + { plain: 'underline', regex: /(\(.*?)\<\/u\>)/igm, plain: "+$2+", xhtml: "$2" }, + { plain: 'underline', regex: /(\(.*?)\<\/ins\>)/igm, plain: "+$2+", xhtml: "$2" } + + ] + }; + + 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 = "" + workingXhtmlMessage + ""; + } + args.message = workingPlainMessage; + args.xhtmlMessage = workingXhtmlMessage; + } + }); + + }; + + return self; +}(CandyShop.Emphasis || {}, Candy, jQuery)); diff --git a/candy-plugins/lefttabs/README.md b/candy-plugins/lefttabs/README.md new file mode 100644 index 0000000..1fe116e --- /dev/null +++ b/candy-plugins/lefttabs/README.md @@ -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 + + +``` +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 diff --git a/candy-plugins/lefttabs/lefttabs.css b/candy-plugins/lefttabs/lefttabs.css new file mode 100644 index 0000000..6641480 --- /dev/null +++ b/candy-plugins/lefttabs/lefttabs.css @@ -0,0 +1,239 @@ +/** + * LeftTabs CSS + * + * @author Melissa Adamaitis + */ + +/* 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; +} diff --git a/candy-plugins/lefttabs/lefttabs.js b/candy-plugins/lefttabs/lefttabs.js new file mode 100644 index 0000000..f2d68d8 --- /dev/null +++ b/candy-plugins/lefttabs/lefttabs.js @@ -0,0 +1,104 @@ +/** File: lefttabs.js + * Candy Plugin Left Tabs + Bootstrap3 Layout + * Author: Melissa Adamaitis + */ + +/* 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: '
    {{> tabs}}{{> toolbar}}{{> rooms}}
    {{> modal}}', + rooms: '
    ', + tabs: '
    ', + tab: '
  • ' + + '{{#privateUserChat}} {{/privateUserChat}}{{name}}' + + '\u00D7' + + '
  • ', + modal: '
    \u00D7' + + '' + + '' + + '
    ', + adminMessage: '
  • {{time}}
    ' + + '{{sender}}' + + '{{subject}} {{message}}
  • ', + infoMessage: '
  • {{time}}
    ' + + '{{subject}} {{message}}
  • ', + toolbar: '
      ' + + '
    • ' + + '
    • {{> soundcontrol}}
    • ' + + '
    • ' + + '
    • ' + + '
    • ' + + '
    • ' + + '
    ', + soundcontrol: '' + + '', + Context: { + menu: '
    ' + + '
      ', + menulinks: '
    • {{label}}
    • ', + contextModalForm: '
      ' + + '' + + '' + + '
      ', + adminMessageReason: '×' + + '

      {{_action}}

      {{#reason}}

      {{_reason}}

      {{/reason}}' + }, + tooltip: '
      ' + + '
      ' + }; + + // 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(''); + }; + + return self; +}(CandyShop.LeftTabs || {}, Candy, jQuery)); diff --git a/candy-plugins/me-does/README.md b/candy-plugins/me-does/README.md new file mode 100644 index 0000000..7128183 --- /dev/null +++ b/candy-plugins/me-does/README.md @@ -0,0 +1,31 @@ +# /me Does + +Format /me messages, implementing XEP-0245 + +## Usage +Include the JavaScript file: + +```HTML + +``` + +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`. diff --git a/candy-plugins/me-does/candy.js b/candy-plugins/me-does/candy.js new file mode 100644 index 0000000..ed8b357 --- /dev/null +++ b/candy-plugins/me-does/candy.js @@ -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 = '
    • {{time}}
      ' + + ' {{name}} {{{message}}}
    • '; + } + else { + Candy.View.Template.Chat.userInfoMessage = '
    • {{time}}
      ' + + ' {{name}} {{{message}}}
    • '; + } + + //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)); diff --git a/candy-plugins/modify-role/README.md b/candy-plugins/modify-role/README.md new file mode 100644 index 0000000..daaa3d8 --- /dev/null +++ b/candy-plugins/modify-role/README.md @@ -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 + + +``` + +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 \ No newline at end of file diff --git a/candy-plugins/modify-role/add-moderator.png b/candy-plugins/modify-role/add-moderator.png new file mode 100644 index 0000000..f8153f7 Binary files /dev/null and b/candy-plugins/modify-role/add-moderator.png differ diff --git a/candy-plugins/modify-role/candy.css b/candy-plugins/modify-role/candy.css new file mode 100644 index 0000000..f6246bc --- /dev/null +++ b/candy-plugins/modify-role/candy.css @@ -0,0 +1,6 @@ +#context-menu .add-moderator { + background-image: url(add-moderator.png); +} +#context-menu .remove-moderator { + background-image: url(remove-moderator.png); +} \ No newline at end of file diff --git a/candy-plugins/modify-role/candy.js b/candy-plugins/modify-role/candy.js new file mode 100644 index 0000000..0996986 --- /dev/null +++ b/candy-plugins/modify-role/candy.js @@ -0,0 +1,97 @@ +/** File: candy.js + * Plugin for modifying roles. Currently implemented: op & deop + * + * Authors: + * - Michael Weibel + * + * 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)); diff --git a/candy-plugins/modify-role/remove-moderator.png b/candy-plugins/modify-role/remove-moderator.png new file mode 100644 index 0000000..e694a77 Binary files /dev/null and b/candy-plugins/modify-role/remove-moderator.png differ diff --git a/candy-plugins/namecomplete/README.md b/candy-plugins/namecomplete/README.md new file mode 100644 index 0000000..011a4c9 --- /dev/null +++ b/candy-plugins/namecomplete/README.md @@ -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 + + + + ... + + 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' + }); \ No newline at end of file diff --git a/candy-plugins/namecomplete/candy.css b/candy-plugins/namecomplete/candy.css new file mode 100644 index 0000000..0102f31 --- /dev/null +++ b/candy-plugins/namecomplete/candy.css @@ -0,0 +1,7 @@ +#context-menu li.selected { + background-color: #ccc; +} + +#context-menu li.candy-namecomplete-option { + padding: 3px 5px; +} \ No newline at end of file diff --git a/candy-plugins/namecomplete/candy.js b/candy-plugins/namecomplete/candy.js new file mode 100644 index 0000000..7467fd5 --- /dev/null +++ b/candy-plugins/namecomplete/candy.js @@ -0,0 +1,260 @@ +/** File: candy.js + * Candy - Chats are not dead yet. + * + * Authors: + * - Troy McCabe + * - Ben Klang + * + * 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('
    • ' + matches[i] + '
    • '); + } + + // 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)); diff --git a/candy-plugins/nickchange/README.md b/candy-plugins/nickchange/README.md new file mode 100644 index 0000000..92acf15 --- /dev/null +++ b/candy-plugins/nickchange/README.md @@ -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 + + +``` + +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. \ No newline at end of file diff --git a/candy-plugins/nickchange/candy.css b/candy-plugins/nickchange/candy.css new file mode 100644 index 0000000..8cf7d7d --- /dev/null +++ b/candy-plugins/nickchange/candy.css @@ -0,0 +1,3 @@ +#nickchange-control { + background: no-repeat url('nickchange-control.png'); +} \ No newline at end of file diff --git a/candy-plugins/nickchange/candy.js b/candy-plugins/nickchange/candy.js new file mode 100644 index 0000000..3294070 --- /dev/null +++ b/candy-plugins/nickchange/candy.js @@ -0,0 +1,63 @@ +/** + * Nickchange plugin for Candy + * + * Copyright 2014 Michael Weibel + * + * 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 = '
    • '; + $('#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 = '{{_label}}' + + '
      ' + + '' + + '
      '; + + 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)); diff --git a/candy-plugins/nickchange/nickchange-control.png b/candy-plugins/nickchange/nickchange-control.png new file mode 100644 index 0000000..4e3688e Binary files /dev/null and b/candy-plugins/nickchange/nickchange-control.png differ diff --git a/candy-plugins/notifications/README.md b/candy-plugins/notifications/README.md new file mode 100644 index 0000000..5fc2f3f --- /dev/null +++ b/candy-plugins/notifications/README.md @@ -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 + +``` + +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 +}); +``` \ No newline at end of file diff --git a/candy-plugins/notifications/candy.js b/candy-plugins/notifications/candy.js new file mode 100644 index 0000000..0aec881 --- /dev/null +++ b/candy-plugins/notifications/candy.js @@ -0,0 +1,111 @@ +/* + * HTML5 Notifications + * @version 1.0 + * @author Jonatan Männchen + * @author Melissa Adamaitis + * + * 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)); diff --git a/candy-plugins/replies/README.md b/candy-plugins/replies/README.md new file mode 100644 index 0000000..68401d1 --- /dev/null +++ b/candy-plugins/replies/README.md @@ -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 + + +``` + +```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. diff --git a/candy-plugins/replies/candy.css b/candy-plugins/replies/candy.css new file mode 100644 index 0000000..0eb0bec --- /dev/null +++ b/candy-plugins/replies/candy.css @@ -0,0 +1,4 @@ +.message-pane li.mention, +.message-pane li.mention small { + background-color: #FFF7DE; +} \ No newline at end of file diff --git a/candy-plugins/replies/candy.js b/candy-plugins/replies/candy.js new file mode 100644 index 0000000..fc8b0fb --- /dev/null +++ b/candy-plugins/replies/candy.js @@ -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)); diff --git a/candy.min.js b/candy.min.js new file mode 100644 index 0000000..474fc85 --- /dev/null +++ b/candy.min.js @@ -0,0 +1,4 @@ +"use strict";var Candy=function(a,b){return a.about={name:"Candy",version:"1.7.1"},a.init=function(c,d){d.viewClass||(d.viewClass=a.View),d.viewClass.init(b("#candy"),d.view),a.Core.init(c,d.core)},a}(Candy||{},jQuery);Candy.Core=function(a,b,c){var d,e=null,f=null,g=null,h={},i=!1,j={autojoin:void 0,debug:!1,disableWindowUnload:!1,presencePriority:1,resource:Candy.about.name},k=function(a,c){b.addNamespace(a,c)},l=function(){k("PRIVATE","jabber:iq:private"),k("BOOKMARKS","storage:bookmarks"),k("PRIVACY","jabber:iq:privacy"),k("DELAY","jabber:x:delay"),k("PUBSUB","http://jabber.org/protocol/pubsub")},m=function(a){var c=b.getNodeFromJid(a),d=b.getDomainFromJid(a);return c?b.escapeNode(c)+"@"+d:d};return a.init=function(d,g){f=d,c.extend(!0,j,g),j.debug&&(void 0!==typeof window.console&&void 0!==typeof window.console.log&&(a.log=Function.prototype.bind&&Candy.Util.getIeVersion()>8?Function.prototype.bind.call(console.log,console):function(){Function.prototype.apply.call(console.log,console,arguments)}),a.log("[Init] Debugging enabled")),l(),e=new b.Connection(f),e.rawInput=a.rawInput.bind(a),e.rawOutput=a.rawOutput.bind(a),e.caps.node="https://candy-chat.github.io/candy/",j.disableWindowUnload||(window.onbeforeunload=a.onWindowUnload)},a.registerEventHandlers=function(){a.addHandler(a.Event.Jabber.Version,b.NS.VERSION,"iq"),a.addHandler(a.Event.Jabber.Presence,null,"presence"),a.addHandler(a.Event.Jabber.Message,null,"message"),a.addHandler(a.Event.Jabber.Bookmarks,b.NS.PRIVATE,"iq"),a.addHandler(a.Event.Jabber.Room.Disco,b.NS.DISCO_INFO,"iq","result"),a.addHandler(e.disco._onDiscoInfo.bind(e.disco),b.NS.DISCO_INFO,"iq","get"),a.addHandler(e.disco._onDiscoItems.bind(e.disco),b.NS.DISCO_ITEMS,"iq","get"),a.addHandler(e.caps._delegateCapabilities.bind(e.caps),b.NS.CAPS)},a.connect=function(d,f,h){e.reset(),a.registerEventHandlers(),c(Candy).triggerHandler("candy:core.before-connect",{connection:e}),i=i?!0:d&&d.indexOf("@")<0,d&&f?(e.connect(m(d)+"/"+j.resource,f,Candy.Core.Event.Strophe.Connect),g=h?new a.ChatUser(d,h):new a.ChatUser(d,b.getNodeFromJid(d))):d&&h?(e.connect(m(d)+"/"+j.resource,null,Candy.Core.Event.Strophe.Connect),g=new a.ChatUser(null,h)):d?Candy.Core.Event.Login(d):Candy.Core.Event.Login()},a.attach=function(c,d,f){g=new a.ChatUser(c,b.getNodeFromJid(c)),a.registerEventHandlers(),e.attach(c,d,f,Candy.Core.Event.Strophe.Connect)},a.disconnect=function(){e.connected&&(c.each(a.getRooms(),function(){Candy.Core.Action.Jabber.Room.Leave(this.getJid())}),e.disconnect())},a.addHandler=function(a,b,c,d,f,g,h){return e.addHandler(a,b,c,d,f,g,h)},a.getUser=function(){return g},a.setUser=function(a){g=a},a.getConnection=function(){return e},a.removeRoom=function(a){delete h[a]},a.getRooms=function(){return h},a.getStropheStatus=function(){return d},a.setStropheStatus=function(a){d=a},a.isAnonymousConnection=function(){return i},a.getOptions=function(){return j},a.getRoom=function(a){return h[a]?h[a]:null},a.onWindowUnload=function(){e.options.sync=!0,a.disconnect(),e.flush()},a.rawInput=function(a){this.log("RECV: "+a)},a.rawOutput=function(a){this.log("SENT: "+a)},a.log=function(){},a}(Candy.Core||{},Strophe,jQuery),Candy.View=function(a,b){var c={container:null,roomJid:null},d={language:"en",assets:"res/",messages:{limit:2e3,remove:500},crop:{message:{nickname:15,body:1e3},roster:{nickname:15}},enableXHTML:!1},e=function(c){b.i18n.load(a.Translation[c])},f=function(){b(Candy).on("candy:core.chat.connection",a.Observer.Chat.Connection),b(Candy).on("candy:core.chat.message",a.Observer.Chat.Message),b(Candy).on("candy:core.login",a.Observer.Login),b(Candy).on("candy:core.autojoin-missing",a.Observer.AutojoinMissing),b(Candy).on("candy:core.presence",a.Observer.Presence.update),b(Candy).on("candy:core.presence.leave",a.Observer.Presence.update),b(Candy).on("candy:core.presence.room",a.Observer.Presence.update),b(Candy).on("candy:core.presence.error",a.Observer.PresenceError),b(Candy).on("candy:core.message",a.Observer.Message)},g=function(){Candy.Util.getIeVersion()<9?b(document).focusin(Candy.View.Pane.Window.onFocus).focusout(Candy.View.Pane.Window.onBlur):b(window).focus(Candy.View.Pane.Window.onFocus).blur(Candy.View.Pane.Window.onBlur),b(window).resize(Candy.View.Pane.Chat.fitTabs)},h=function(){a.Pane.Chat.Toolbar.init()},i=function(){b("body").delegate("li[data-tooltip]","mouseenter",Candy.View.Pane.Chat.Tooltip.show)};return a.init=function(a,j){j.resources&&(j.assets=j.resources),delete j.resources,b.extend(!0,d,j),e(d.language),Candy.Util.Parser.setEmoticonPath(this.getOptions().assets+"img/emoticons/"),c.container=a,c.container.html(Mustache.to_html(Candy.View.Template.Chat.pane,{tooltipEmoticons:b.i18n._("tooltipEmoticons"),tooltipSound:b.i18n._("tooltipSound"),tooltipAutoscroll:b.i18n._("tooltipAutoscroll"),tooltipStatusmessage:b.i18n._("tooltipStatusmessage"),tooltipAdministration:b.i18n._("tooltipAdministration"),tooltipUsercount:b.i18n._("tooltipUsercount"),assetsPath:this.getOptions().assets},{tabs:Candy.View.Template.Chat.tabs,rooms:Candy.View.Template.Chat.rooms,modal:Candy.View.Template.Chat.modal,toolbar:Candy.View.Template.Chat.toolbar,soundcontrol:Candy.View.Template.Chat.soundcontrol})),g(),h(),f(),i()},a.getCurrent=function(){return c},a.getOptions=function(){return d},a}(Candy.View||{},jQuery),Candy.Util=function(a,b){a.jidToId=function(a){return MD5.hexdigest(a)},a.escapeJid=function(a){var b=Strophe.escapeNode(Strophe.getNodeFromJid(a)),c=Strophe.getDomainFromJid(a),d=Strophe.getResourceFromJid(a);return a=b+"@"+c,d&&(a+="/"+d),a},a.unescapeJid=function(a){var b=Strophe.unescapeNode(Strophe.getNodeFromJid(a)),c=Strophe.getDomainFromJid(a),d=Strophe.getResourceFromJid(a);return a=b+"@"+c,d&&(a+="/"+d),a},a.crop=function(a,b){return a.length>b&&(a=a.substr(0,b-3)+"..."),a},a.parseAndCropXhtml=function(c,d){return b("
      ").append(a.createHtml(b(c).get(0),d)).html()},a.setCookie=function(a,b,c){var d=new Date;d.setDate((new Date).getDate()+c),document.cookie=a+"="+b+";expires="+d.toUTCString()+";path=/"},a.cookieExists=function(a){return document.cookie.indexOf(a)>-1},a.getCookie=function(a){if(document.cookie){var b=new RegExp(escape(a)+"=([^;]*)","gm"),c=b.exec(document.cookie);if(c)return c[1]}},a.deleteCookie=function(a){document.cookie=a+"=;expires=Thu, 01-Jan-70 00:00:01 GMT;path=/"},a.getPosLeftAccordingToWindowBounds=function(a,c){var d=b(document).width(),e=a.outerWidth(),f=e-a.outerWidth(!0),g="left";return c+e>=d&&(c-=e-f,g="right"),{px:c,backgroundPositionAlignment:g}},a.getPosTopAccordingToWindowBounds=function(a,c){var d=b(document).height(),e=a.outerHeight(),f=e-a.outerHeight(!0),g="top";return c+e>=d&&(c-=e-f,g="bottom"),{px:c,backgroundPositionAlignment:g}},a.localizedTime=function(c){if(void 0===c)return void 0;var d=a.iso8601toDate(c);return d.format(d.toDateString()===(new Date).toDateString()?b.i18n._("timeFormat"):b.i18n._("dateFormat"))},a.iso8601toDate=function(a){var b=Date.parse(a);if(isNaN(b)){var c=/^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(a);if(c){var d=0;return"Z"!==c[8]&&(d=60*+c[10]+ +c[11],"+"===c[9]&&(d=-d)),d-=(new Date).getTimezoneOffset(),new Date(+c[1],+c[2]-1,+c[3],+c[4],+c[5]+d,+c[6],c[7]?+c[7].substr(0,3):0)}b=Date.parse(a.replace(/^(\d{4})(\d{2})(\d{2})/,"$1-$2-$3")+"Z")}return new Date(b)},a.isEmptyObject=function(a){var b;for(b in a)if(a.hasOwnProperty(b))return!1;return!0},a.forceRedraw=function(a){a.css({display:"none"}),setTimeout(function(){this.css({display:"block"})}.bind(a),1)};var c=function(){for(var a,b=3,c=document.createElement("div"),d=c.getElementsByTagName("i");c.innerHTML="",d[0];);return b>4?b:a}();return a.getIeVersion=function(){return c},a.Parser={_emoticonPath:"",setEmoticonPath:function(a){this._emoticonPath=a},emoticons:[{plain:":)",regex:/((\s):-?\)|:-?\)(\s|$))/gm,image:"Smiling.png"},{plain:";)",regex:/((\s);-?\)|;-?\)(\s|$))/gm,image:"Winking.png"},{plain:":D",regex:/((\s):-?D|:-?D(\s|$))/gm,image:"Grinning.png"},{plain:";D",regex:/((\s);-?D|;-?D(\s|$))/gm,image:"Grinning_Winking.png"},{plain:":(",regex:/((\s):-?\(|:-?\((\s|$))/gm,image:"Unhappy.png"},{plain:"^^",regex:/((\s)\^\^|\^\^(\s|$))/gm,image:"Happy_3.png"},{plain:":P",regex:/((\s):-?P|:-?P(\s|$))/gim,image:"Tongue_Out.png"},{plain:";P",regex:/((\s);-?P|;-?P(\s|$))/gim,image:"Tongue_Out_Winking.png"},{plain:":S",regex:/((\s):-?S|:-?S(\s|$))/gim,image:"Confused.png"},{plain:":/",regex:/((\s):-?\/|:-?\/(\s|$))/gm,image:"Uncertain.png"},{plain:"8)",regex:/((\s)8-?\)|8-?\)(\s|$))/gm,image:"Sunglasses.png"},{plain:"$)",regex:/((\s)\$-?\)|\$-?\)(\s|$))/gm,image:"Greedy.png"},{plain:"oO",regex:/((\s)oO|oO(\s|$))/gm,image:"Huh.png"},{plain:":x",regex:/((\s):x|:x(\s|$))/gm,image:"Lips_Sealed.png"},{plain:":666:",regex:/((\s):666:|:666:(\s|$))/gm,image:"Devil.png"},{plain:"<3",regex:/((\s)<3|<3(\s|$))/gm,image:"Heart.png"}],emotify:function(a){var b;for(b=this.emoticons.length-1;b>=0;b--)a=a.replace(this.emoticons[b].regex,'$2$1$3');return a},linkify:function(a){return a=a.replace(/(^|[^\/])(www\.[^\.]+\.[\S]+(\b|$))/gi,"$1http://$2"),a.replace(/(\b(https?|ftp|file):\/\/[\-A-Z0-9+&@#\/%?=~_|!:,.;]*[\-A-Z0-9+&@#\/%=~_|])/gi,'$1')},escape:function(a){return b("
      ").text(a).html()},nl2br:function(a){return a.replace(/\r\n|\r|\n/g,"
      ")},all:function(a){return a&&(a=this.escape(a),a=this.linkify(a),a=this.emotify(a),a=this.nl2br(a)),a}},a.createHtml=function(c,d,e){e=e||0;var f,g,h,i,j,k,l,m,n,o,p;if(c.nodeType===Strophe.ElementType.NORMAL)if(i=c.nodeName.toLowerCase(),Strophe.XHTML.validTag(i))try{for(g=b("<"+i+"/>"),f=0;f0&&(k=l.join("; "),g.attr(j,k))}else g.attr(j,k);for(f=0;fd&&(r=r.substring(0,d)),r=Candy.Util.Parser.all(r),g=b.parseHTML(r)}return g},a}(Candy.Util||{},jQuery),Candy.Core.Action=function(a,b,c){return a.Jabber={Version:function(a){Candy.Core.getConnection().sendIQ($iq({type:"result",to:Candy.Util.escapeJid(a.attr("from")),from:Candy.Util.escapeJid(a.attr("to")),id:a.attr("id")}).c("query",{name:Candy.about.name,version:Candy.about.version,os:navigator.userAgent}))},SetNickname:function(a,b){b=b instanceof Array?b:Candy.Core.getRooms();var d,e,f=Candy.Core.getConnection();c.each(b,function(b){d=Candy.Util.escapeJid(b+"/"+a),e=$pres({to:d,from:f.jid,id:"pres:"+f.getUniqueId()}),Candy.Core.getConnection().send(e)})},Roster:function(){Candy.Core.getConnection().sendIQ($iq({type:"get",xmlns:b.NS.CLIENT}).c("query",{xmlns:b.NS.ROSTER}).tree())},Presence:function(a,b){var c=Candy.Core.getConnection();a=a||{},a.id||(a.id="pres:"+c.getUniqueId());var d=$pres(a).c("priority").t(Candy.Core.getOptions().presencePriority.toString()).up().c("c",c.caps.generateCapsAttrs()).up();b&&d.node.appendChild(b.node),c.send(d.tree())},Services:function(){Candy.Core.getConnection().sendIQ($iq({type:"get",xmlns:b.NS.CLIENT}).c("query",{xmlns:b.NS.DISCO_ITEMS}).tree())},Autojoin:function(){if(Candy.Core.getOptions().autojoin===!0){Candy.Core.getConnection().sendIQ($iq({type:"get",xmlns:b.NS.CLIENT}).c("query",{xmlns:b.NS.PRIVATE}).c("storage",{xmlns:b.NS.BOOKMARKS}).tree());var d=Candy.Core.getConnection().getUniqueId("pubsub");Candy.Core.addHandler(Candy.Core.Event.Jabber.Bookmarks,b.NS.PUBSUB,"iq","result",d),Candy.Core.getConnection().sendIQ($iq({type:"get",id:d}).c("pubsub",{xmlns:b.NS.PUBSUB}).c("items",{node:b.NS.BOOKMARKS}).tree())}else c.isArray(Candy.Core.getOptions().autojoin)?c.each(Candy.Core.getOptions().autojoin,function(){a.Jabber.Room.Join.apply(null,this.valueOf().split(":",2))}):c(Candy).triggerHandler("candy:core.autojoin-missing")},ResetIgnoreList:function(){Candy.Core.getConnection().sendIQ($iq({type:"set",from:Candy.Core.getUser().getEscapedJid()}).c("query",{xmlns:b.NS.PRIVACY}).c("list",{name:"ignore"}).c("item",{action:"allow",order:"0"}).tree())},RemoveIgnoreList:function(){Candy.Core.getConnection().sendIQ($iq({type:"set",from:Candy.Core.getUser().getEscapedJid()}).c("query",{xmlns:b.NS.PRIVACY}).c("list",{name:"ignore"}).tree())},GetIgnoreList:function(){var a=$iq({type:"get",from:Candy.Core.getUser().getEscapedJid()}).c("query",{xmlns:b.NS.PRIVACY}).c("list",{name:"ignore"}).tree(),c=Candy.Core.getConnection().sendIQ(a);Candy.Core.addHandler(Candy.Core.Event.Jabber.PrivacyList,null,"iq",null,c)},SetIgnoreListActive:function(){Candy.Core.getConnection().sendIQ($iq({type:"set",from:Candy.Core.getUser().getEscapedJid()}).c("query",{xmlns:b.NS.PRIVACY}).c("active",{name:"ignore"}).tree())},GetJidIfAnonymous:function(){Candy.Core.getUser().getJid()||(Candy.Core.log("[Jabber] Anonymous login"),Candy.Core.getUser().data.jid=Candy.Core.getConnection().jid)},Room:{Join:function(c,d){a.Jabber.Room.Disco(c),c=Candy.Util.escapeJid(c);var e=Candy.Core.getConnection(),f=c+"/"+Candy.Core.getUser().getNick(),g=$pres({to:f,id:"pres:"+e.getUniqueId()}).c("x",{xmlns:b.NS.MUC});d&&g.c("password").t(d),g.up().c("c",e.caps.generateCapsAttrs()),e.send(g.tree())},Leave:function(a){var b=Candy.Core.getRoom(a).getUser();a=Candy.Util.escapeJid(a),b&&Candy.Core.getConnection().muc.leave(a,b.getNick(),function(){})},Disco:function(a){Candy.Core.getConnection().sendIQ($iq({type:"get",from:Candy.Core.getUser().getEscapedJid(),to:Candy.Util.escapeJid(a)}).c("query",{xmlns:b.NS.DISCO_INFO}).tree())},Message:function(a,d,e,f){if(d=c.trim(d),""===d)return!1;var g=null;return"chat"===e&&(g=b.getResourceFromJid(a),a=b.getBareJidFromJid(a)),Candy.Core.getConnection().muc.message(a,g,d,f,e),!0},Invite:function(a,d,e,f){e=c.trim(e);var g=$msg({to:a}),h=g.c("x",{xmlns:b.NS.MUC_USER});c.each(d,function(a,c){c=b.getBareJidFromJid(c),h.c("invite",{to:c}),"undefined"!=typeof e&&""!==e&&h.c("reason",e)}),"undefined"!=typeof f&&""!==f&&h.c("password",f),Candy.Core.getConnection().send(g)},IgnoreUnignore:function(a){Candy.Core.getUser().addToOrRemoveFromPrivacyList("ignore",a),Candy.Core.Action.Jabber.Room.UpdatePrivacyList()},UpdatePrivacyList:function(){var a=Candy.Core.getUser(),b=$iq({type:"set",from:a.getEscapedJid()}).c("query",{xmlns:"jabber:iq:privacy"}).c("list",{name:"ignore"}),d=a.getPrivacyList("ignore");d.length>0?c.each(d,function(a,c){b.c("item",{type:"jid",value:Candy.Util.escapeJid(c),action:"deny",order:a}).c("message").up().up()}):b.c("item",{action:"allow",order:"0"}),Candy.Core.getConnection().sendIQ(b.tree())},Admin:{UserAction:function(a,c,d,e){a=Candy.Util.escapeJid(a),c=Candy.Util.escapeJid(c);var f={nick:b.getResourceFromJid(c)};switch(d){case"kick":f.role="none";break;case"ban":f.affiliation="outcast";break;default:return!1}return Candy.Core.getConnection().sendIQ($iq({type:"set",from:Candy.Core.getUser().getEscapedJid(),to:a}).c("query",{xmlns:b.NS.MUC_ADMIN}).c("item",f).c("reason").t(e).tree()),!0},SetSubject:function(a,b){Candy.Core.getConnection().muc.setTopic(Candy.Util.escapeJid(a),b)}}}},a}(Candy.Core.Action||{},Strophe,jQuery),Candy.Core.ChatRoom=function(a){this.room={jid:a,name:Strophe.getNodeFromJid(a)},this.user=null,this.roster=new Candy.Core.ChatRoster,this.setUser=function(a){this.user=a},this.getUser=function(){return this.user},this.getJid=function(){return this.room.jid},this.setName=function(a){this.room.name=a},this.getName=function(){return this.room.name},this.setRoster=function(a){this.roster=a},this.getRoster=function(){return this.roster}},Candy.Core.ChatRoster=function(){this.items={},this.add=function(a){this.items[a.getJid()]=a},this.remove=function(a){delete this.items[a]},this.get=function(a){return this.items[a]},this.getAll=function(){return this.items}},Candy.Core.ChatUser=function(a,b,c,d){this.ROLE_MODERATOR="moderator",this.AFFILIATION_OWNER="owner",this.data={jid:a,nick:Strophe.unescapeNode(b),affiliation:c,role:d,privacyLists:{},customData:{},previousNick:void 0},this.getJid=function(){return this.data.jid?Candy.Util.unescapeJid(this.data.jid):void 0},this.getEscapedJid=function(){return Candy.Util.escapeJid(this.data.jid)},this.setJid=function(a){this.data.jid=a},this.getNick=function(){return Strophe.unescapeNode(this.data.nick)},this.setNick=function(a){this.data.nick=a},this.getRole=function(){return this.data.role},this.setRole=function(a){this.data.role=a},this.setAffiliation=function(a){this.data.affiliation=a},this.getAffiliation=function(){return this.data.affiliation},this.isModerator=function(){return this.getRole()===this.ROLE_MODERATOR||this.getAffiliation()===this.AFFILIATION_OWNER},this.addToOrRemoveFromPrivacyList=function(a,b){this.data.privacyLists[a]||(this.data.privacyLists[a]=[]);var c=-1;return-1!==(c=this.data.privacyLists[a].indexOf(b))?this.data.privacyLists[a].splice(c,1):this.data.privacyLists[a].push(b),this.data.privacyLists[a]},this.getPrivacyList=function(a){return this.data.privacyLists[a]||(this.data.privacyLists[a]=[]),this.data.privacyLists[a]},this.setPrivacyLists=function(a){this.data.privacyLists=a},this.isInPrivacyList=function(a,b){return this.data.privacyLists[a]?-1!==this.data.privacyLists[a].indexOf(b):!1},this.setCustomData=function(a){this.data.customData=a},this.getCustomData=function(){return this.data.customData},this.setPreviousNick=function(a){this.data.previousNick=a},this.getPreviousNick=function(){return this.data.previousNick}},Candy.Core.Event=function(a,b,c){return a.Login=function(a){c(Candy).triggerHandler("candy:core.login",{presetJid:a})},a.Strophe={Connect:function(a){switch(Candy.Core.setStropheStatus(a),a){case b.Status.CONNECTED:Candy.Core.log("[Connection] Connected"),Candy.Core.Action.Jabber.GetJidIfAnonymous();case b.Status.ATTACHED:Candy.Core.log("[Connection] Attached"),Candy.Core.Action.Jabber.Presence(),Candy.Core.Action.Jabber.Autojoin(),Candy.Core.Action.Jabber.GetIgnoreList();break;case b.Status.DISCONNECTED:Candy.Core.log("[Connection] Disconnected");break;case b.Status.AUTHFAIL:Candy.Core.log("[Connection] Authentication failed");break;case b.Status.CONNECTING:Candy.Core.log("[Connection] Connecting");break;case b.Status.DISCONNECTING:Candy.Core.log("[Connection] Disconnecting");break;case b.Status.AUTHENTICATING:Candy.Core.log("[Connection] Authenticating");break;case b.Status.ERROR:case b.Status.CONNFAIL:Candy.Core.log("[Connection] Failed ("+a+")");break;default:Candy.Core.log("[Connection] What?!")}c(Candy).triggerHandler("candy:core.chat.connection",{status:a})}},a.Jabber={Version:function(a){return Candy.Core.log("[Jabber] Version"),Candy.Core.Action.Jabber.Version(c(a)),!0},Presence:function(d){return Candy.Core.log("[Jabber] Presence"),d=c(d),d.children('x[xmlns^="'+b.NS.MUC+'"]').length>0?"error"===d.attr("type")?a.Jabber.Room.PresenceError(d):a.Jabber.Room.Presence(d):c(Candy).triggerHandler("candy:core.presence",{from:d.attr("from"),stanza:d}),!0},Bookmarks:function(a){return Candy.Core.log("[Jabber] Bookmarks"),c("conference",a).each(function(){var a=c(this);a.attr("autojoin")&&Candy.Core.Action.Jabber.Room.Join(a.attr("jid"))}),!0},PrivacyList:function(b){Candy.Core.log("[Jabber] PrivacyList");var d=Candy.Core.getUser();return b=c(b),"result"===b.attr("type")?(c('list[name="ignore"] item',b).each(function(){var a=c(this);"deny"===a.attr("action")&&d.addToOrRemoveFromPrivacyList("ignore",a.attr("value"))}),Candy.Core.Action.Jabber.SetIgnoreListActive(),!1):a.Jabber.PrivacyListError(b)},PrivacyListError:function(a){return Candy.Core.log("[Jabber] PrivacyListError"),c('error[code="404"][type="cancel"] item-not-found',a)&&(Candy.Core.Action.Jabber.ResetIgnoreList(),Candy.Core.Action.Jabber.SetIgnoreListActive()),!1},Message:function(d){Candy.Core.log("[Jabber] Message"),d=c(d);var e=d.attr("from"),f=d.attr("type")||"undefined",g=d.attr("to");if("normal"===f||"undefined"===f){var h=d.find("invite"),i=d.find('x[xmlns="jabber:x:conference"]');if(h.length>0){var j=d.find("password"),k=null,l=h.find("continue"),m=null;j&&(k=j.text()),l&&(m=l.attr("thread")),c(Candy).triggerHandler("candy:core:chat:invite",{roomJid:e,from:h.attr("from")||"undefined",reason:h.find("reason").html()||"",password:k,continuedThread:m})}return i.length>0&&c(Candy).triggerHandler("candy:core:chat:invite",{roomJid:i.attr("jid"),from:e,reason:i.attr("reason")||"",password:i.attr("password"),continuedThread:i.attr("thread")}),c(Candy).triggerHandler("candy:core:chat:message:normal",{type:f||"normal",message:d}),!0}return"groupchat"!==f&&"chat"!==f&&"error"!==f&&"headline"!==f?(c(Candy).triggerHandler("candy:core:chat:message:other",{type:f,message:d}),!0):(e===b.getDomainFromJid(e)||"groupchat"!==f&&"chat"!==f&&"error"!==f?g||e!==b.getDomainFromJid(e)?g&&e===b.getDomainFromJid(e)&&c(Candy).triggerHandler("candy:core.chat.message.server",{type:f||"message",subject:d.children("subject").text(),message:d.children("body").text()}):c(Candy).triggerHandler("candy:core.chat.message.admin",{type:f||"message",message:d.children("body").text()}):a.Jabber.Room.Message(d),!0)},Room:{Leave:function(a){Candy.Core.log("[Jabber:Room] Leave"),a=c(a);var d=Candy.Util.unescapeJid(a.attr("from")),e=b.getBareJidFromJid(d);if(!Candy.Core.getRoom(e))return!0;var f,g,h=Candy.Core.getRoom(e).getName(),i=a.find("item"),j="leave";if(delete Candy.Core.getRooms()[e],"none"===i.attr("role")){var k=a.find("status").attr("code");"307"===k?j="kick":"301"===k&&(j="ban"),f=i.find("reason").text(),g=i.find("actor").attr("jid")}var l=new Candy.Core.ChatUser(d,b.getResourceFromJid(d),i.attr("affiliation"),i.attr("role"));return c(Candy).triggerHandler("candy:core.presence.leave",{roomJid:e,roomName:h,type:j,reason:f,actor:g,user:l}),!0},Disco:function(a){if(Candy.Core.log("[Jabber:Room] Disco"),a=c(a),!a.find('identity[category="conference"]').length)return!0;var d=b.getBareJidFromJid(Candy.Util.unescapeJid(a.attr("from")));Candy.Core.getRooms()[d]||(Candy.Core.getRooms()[d]=new Candy.Core.ChatRoom(d));var e=a.find("identity");if(e.length){var f=e.attr("name"),g=Candy.Core.getRoom(d);null===g.getName()&&g.setName(b.unescapeNode(f))}return!0},Presence:function(d){Candy.Core.log("[Jabber:Room] Presence");var e=Candy.Util.unescapeJid(d.attr("from")),f=b.getBareJidFromJid(e),g=d.attr("type"),h=d.find("status"),i=!1,j=!1;if(h.length)for(var k=0,l=h.length;l>k;k++){var m=c(h[k]),n=m.attr("code");"303"===n?j=!0:"210"===n&&(i=!0)}var o=Candy.Core.getRoom(f);o||(Candy.Core.getRooms()[f]=new Candy.Core.ChatRoom(f),o=Candy.Core.getRoom(f));var p=o.getUser()?o.getUser():Candy.Core.getUser();if(b.getResourceFromJid(e)===p.getNick()&&"unavailable"===g&&j===!1)return a.Jabber.Room.Leave(d),!0;var q,r,s,t=o.getRoster(),u=d.find("item");if("unavailable"!==g)if(t.get(e)){r=t.get(e);var v=u.attr("role"),w=u.attr("affiliation");r.setRole(v),r.setAffiliation(w),q="join"}else s=b.getResourceFromJid(e),r=new Candy.Core.ChatUser(e,s,u.attr("affiliation"),u.attr("role")),null!==o.getUser()||Candy.Core.getUser().getNick()!==s&&!i||(o.setUser(r),p=r),t.add(r),q="join";else r=t.get(e),t.remove(e),j?(s=u.attr("nick"),q="nickchange",r.setPreviousNick(r.getNick()),r.setNick(s),r.setJid(b.getBareJidFromJid(e)+"/"+s),t.add(r)):(q="leave","none"===u.attr("role")&&("307"===d.find("status").attr("code")?q="kick":"301"===d.find("status").attr("code")&&(q="ban")));return c(Candy).triggerHandler("candy:core.presence.room",{roomJid:f,roomName:o.getName(),user:r,action:q,currentUser:p}),!0},PresenceError:function(a){Candy.Core.log("[Jabber:Room] Presence Error");var d=Candy.Util.unescapeJid(a.attr("from")),e=b.getBareJidFromJid(d),f=Candy.Core.getRooms()[e],g=f.getName();return Candy.Core.removeRoom(e),f=void 0,c(Candy).triggerHandler("candy:core.presence.error",{msg:a,type:a.children("error").children()[0].tagName.toLowerCase(),roomJid:e,roomName:g}),!0},Message:function(a){Candy.Core.log("[Jabber:Room] Message");var d,e,f;if(a.children("subject").length>0&&a.children("subject").text().length>0&&"groupchat"===a.attr("type"))d=Candy.Util.unescapeJid(b.getBareJidFromJid(a.attr("from"))),e={name:b.getNodeFromJid(d),body:a.children("subject").text(),type:"subject"};else if("error"===a.attr("type")){var g=a.children("error");g.children("text").length>0&&(d=a.attr("from"),e={type:"info",body:g.children("text").text()})}else{if(!(a.children("body").length>0)){if(a.children("composing").length>0||a.children("inactive").length>0||a.children("paused").length>0){d=Candy.Util.unescapeJid(a.attr("from")),f=b.getResourceFromJid(d);var h;return a.children("composing").length>0?h="composing":a.children("paused").length>0?h="paused":a.children("inactive").length>0?h="inactive":a.children("gone").length>0&&(h="gone"),c(Candy).triggerHandler("candy:core.message.chatstate",{name:f,roomJid:d,chatstate:h}),!0}return!0}if("chat"===a.attr("type")||"normal"===a.attr("type")){d=Candy.Util.unescapeJid(a.attr("from"));var i=b.getBareJidFromJid(d),j=!Candy.Core.getRoom(i);f=j?b.getNodeFromJid(d):b.getResourceFromJid(d),e={name:f,body:a.children("body").text(),type:a.attr("type"),isNoConferenceRoomJid:j}}else{d=Candy.Util.unescapeJid(b.getBareJidFromJid(a.attr("from")));var k=b.getResourceFromJid(a.attr("from"));if(k)k=b.unescapeNode(k),e={name:k,body:a.children("body").text(),type:a.attr("type")};else{if(!Candy.View.Pane.Chat.rooms[a.attr("from")])return!0;e={name:"",body:a.children("body").text(),type:"info"}}}var l=a.children('html[xmlns="'+b.NS.XHTML_IM+'"]');if(Candy.View.getOptions().enableXHTML===!0&&l.length>0){var m=l.children('body[xmlns="'+b.NS.XHTML+'"]').first().html();e.xhtmlMessage=m}}var n=a.children(a.children("delay")?"delay":'x[xmlns="'+b.NS.DELAY+'"]'),o=void 0!==n?n.attr("stamp"):null;return c(Candy).triggerHandler("candy:core.message",{roomJid:d,message:e,timestamp:o}),!0}}},a}(Candy.Core.Event||{},Strophe,jQuery),Candy.View.Observer=function(a,b){var c=!0;return a.Chat={Connection:function(a,d){var e="candy:view.connection.status-"+d.status;if(b(Candy).triggerHandler(e)===!1)return!1;switch(d.status){case Strophe.Status.CONNECTING:case Strophe.Status.AUTHENTICATING:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusConnecting"),!1,!0);break;case Strophe.Status.ATTACHED:case Strophe.Status.CONNECTED:c===!0&&(Candy.View.Pane.Chat.Modal.show(b.i18n._("statusConnected")),Candy.View.Pane.Chat.Modal.hide());break;case Strophe.Status.DISCONNECTING:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusDisconnecting"),!1,!0);break;case Strophe.Status.DISCONNECTED:var f=Candy.Core.isAnonymousConnection()?Strophe.getDomainFromJid(Candy.Core.getUser().getJid()):null;Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("statusDisconnected"),f);break;case Strophe.Status.AUTHFAIL:Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("statusAuthfail"));break;default:Candy.View.Pane.Chat.Modal.show(b.i18n._("status",d.status))}},Message:function(a,b){"message"===b.type?Candy.View.Pane.Chat.adminMessage(b.subject||"",b.message):("chat"===b.type||"groupchat"===b.type)&&Candy.View.Pane.Chat.onInfoMessage(Candy.View.getCurrent().roomJid,b.subject||"",b.message)}},a.Presence={update:function(c,d){if("leave"===d.type){var e=Candy.View.Pane.Room.getUser(d.roomJid);Candy.View.Pane.Room.close(d.roomJid),a.Presence.notifyPrivateChats(e,d.type)}else if("kick"===d.type||"ban"===d.type){var f,g=d.actor?Strophe.getNodeFromJid(d.actor):null,h=[d.roomName];switch(g&&h.push(g),d.type){case"kick":f=b.i18n._(g?"youHaveBeenKickedBy":"youHaveBeenKicked",h);break;case"ban":f=b.i18n._(g?"youHaveBeenBannedBy":"youHaveBeenBanned",h)}Candy.View.Pane.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.adminMessageReason,{reason:d.reason,_action:f,_reason:b.i18n._("reasonWas",[d.reason])})),setTimeout(function(){Candy.View.Pane.Chat.Modal.hide(function(){Candy.View.Pane.Room.close(d.roomJid),a.Presence.notifyPrivateChats(d.user,d.type)})},5e3);var i={type:d.type,reason:d.reason,roomJid:d.roomJid,user:d.user};b(Candy).triggerHandler("candy:view.presence",[i])}else if(d.roomJid){if(d.roomJid=Candy.Util.unescapeJid(d.roomJid),!Candy.View.Pane.Chat.rooms[d.roomJid]){if(Candy.View.Pane.Room.init(d.roomJid,d.roomName)===!1)return!1;Candy.View.Pane.Room.show(d.roomJid)}Candy.View.Pane.Roster.update(d.roomJid,d.user,d.action,d.currentUser),Candy.View.Pane.Chat.rooms[d.user.getJid()]&&"nickchange"!==d.action&&(Candy.View.Pane.Roster.update(d.user.getJid(),d.user,d.action,d.currentUser),Candy.View.Pane.PrivateRoom.setStatus(d.user.getJid(),d.action))}},notifyPrivateChats:function(a,b){Candy.Core.log("[View:Observer] notify Private Chats");var c;for(c in Candy.View.Pane.Chat.rooms)Candy.View.Pane.Chat.rooms.hasOwnProperty(c)&&Candy.View.Pane.Room.getUser(c)&&a.getJid()===Candy.View.Pane.Room.getUser(c).getJid()&&(Candy.View.Pane.Roster.update(c,a,b,a),Candy.View.Pane.PrivateRoom.setStatus(c,b))}},a.PresenceError=function(a,c){switch(c.type){case"not-authorized":var d;c.msg.children("x").children("password").length>0&&(d=b.i18n._("passwordEnteredInvalid",[c.roomName])),Candy.View.Pane.Chat.Modal.showEnterPasswordForm(c.roomJid,c.roomName,d);break;case"conflict":Candy.View.Pane.Chat.Modal.showNicknameConflictForm(c.roomJid);break;case"registration-required":Candy.View.Pane.Chat.Modal.showError("errorMembersOnly",[c.roomName]);break;case"service-unavailable":Candy.View.Pane.Chat.Modal.showError("errorMaxOccupantsReached",[c.roomName])}},a.Message=function(a,b){"subject"===b.message.type?(Candy.View.Pane.Chat.rooms[b.roomJid]||(Candy.View.Pane.Room.init(b.roomJid,b.message.name),Candy.View.Pane.Room.show(b.roomJid)),Candy.View.Pane.Room.setSubject(b.roomJid,b.message.body)):"info"===b.message.type?Candy.View.Pane.Chat.infoMessage(b.roomJid,b.message.body):("chat"!==b.message.type||Candy.View.Pane.Chat.rooms[b.roomJid]||Candy.View.Pane.PrivateRoom.open(b.roomJid,b.message.name,!1,b.message.isNoConferenceRoomJid),Candy.View.Pane.Message.show(b.roomJid,b.message.name,b.message.body,b.message.xhtmlMessage,b.timestamp))},a.Login=function(a,b){Candy.View.Pane.Chat.Modal.showLoginForm(null,b.presetJid)},a.AutojoinMissing=function(){c=!1,Candy.View.Pane.Chat.Modal.showError("errorAutojoinMissing")},a}(Candy.View.Observer||{},jQuery),Candy.View.Pane=function(a,b){return a.Window={_hasFocus:!0,_plainTitle:document.title,_unreadMessagesCount:0,autoscroll:!0,hasFocus:function(){return a.Window._hasFocus},increaseUnreadMessages:function(){a.Window.renderUnreadMessages(++a.Window._unreadMessagesCount)},reduceUnreadMessages:function(b){a.Window._unreadMessagesCount-=b,a.Window._unreadMessagesCount<=0?a.Window.clearUnreadMessages():a.Window.renderUnreadMessages(a.Window._unreadMessagesCount)},clearUnreadMessages:function(){a.Window._unreadMessagesCount=0,document.title=a.Window._plainTitle},renderUnreadMessages:function(b){document.title=Candy.View.Template.Window.unreadmessages.replace("{{count}}",b).replace("{{title}}",a.Window._plainTitle)},onFocus:function(){a.Window._hasFocus=!0,Candy.View.getCurrent().roomJid&&(a.Room.setFocusToForm(Candy.View.getCurrent().roomJid),a.Chat.clearUnreadMessages(Candy.View.getCurrent().roomJid)) +},onBlur:function(){a.Window._hasFocus=!1}},a.Chat={rooms:[],addTab:function(c,d,e){var f=Candy.Util.jidToId(c),g=Mustache.to_html(Candy.View.Template.Chat.tab,{roomJid:c,roomId:f,name:d||Strophe.getNodeFromJid(c),privateUserChat:function(){return"chat"===e},roomType:e}),h=b(g).appendTo("#chat-tabs");h.click(a.Chat.tabClick),b("a.close",h).click(a.Chat.tabClose),a.Chat.fitTabs()},getTab:function(a){return b("#chat-tabs").children('li[data-roomjid="'+a+'"]')},removeTab:function(b){a.Chat.getTab(b).remove(),a.Chat.fitTabs()},setActiveTab:function(a){b("#chat-tabs").children().each(function(){var c=b(this);c.attr("data-roomjid")===a?c.addClass("active"):c.removeClass("active")})},increaseUnreadMessages:function(b){var c=this.getTab(b).find(".unread");c.show().text(""!==c.text()?parseInt(c.text(),10)+1:1),"chat"===a.Chat.rooms[b].type&&a.Window.increaseUnreadMessages()},clearUnreadMessages:function(b){var c=a.Chat.getTab(b).find(".unread");a.Window.reduceUnreadMessages(c.text()),c.hide().text("")},tabClick:function(c){var d=Candy.View.getCurrent().roomJid;a.Chat.rooms[d].scrollPosition=a.Room.getPane(d,".message-pane-wrapper").scrollTop(),a.Room.show(b(this).attr("data-roomjid")),c.preventDefault()},tabClose:function(){var c=b(this).parent().attr("data-roomjid");return"chat"===a.Chat.rooms[c].type?a.Room.close(c):Candy.Core.Action.Jabber.Room.Leave(c),!1},allTabsClosed:function(){Candy.Core.disconnect(),a.Chat.Toolbar.hide()},fitTabs:function(){var a=b("#chat-tabs").innerWidth(),c=0,d=b("#chat-tabs").children();if(d.each(function(){c+=b(this).css({width:"auto",overflow:"visible"}).outerWidth(!0)}),c>a){var e=d.outerWidth(!0)-d.width(),f=Math.floor(a/d.length)-e;d.css({width:f,overflow:"hidden"})}},adminMessage:function(c,d){if(Candy.View.getCurrent().roomJid){var e=Mustache.to_html(Candy.View.Template.Chat.adminMessage,{subject:c,message:d,sender:b.i18n._("administratorMessageSubject"),time:Candy.Util.localizedTime((new Date).toGMTString())});b("#chat-rooms").children().each(function(){a.Room.appendToMessagePane(b(this).attr("data-roomjid"),e)}),a.Room.scrollToBottom(Candy.View.getCurrent().roomJid),b(Candy).triggerHandler("candy:view.chat.admin-message",{subject:c,message:d})}},infoMessage:function(b,c,d){a.Chat.onInfoMessage(b,c,d)},onInfoMessage:function(c,d,e){if(Candy.View.getCurrent().roomJid){var f=Mustache.to_html(Candy.View.Template.Chat.infoMessage,{subject:d,message:b.i18n._(e),time:Candy.Util.localizedTime((new Date).toGMTString())});a.Room.appendToMessagePane(c,f),Candy.View.getCurrent().roomJid===c&&a.Room.scrollToBottom(Candy.View.getCurrent().roomJid)}},Toolbar:{_supportsNativeAudio:!1,init:function(){b("#emoticons-icon").click(function(b){a.Chat.Context.showEmoticonsMenu(b.currentTarget),b.stopPropagation()}),b("#chat-autoscroll-control").click(a.Chat.Toolbar.onAutoscrollControlClick);var c=document.createElement("audio");a.Chat.Toolbar._supportsNativeAudio=!(!c.canPlayType||!c.canPlayType("audio/mpeg;").replace(/no/,"")),b("#chat-sound-control").click(a.Chat.Toolbar.onSoundControlClick),Candy.Util.cookieExists("candy-nosound")&&b("#chat-sound-control").click(),b("#chat-statusmessage-control").click(a.Chat.Toolbar.onStatusMessageControlClick),Candy.Util.cookieExists("candy-nostatusmessages")&&b("#chat-statusmessage-control").click()},show:function(){b("#chat-toolbar").show()},hide:function(){b("#chat-toolbar").hide()},update:function(c){var d=b("#chat-toolbar").find(".context"),e=a.Room.getUser(c);e&&e.isModerator()?d.show().click(function(b){a.Chat.Context.show(b.currentTarget,c),b.stopPropagation()}):d.hide(),a.Chat.Toolbar.updateUsercount(a.Chat.rooms[c].usercount)},playSound:function(){a.Chat.Toolbar.onPlaySound()},onPlaySound:function(){try{if(a.Chat.Toolbar._supportsNativeAudio)new Audio(Candy.View.getOptions().assets+"notify.mp3").play();else{var b=document.getElementById("chat-sound-player");b.SetVariable("method:stop",""),b.SetVariable("method:play","")}}catch(c){}},onSoundControlClick:function(){var c=b("#chat-sound-control");c.hasClass("checked")?(a.Chat.Toolbar.playSound=function(){},Candy.Util.setCookie("candy-nosound","1",365)):(a.Chat.Toolbar.playSound=function(){a.Chat.Toolbar.onPlaySound()},Candy.Util.deleteCookie("candy-nosound")),c.toggleClass("checked")},onAutoscrollControlClick:function(){var c=b("#chat-autoscroll-control");c.hasClass("checked")?(a.Room.scrollToBottom=function(b){a.Room.onScrollToStoredPosition(b)},a.Window.autoscroll=!1):(a.Room.scrollToBottom=function(b){a.Room.onScrollToBottom(b)},a.Room.scrollToBottom(Candy.View.getCurrent().roomJid),a.Window.autoscroll=!0),c.toggleClass("checked")},onStatusMessageControlClick:function(){var c=b("#chat-statusmessage-control");c.hasClass("checked")?(a.Chat.infoMessage=function(){},Candy.Util.setCookie("candy-nostatusmessages","1",365)):(a.Chat.infoMessage=function(b,c,d){a.Chat.onInfoMessage(b,c,d)},Candy.Util.deleteCookie("candy-nostatusmessages")),c.toggleClass("checked")},updateUsercount:function(a){b("#chat-usercount").text(a)}},Modal:{show:function(c,d,e){d?a.Chat.Modal.showCloseControl():a.Chat.Modal.hideCloseControl(),e?a.Chat.Modal.showSpinner():a.Chat.Modal.hideSpinner(),b("#chat-modal").stop(!1,!0),b("#chat-modal-body").html(c),b("#chat-modal").fadeIn("fast"),b("#chat-modal-overlay").show()},hide:function(a){b("#chat-modal").fadeOut("fast",function(){b("#chat-modal-body").text(""),b("#chat-modal-overlay").hide()}),b(document).keydown(function(a){27===a.which&&a.preventDefault()}),a&&a()},showSpinner:function(){b("#chat-modal-spinner").show()},hideSpinner:function(){b("#chat-modal-spinner").hide()},showCloseControl:function(){b("#admin-message-cancel").show().click(function(b){a.Chat.Modal.hide(),b.preventDefault()}),b(document).keydown(function(b){27===b.which&&(a.Chat.Modal.hide(),b.preventDefault())})},hideCloseControl:function(){b("#admin-message-cancel").hide().click(function(){})},showLoginForm:function(c,d){a.Chat.Modal.show((c?c:"")+Mustache.to_html(Candy.View.Template.Login.form,{_labelNickname:b.i18n._("labelNickname"),_labelUsername:b.i18n._("labelUsername"),_labelPassword:b.i18n._("labelPassword"),_loginSubmit:b.i18n._("loginSubmit"),displayPassword:!Candy.Core.isAnonymousConnection(),displayUsername:!d,displayNickname:Candy.Core.isAnonymousConnection(),presetJid:d?d:!1})),b("#login-form").children(":input:first").focus(),b("#login-form").submit(function(){var a=b("#username").val(),c=b("#password").val();if(Candy.Core.isAnonymousConnection())Candy.Core.connect(d,null,a);else{var e=Candy.Core.getUser()&&a.indexOf("@")<0?a+"@"+Strophe.getDomainFromJid(Candy.Core.getUser().getJid()):a;e.indexOf("@")<0&&!Candy.Core.getUser()?Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("loginInvalid")):Candy.Core.connect(e,c)}return!1})},showEnterPasswordForm:function(c,d,e){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.PresenceError.enterPasswordForm,{roomName:d,_labelPassword:b.i18n._("labelPassword"),_label:e?e:b.i18n._("enterRoomPassword",[d]),_joinSubmit:b.i18n._("enterRoomPasswordSubmit")}),!0),b("#password").focus(),b("#enter-password-form").submit(function(){var d=b("#password").val();return a.Chat.Modal.hide(function(){Candy.Core.Action.Jabber.Room.Join(c,d)}),!1})},showNicknameConflictForm:function(c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.PresenceError.nicknameConflictForm,{_labelNickname:b.i18n._("labelNickname"),_label:b.i18n._("nicknameConflict"),_loginSubmit:b.i18n._("loginSubmit")})),b("#nickname").focus(),b("#nickname-conflict-form").submit(function(){var d=b("#nickname").val();return a.Chat.Modal.hide(function(){Candy.Core.getUser().data.nick=d,Candy.Core.Action.Jabber.Room.Join(c)}),!1})},showError:function(c,d){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.PresenceError.displayError,{_error:b.i18n._(c,d)}),!0)}},Tooltip:{show:function(a,c){var d=b("#tooltip"),e=b(a.currentTarget);if(c||(c=e.attr("data-tooltip")),0===d.length){var f=Mustache.to_html(Candy.View.Template.Chat.tooltip);b("#chat-pane").append(f),d=b("#tooltip")}b("#context-menu").hide(),d.stop(!1,!0),d.children("div").html(c);var g=e.offset(),h=Candy.Util.getPosLeftAccordingToWindowBounds(d,g.left),i=Candy.Util.getPosTopAccordingToWindowBounds(d,g.top);d.css({left:h.px,top:i.px}).removeClass("left-top left-bottom right-top right-bottom").addClass(h.backgroundPositionAlignment+"-"+i.backgroundPositionAlignment).fadeIn("fast"),e.mouseleave(function(a){a.stopPropagation(),b("#tooltip").stop(!1,!0).fadeOut("fast",function(){b(this).css({top:0,left:0})})})}},Context:{init:function(){if(0===b("#context-menu").length){var a=Mustache.to_html(Candy.View.Template.Chat.Context.menu);b("#chat-pane").append(a),b("#context-menu").mouseleave(function(){b(this).fadeOut("fast")})}},show:function(c,d,e){c=b(c);var f=a.Chat.rooms[d].id,g=b("#context-menu"),h=b("ul li",g);b("#tooltip").hide(),e||(e=Candy.Core.getUser()),h.remove();var i,j=this.getMenuLinks(d,e,c),k=function(a,c){return function(d){d.data.callback(d,a,c),b("#context-menu").hide()}};for(i in j)if(j.hasOwnProperty(i)){var l=j[i],m=Mustache.to_html(Candy.View.Template.Chat.Context.menulinks,{roomId:f,"class":l["class"],id:i,label:l.label});b("ul",g).append(m),b("#context-menu-"+i).bind("click",l,k(d,e))}if(i){var n=c.offset(),o=Candy.Util.getPosLeftAccordingToWindowBounds(g,n.left),p=Candy.Util.getPosTopAccordingToWindowBounds(g,n.top);return g.css({left:o.px,top:p.px}).removeClass("left-top left-bottom right-top right-bottom").addClass(o.backgroundPositionAlignment+"-"+p.backgroundPositionAlignment).fadeIn("fast"),b(Candy).triggerHandler("candy:view.roster.after-context-menu",{roomJid:d,user:e,element:g}),!0}},getMenuLinks:function(c,d,e){var f,g,h={roomJid:c,user:d,elem:e,menulinks:this.initialMenuLinks(e)};b(Candy).triggerHandler("candy:view.roster.context-menu",h),f=h.menulinks;for(g in f)f.hasOwnProperty(g)&&void 0!==f[g].requiredPermission&&!f[g].requiredPermission(d,a.Room.getUser(c),e)&&delete f[g];return f},initialMenuLinks:function(){return{"private":{requiredPermission:function(a,b){return b.getNick()!==a.getNick()&&Candy.Core.getRoom(Candy.View.getCurrent().roomJid)&&!Candy.Core.getUser().isInPrivacyList("ignore",a.getJid())},"class":"private",label:b.i18n._("privateActionLabel"),callback:function(a,c,d){b("#user-"+Candy.Util.jidToId(c)+"-"+Candy.Util.jidToId(d.getJid())).click()}},ignore:{requiredPermission:function(a,b){return b.getNick()!==a.getNick()&&!Candy.Core.getUser().isInPrivacyList("ignore",a.getJid())},"class":"ignore",label:b.i18n._("ignoreActionLabel"),callback:function(a,b,c){Candy.View.Pane.Room.ignoreUser(b,c.getJid())}},unignore:{requiredPermission:function(a,b){return b.getNick()!==a.getNick()&&Candy.Core.getUser().isInPrivacyList("ignore",a.getJid())},"class":"unignore",label:b.i18n._("unignoreActionLabel"),callback:function(a,b,c){Candy.View.Pane.Room.unignoreUser(b,c.getJid())}},kick:{requiredPermission:function(a,b){return b.getNick()!==a.getNick()&&b.isModerator()&&!a.isModerator()},"class":"kick",label:b.i18n._("kickActionLabel"),callback:function(c,d,e){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("reason"),_submit:b.i18n._("kickActionLabel")}),!0),b("#context-modal-field").focus(),b("#context-modal-form").submit(function(){return Candy.Core.Action.Jabber.Room.Admin.UserAction(d,e.getJid(),"kick",b("#context-modal-field").val()),a.Chat.Modal.hide(),!1})}},ban:{requiredPermission:function(a,b){return b.getNick()!==a.getNick()&&b.isModerator()&&!a.isModerator()},"class":"ban",label:b.i18n._("banActionLabel"),callback:function(c,d,e){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("reason"),_submit:b.i18n._("banActionLabel")}),!0),b("#context-modal-field").focus(),b("#context-modal-form").submit(function(){return Candy.Core.Action.Jabber.Room.Admin.UserAction(d,e.getJid(),"ban",b("#context-modal-field").val()),a.Chat.Modal.hide(),!1})}},subject:{requiredPermission:function(a,b){return b.getNick()===a.getNick()&&b.isModerator()},"class":"subject",label:b.i18n._("setSubjectActionLabel"),callback:function(c,d){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("subject"),_submit:b.i18n._("setSubjectActionLabel")}),!0),b("#context-modal-field").focus(),b("#context-modal-form").submit(function(c){Candy.Core.Action.Jabber.Room.Admin.SetSubject(d,b("#context-modal-field").val()),a.Chat.Modal.hide(),c.preventDefault()})}}}},showEmoticonsMenu:function(a){a=b(a);var c,d=a.offset(),e=b("#context-menu"),f=b("ul",e),g="";for(b("#tooltip").hide(),c=Candy.Util.Parser.emoticons.length-1;c>=0;c--)g=''+Candy.Util.Parser.emoticons[c].plain+''+g;f.html('
    • '+g+"
    • "),f.find("img").click(function(){var a=Candy.View.Pane.Room.getPane(Candy.View.getCurrent().roomJid,".message-form").children(".field"),c=a.val(),d=b(this).attr("alt")+" ";a.val(c?c+" "+d:d).focus()});var h=Candy.Util.getPosLeftAccordingToWindowBounds(e,d.left),i=Candy.Util.getPosTopAccordingToWindowBounds(e,d.top);return e.css({left:h.px,top:i.px}).removeClass("left-top left-bottom right-top right-bottom").addClass(h.backgroundPositionAlignment+"-"+i.backgroundPositionAlignment).fadeIn("fast"),!0}}},a.Room={init:function(c,d,e){e=e||"groupchat",c=Candy.Util.unescapeJid(c);var f={roomJid:c,type:e};if(b(Candy).triggerHandler("candy:view.room.before-add",f)===!1)return!1;Candy.Util.isEmptyObject(a.Chat.rooms)&&a.Chat.Toolbar.show();var g=Candy.Util.jidToId(c);return a.Chat.rooms[c]={id:g,usercount:0,name:d,type:e,messageCount:0,scrollPosition:-1},b("#chat-rooms").append(Mustache.to_html(Candy.View.Template.Room.pane,{roomId:g,roomJid:c,roomType:e,form:{_messageSubmit:b.i18n._("messageSubmit")},roster:{_userOnline:b.i18n._("userOnline")}},{roster:Candy.View.Template.Roster.pane,messages:Candy.View.Template.Message.pane,form:Candy.View.Template.Room.form})),a.Chat.addTab(c,d,e),a.Room.getPane(c,".message-form").submit(a.Message.submit),f.element=a.Room.getPane(c),b(Candy).triggerHandler("candy:view.room.after-add",f),g},show:function(c){var d,e=a.Chat.rooms[c].id;b(".room-pane").each(function(){var f=b(this);d={roomJid:f.attr("data-roomjid"),element:f},f.attr("id")==="chat-room-"+e?(f.show(),Candy.View.getCurrent().roomJid=c,a.Chat.setActiveTab(c),a.Chat.Toolbar.update(c),a.Chat.clearUnreadMessages(c),a.Room.setFocusToForm(c),a.Room.scrollToBottom(c),b(Candy).triggerHandler("candy:view.room.after-show",d)):(f.hide(),b(Candy).triggerHandler("candy:view.room.after-hide",d))})},setSubject:function(c,d){d=Candy.Util.Parser.linkify(Candy.Util.Parser.escape(d));var e=Mustache.to_html(Candy.View.Template.Room.subject,{subject:d,roomName:a.Chat.rooms[c].name,_roomSubject:b.i18n._("roomSubject"),time:Candy.Util.localizedTime((new Date).toGMTString())});a.Room.appendToMessagePane(c,e),a.Room.scrollToBottom(c),b(Candy).triggerHandler("candy:view.room.after-subject-change",{roomJid:c,element:a.Room.getPane(c),subject:d})},close:function(c){a.Chat.removeTab(c),a.Window.clearUnreadMessages(),a.Room.getPane(c).remove();var d=b("#chat-rooms").children();Candy.View.getCurrent().roomJid===c&&(Candy.View.getCurrent().roomJid=null,0===d.length?a.Chat.allTabsClosed():a.Room.show(d.last().attr("data-roomjid"))),delete a.Chat.rooms[c],b(Candy).triggerHandler("candy:view.room.after-close",{roomJid:c})},appendToMessagePane:function(b,c){a.Room.getPane(b,".message-pane").append(c),a.Chat.rooms[b].messageCount++,a.Room.sliceMessagePane(b)},sliceMessagePane:function(b){if(a.Window.autoscroll){var c=Candy.View.getOptions().messages;a.Chat.rooms[b].messageCount>c.limit&&(a.Room.getPane(b,".message-pane").children().slice(0,c.remove).remove(),a.Chat.rooms[b].messageCount-=c.remove)}},scrollToBottom:function(b){a.Room.onScrollToBottom(b)},onScrollToBottom:function(b){var c=a.Room.getPane(b,".message-pane-wrapper");c.scrollTop(c.prop("scrollHeight"))},onScrollToStoredPosition:function(b){if(a.Chat.rooms[b].scrollPosition>-1){var c=a.Room.getPane(b,".message-pane-wrapper");c.scrollTop(a.Chat.rooms[b].scrollPosition),a.Chat.rooms[b].scrollPosition=-1}},setFocusToForm:function(b){var c=a.Room.getPane(b,".message-form");if(c)try{c.children(".field")[0].focus()}catch(d){}},setUser:function(c,d){a.Chat.rooms[c].user=d;var e=a.Room.getPane(c),f=b("#chat-pane");e.attr("data-userjid",d.getJid()),d.isModerator()?(d.getRole()===d.ROLE_MODERATOR&&f.addClass("role-moderator"),d.getAffiliation()===d.AFFILIATION_OWNER&&f.addClass("affiliation-owner")):f.removeClass("role-moderator affiliation-owner"),a.Chat.Context.init()},getUser:function(b){return a.Chat.rooms[b].user},ignoreUser:function(a,b){Candy.Core.Action.Jabber.Room.IgnoreUnignore(b),Candy.View.Pane.Room.addIgnoreIcon(a,b)},unignoreUser:function(a,b){Candy.Core.Action.Jabber.Room.IgnoreUnignore(b),Candy.View.Pane.Room.removeIgnoreIcon(a,b)},addIgnoreIcon:function(a,c){Candy.View.Pane.Chat.rooms[c]&&b("#user-"+Candy.View.Pane.Chat.rooms[c].id+"-"+Candy.Util.jidToId(c)).addClass("status-ignored"),Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(a)]&&b("#user-"+Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(a)].id+"-"+Candy.Util.jidToId(c)).addClass("status-ignored")},removeIgnoreIcon:function(a,c){Candy.View.Pane.Chat.rooms[c]&&b("#user-"+Candy.View.Pane.Chat.rooms[c].id+"-"+Candy.Util.jidToId(c)).removeClass("status-ignored"),Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(a)]&&b("#user-"+Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(a)].id+"-"+Candy.Util.jidToId(c)).removeClass("status-ignored")},getPane:function(c,d){return a.Chat.rooms[c]?d?a.Chat.rooms[c]["pane-"+d]?a.Chat.rooms[c]["pane-"+d]:(a.Chat.rooms[c]["pane-"+d]=b("#chat-room-"+a.Chat.rooms[c].id).find(d),a.Chat.rooms[c]["pane-"+d]):b("#chat-room-"+a.Chat.rooms[c].id):void 0},changeDataUserJidIfUserIsMe:function(a,c){if(c.getNick()===Candy.Core.getUser().getNick()){var d=b("#chat-room-"+a);d.attr("data-userjid",Strophe.getBareJidFromJid(d.attr("data-userjid"))+"/"+c.getNick())}}},a.PrivateRoom={open:function(c,d,e,f){var g=f?Candy.Core.getUser():a.Room.getUser(Strophe.getBareJidFromJid(c)),h={roomJid:c,roomName:d,type:"chat"};return b(Candy).triggerHandler("candy:view.private-room.before-open",h)===!1?!1:Candy.Core.getUser().isInPrivacyList("ignore",c)?!1:a.Chat.rooms[c]||a.Room.init(c,d,"chat")!==!1?(e&&a.Room.show(c),a.Roster.update(c,new Candy.Core.ChatUser(c,d),"join",g),a.Roster.update(c,g,"join",g),a.PrivateRoom.setStatus(c,"join"),f&&a.Chat.infoMessage(c,b.i18n._("presenceUnknownWarningSubject"),b.i18n._("presenceUnknownWarning")),h.element=a.Room.getPane(c),void b(Candy).triggerHandler("candy:view.private-room.after-open",h)):!1},setStatus:function(b,c){var d=a.Room.getPane(b,".message-form");"join"===c?(a.Chat.getTab(b).addClass("online").removeClass("offline"),d.children(".field").removeAttr("disabled"),d.children(".submit").removeAttr("disabled"),a.Chat.getTab(b)):"leave"===c&&(a.Chat.getTab(b).addClass("offline").removeClass("online"),d.children(".field").attr("disabled",!0),d.children(".submit").attr("disabled",!0))},changeNick:function(c,d){Candy.Core.log("[View:Pane:PrivateRoom] changeNick");var e,f,g=c+"/"+d.getPreviousNick(),h=c+"/"+d.getNick(),i=Candy.Util.jidToId(g),j=Candy.Util.jidToId(h),k=a.Chat.rooms[g];a.Chat.rooms[h]&&a.Room.close(h),k?(k.name=d.getNick(),k.id=j,a.Chat.rooms[h]=k,delete a.Chat.rooms[g],e=b("#chat-room-"+i),e&&(e.attr("data-roomjid",h),e.attr("id","chat-room-"+j),f=b('#chat-tabs li[data-roomjid="'+g+'"]'),f.attr("data-roomjid",h),f.children("a.label").text("@"+d.getNick()),Candy.View.getCurrent().roomJid===g&&(Candy.View.getCurrent().roomJid=h))):(e=b('.room-pane.roomtype-chat[data-userjid="'+g+'"]'),e.length&&(i=Candy.Util.jidToId(e.attr("data-roomjid")),e.attr("data-userjid",h))),e&&e.length&&a.Roster.changeNick(i,d)}},a.Roster={update:function(c,d,e,f){Candy.Core.log("[View:Pane:Roster] "+e);var g=a.Chat.rooms[c].id,h=Candy.Util.jidToId(d.getJid()),i=-1,j=b("#user-"+g+"-"+h),k={roomJid:c,user:d,action:e,element:j};if(b(Candy).triggerHandler("candy:view.roster.before-update",k),"join"===e){i=1;var l=Mustache.to_html(Candy.View.Template.Roster.user,{roomId:g,userId:h,userJid:d.getJid(),nick:d.getNick(),displayNick:Candy.Util.crop(d.getNick(),Candy.View.getOptions().crop.roster.nickname),role:d.getRole(),affiliation:d.getAffiliation(),me:void 0!==f&&d.getNick()===f.getNick(),tooltipRole:b.i18n._("tooltipRole"),tooltipIgnored:b.i18n._("tooltipIgnored")});if(j.length<1){var m=!1,n=a.Room.getPane(c,".roster-pane");if(n.children().length>0){var o=d.getNick().toUpperCase();n.children().each(function(){var a=b(this);return a.attr("data-nick").toUpperCase()>o?(a.before(l),m=!0,!1):!0})}m||n.append(l),a.Roster.showJoinAnimation(d,h,g,c,f)}else i=0,j.replaceWith(l),b("#user-"+g+"-"+h).css({opacity:1}).show(),void 0!==f&&d.getNick()===f.getNick()&&a.Room.getUser(c)&&a.Chat.Toolbar.update(c);void 0!==f&&f.getNick()===d.getNick()?a.Room.setUser(c,d):b("#user-"+g+"-"+h).click(a.Roster.userClick),b("#user-"+g+"-"+h+" .context").click(function(b){a.Chat.Context.show(b.currentTarget,c,d),b.stopPropagation()}),void 0!==f&&f.isInPrivacyList("ignore",d.getJid())&&Candy.View.Pane.Room.addIgnoreIcon(c,d.getJid())}else if("leave"===e)a.Roster.leaveAnimation("user-"+g+"-"+h),"chat"===a.Chat.rooms[c].type?a.Chat.onInfoMessage(c,b.i18n._("userLeftRoom",[d.getNick()])):a.Chat.infoMessage(c,b.i18n._("userLeftRoom",[d.getNick()]));else if("nickchange"===e){i=0,a.Roster.changeNick(g,d),a.Room.changeDataUserJidIfUserIsMe(g,d),a.PrivateRoom.changeNick(c,d);var p=b.i18n._("userChangedNick",[d.getPreviousNick(),d.getNick()]);a.Chat.onInfoMessage(c,p)}else"kick"===e?(a.Roster.leaveAnimation("user-"+g+"-"+h),a.Chat.onInfoMessage(c,b.i18n._("userHasBeenKickedFromRoom",[d.getNick()]))):"ban"===e&&(a.Roster.leaveAnimation("user-"+g+"-"+h),a.Chat.onInfoMessage(c,b.i18n._("userHasBeenBannedFromRoom",[d.getNick()])));Candy.View.Pane.Chat.rooms[c].usercount+=i,c===Candy.View.getCurrent().roomJid&&Candy.View.Pane.Chat.Toolbar.updateUsercount(Candy.View.Pane.Chat.rooms[c].usercount),k.element=b("#user-"+g+"-"+h),b(Candy).triggerHandler("candy:view.roster.after-update",k)},userClick:function(){var c=b(this);a.PrivateRoom.open(c.attr("data-jid"),c.attr("data-nick"),!0)},showJoinAnimation:function(c,d,e,f,g){var h="user-"+e+"-"+d,i=b("#"+h);c.getPreviousNick()&&i&&i.is(":visible")!==!1||(a.Roster.joinAnimation(h),void 0!==g&&c.getNick()!==g.getNick()&&a.Room.getUser(f)&&("chat"===a.Chat.rooms[f].type?a.Chat.onInfoMessage(f,b.i18n._("userJoinedRoom",[c.getNick()])):a.Chat.infoMessage(f,b.i18n._("userJoinedRoom",[c.getNick()]))))},joinAnimation:function(a){b("#"+a).stop(!0).slideDown("normal",function(){b(this).animate({opacity:1})})},leaveAnimation:function(a){b("#"+a).stop(!0).attr("id","#"+a+"-leaving").animate({opacity:0},{complete:function(){b(this).slideUp("normal",function(){b(this).remove()})}})},changeNick:function(a,c){Candy.Core.log("[View:Pane:Roster] changeNick");var d=Strophe.getBareJidFromJid(c.getJid())+"/"+c.getPreviousNick(),e="user-"+a+"-"+Candy.Util.jidToId(d),f=b("#"+e);f.attr("data-nick",c.getNick()),f.attr("data-jid",c.getJid()),f.children("div.label").text(c.getNick()),f.attr("id","user-"+a+"-"+Candy.Util.jidToId(c.getJid()))}},a.Message={submit:function(c){var d,e=Candy.View.getCurrent().roomJid,f=Candy.View.Pane.Chat.rooms[e].type,g=b(this).children(".field").val().substring(0,Candy.View.getOptions().crop.message.body),h={roomJid:e,message:g,xhtmlMessage:d};return b(Candy).triggerHandler("candy:view.message.before-send",h)===!1?void c.preventDefault():(g=h.message,d=h.xhtmlMessage,Candy.Core.Action.Jabber.Room.Message(e,g,f,d),"chat"===f&&g&&a.Message.show(e,a.Room.getUser(e).getNick(),g),b(this).children(".field").val("").focus(),void c.preventDefault())},show:function(c,d,e,f,g){e=Candy.Util.Parser.all(e.substring(0,Candy.View.getOptions().crop.message.body)),f&&(f=Candy.Util.parseAndCropXhtml(f,Candy.View.getOptions().crop.message.body));var h={roomJid:c,name:d,message:e,xhtmlMessage:f};if(b(Candy).triggerHandler("candy:view.message.before-show",h)!==!1&&(e=h.message,f=h.xhtmlMessage,void 0!==f&&f.length>0&&(e=f),e)){var i={template:Candy.View.Template.Message.item,templateData:{name:d,displayName:Candy.Util.crop(d,Candy.View.getOptions().crop.message.nickname),message:e,time:Candy.Util.localizedTime(g||(new Date).toGMTString())}};b(Candy).triggerHandler("candy:view.message.before-render",i);var j=Mustache.to_html(i.template,i.templateData);a.Room.appendToMessagePane(c,j);var k=a.Room.getPane(c,".message-pane").children().last();k.find("a.label").click(function(b){b.preventDefault();var e=Candy.Core.getRoom(c);return e&&d!==a.Room.getUser(Candy.View.getCurrent().roomJid).getNick()&&e.getRoster().get(c+"/"+d)&&Candy.View.Pane.PrivateRoom.open(c+"/"+d,d,!0)===!1?!1:void 0}),Candy.View.getCurrent().roomJid===c&&a.Window.hasFocus()||(a.Chat.increaseUnreadMessages(c),"chat"!==Candy.View.Pane.Chat.rooms[c].type||a.Window.hasFocus()||a.Chat.Toolbar.playSound()),Candy.View.getCurrent().roomJid===c&&a.Room.scrollToBottom(c),h.element=k,b(Candy).triggerHandler("candy:view.message.after-show",h)}}},a}(Candy.View.Pane||{},jQuery),Candy.View.Template=function(a){return a.Window={unreadmessages:"({{count}}) {{title}}"},a.Chat={pane:'
      {{> tabs}}{{> toolbar}}{{> rooms}}
      {{> modal}}',rooms:'
      ',tabs:'
        ',tab:'
      • {{#privateUserChat}}@{{/privateUserChat}}{{name}}×
      • ',modal:'
        ',adminMessage:'
      • {{time}}
        {{sender}}{{subject}} {{message}}
      • ',infoMessage:'
      • {{time}}
        {{subject}} {{message}}
      • ',toolbar:'
        • {{> soundcontrol}}
        ',soundcontrol:'',Context:{menu:'
          ',menulinks:'
        • {{label}}
        • ',contextModalForm:'
          ',adminMessageReason:'×

          {{_action}}

          {{#reason}}

          {{_reason}}

          {{/reason}}'},tooltip:'
          '},a.Room={pane:'
          {{> roster}}{{> messages}}{{> form}}
          ',subject:'
        • {{time}}
          {{roomName}}{{_roomSubject}} {{{subject}}}
        • ',form:'
          '},a.Roster={pane:'
          ',user:'
          {{displayNick}}
          '},a.Message={pane:'
            ',item:'
          • {{time}}
            {{displayName}}{{{message}}}
          • '},a.Login={form:''},a.PresenceError={enterPasswordForm:'{{_label}}
            ',nicknameConflictForm:'{{_label}}
            ',displayError:"{{_error}}"},a}(Candy.View.Template||{}),Candy.View.Translation={en:{status:"Status: %s",statusConnecting:"Connecting...",statusConnected:"Connected",statusDisconnecting:"Disconnecting...",statusDisconnected:"Disconnected",statusAuthfail:"Authentication failed",roomSubject:"Subject:",messageSubmit:"Send",labelUsername:"Username:",labelNickname:"Nickname:",labelPassword:"Password:",loginSubmit:"Login",loginInvalid:"Invalid JID",reason:"Reason:",subject:"Subject:",reasonWas:"Reason was: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"You have been kicked from %2$s by %1$s",youHaveBeenKicked:"You have been kicked from %s",banActionLabel:"Ban",youHaveBeenBannedBy:"You have been banned from %1$s by %2$s",youHaveBeenBanned:"You have been banned from %s",privateActionLabel:"Private chat",ignoreActionLabel:"Ignore",unignoreActionLabel:"Unignore",setSubjectActionLabel:"Change Subject",administratorMessageSubject:"Administrator",userJoinedRoom:"%s joined the room.",userLeftRoom:"%s left the room.",userHasBeenKickedFromRoom:"%s has been kicked from the room.",userHasBeenBannedFromRoom:"%s has been banned from the room.",userChangedNick:"%1$s has changed his nickname to %2$s.",presenceUnknownWarningSubject:"Notice:",presenceUnknownWarning:"This user might be offline. We can't track his presence.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"You ignore this user",tooltipEmoticons:"Emoticons",tooltipSound:"Play sound for new private messages",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Display status messages",tooltipAdministration:"Room Administration",tooltipUsercount:"Room Occupants",enterRoomPassword:'Room "%s" is password protected.',enterRoomPasswordSubmit:"Join room",passwordEnteredInvalid:'Invalid password for room "%s".',nicknameConflict:"Username already in use. Please choose another one.",errorMembersOnly:'You can\'t join room "%s": Insufficient rights.',errorMaxOccupantsReached:'You can\'t join room "%s": Too many occupants.',errorAutojoinMissing:"No autojoin parameter set in configuration. Please set one to continue.",antiSpamMessage:"Please do not spam. You have been blocked for a short-time."},de:{status:"Status: %s",statusConnecting:"Verbinden...",statusConnected:"Verbunden",statusDisconnecting:"Verbindung trennen...",statusDisconnected:"Verbindung getrennt",statusAuthfail:"Authentifizierung fehlgeschlagen",roomSubject:"Thema:",messageSubmit:"Senden",labelUsername:"Benutzername:",labelNickname:"Spitzname:",labelPassword:"Passwort:",loginSubmit:"Anmelden",loginInvalid:"Ungültige JID",reason:"Begründung:",subject:"Titel:",reasonWas:"Begründung: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"Du wurdest soeben aus dem Raum %1$s gekickt (%2$s)",youHaveBeenKicked:"Du wurdest soeben aus dem Raum %s gekickt",banActionLabel:"Ban",youHaveBeenBannedBy:"Du wurdest soeben aus dem Raum %1$s verbannt (%2$s)",youHaveBeenBanned:"Du wurdest soeben aus dem Raum %s verbannt",privateActionLabel:"Privater Chat",ignoreActionLabel:"Ignorieren",unignoreActionLabel:"Nicht mehr ignorieren",setSubjectActionLabel:"Thema ändern",administratorMessageSubject:"Administrator",userJoinedRoom:"%s hat soeben den Raum betreten.",userLeftRoom:"%s hat soeben den Raum verlassen.",userHasBeenKickedFromRoom:"%s ist aus dem Raum gekickt worden.",userHasBeenBannedFromRoom:"%s ist aus dem Raum verbannt worden.",userChangedNick:"%1$s hat den Nicknamen zu %2$s geändert.",presenceUnknownWarningSubject:"Hinweis:",presenceUnknownWarning:"Dieser Benutzer könnte bereits abgemeldet sein. Wir können seine Anwesenheit nicht verfolgen.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Du ignorierst diesen Benutzer",tooltipEmoticons:"Smileys",tooltipSound:"Ton abspielen bei neuen privaten Nachrichten",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Statusnachrichten anzeigen",tooltipAdministration:"Raum Administration",tooltipUsercount:"Anzahl Benutzer im Raum",enterRoomPassword:'Raum "%s" ist durch ein Passwort geschützt.',enterRoomPasswordSubmit:"Raum betreten",passwordEnteredInvalid:'Inkorrektes Passwort für Raum "%s".',nicknameConflict:"Der Benutzername wird bereits verwendet. Bitte wähle einen anderen.",errorMembersOnly:'Du kannst den Raum "%s" nicht betreten: Ungenügende Rechte.',errorMaxOccupantsReached:'Du kannst den Raum "%s" nicht betreten: Benutzerlimit erreicht.',errorAutojoinMissing:'Keine "autojoin" Konfiguration gefunden. Bitte setze eine konfiguration um fortzufahren.',antiSpamMessage:"Bitte nicht spammen. Du wurdest für eine kurze Zeit blockiert."},fr:{status:"Status : %s",statusConnecting:"Connexion…",statusConnected:"Connecté.",statusDisconnecting:"Déconnexion…",statusDisconnected:"Déconnecté.",statusAuthfail:"L'authentification a échoué",roomSubject:"Sujet :",messageSubmit:"Envoyer",labelUsername:"Nom d'utilisateur :",labelPassword:"Mot de passe :",loginSubmit:"Connexion",loginInvalid:"JID invalide",reason:"Motif :",subject:"Titre :",reasonWas:"Motif : %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"Vous avez été expulsé du salon %1$s (%2$s)",youHaveBeenKicked:"Vous avez été expulsé du salon %s",banActionLabel:"Ban",youHaveBeenBannedBy:"Vous avez été banni du salon %1$s (%2$s)",youHaveBeenBanned:"Vous avez été banni du salon %s",privateActionLabel:"Chat privé",ignoreActionLabel:"Ignorer",unignoreActionLabel:"Ne plus ignorer",setSubjectActionLabel:"Changer le sujet",administratorMessageSubject:"Administrateur",userJoinedRoom:"%s vient d'entrer dans le salon.",userLeftRoom:"%s vient de quitter le salon.",userHasBeenKickedFromRoom:"%s a été expulsé du salon.",userHasBeenBannedFromRoom:"%s a été banni du salon.",presenceUnknownWarningSubject:"Note :",presenceUnknownWarning:"Cet utilisateur n'est malheureusement plus connecté, le message ne sera pas envoyé.",dateFormat:"dd/mm/yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Modérateur",tooltipIgnored:"Vous ignorez cette personne",tooltipEmoticons:"Smileys",tooltipSound:"Jouer un son lors de la réception de nouveaux messages privés",tooltipAutoscroll:"Défilement automatique",tooltipStatusmessage:"Messages d'état",tooltipAdministration:"Administration du salon",tooltipUsercount:"Nombre d'utilisateurs dans le salon",enterRoomPassword:'Le salon "%s" est protégé par un mot de passe.',enterRoomPasswordSubmit:"Entrer dans le salon",passwordEnteredInvalid:'Le mot de passe pour le salon "%s" est invalide.',nicknameConflict:"Le nom d'utilisateur est déjà utilisé. Veuillez en choisir un autre.",errorMembersOnly:'Vous ne pouvez pas entrer dans le salon "%s" : droits insuffisants.',errorMaxOccupantsReached:'Vous ne pouvez pas entrer dans le salon "%s": Limite d\'utilisateur atteint.',antiSpamMessage:"Merci de ne pas envoyer de spam. Vous avez été bloqué pendant une courte période.."},nl:{status:"Status: %s",statusConnecting:"Verbinding maken...",statusConnected:"Verbinding is gereed",statusDisconnecting:"Verbinding verbreken...",statusDisconnected:"Verbinding is verbroken",statusAuthfail:"Authenticatie is mislukt",roomSubject:"Onderwerp:",messageSubmit:"Verstuur",labelUsername:"Gebruikersnaam:",labelPassword:"Wachtwoord:",loginSubmit:"Inloggen",loginInvalid:"JID is onjuist",reason:"Reden:",subject:"Onderwerp:",reasonWas:"De reden was: %s.",kickActionLabel:"Verwijderen",youHaveBeenKickedBy:"Je bent verwijderd van %1$s door %2$s",youHaveBeenKicked:"Je bent verwijderd van %s",banActionLabel:"Blokkeren",youHaveBeenBannedBy:"Je bent geblokkeerd van %1$s door %2$s",youHaveBeenBanned:"Je bent geblokkeerd van %s",privateActionLabel:"Prive gesprek",ignoreActionLabel:"Negeren",unignoreActionLabel:"Niet negeren",setSubjectActionLabel:"Onderwerp wijzigen",administratorMessageSubject:"Beheerder",userJoinedRoom:"%s komt de chat binnen.",userLeftRoom:"%s heeft de chat verlaten.",userHasBeenKickedFromRoom:"%s is verwijderd.",userHasBeenBannedFromRoom:"%s is geblokkeerd.",presenceUnknownWarningSubject:"Mededeling:",presenceUnknownWarning:"Deze gebruiker is waarschijnlijk offline, we kunnen zijn/haar aanwezigheid niet vaststellen.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Je negeert deze gebruiker",tooltipEmoticons:"Emotie-iconen",tooltipSound:"Speel een geluid af bij nieuwe privé berichten.",tooltipAutoscroll:"Automatisch scrollen",tooltipStatusmessage:"Statusberichten weergeven",tooltipAdministration:"Instellingen",tooltipUsercount:"Gebruikers",enterRoomPassword:'De Chatroom "%s" is met een wachtwoord beveiligd.',enterRoomPasswordSubmit:"Ga naar Chatroom",passwordEnteredInvalid:'Het wachtwoord voor de Chatroom "%s" is onjuist.',nicknameConflict:"De gebruikersnaam is reeds in gebruik. Probeer a.u.b. een andere gebruikersnaam.",errorMembersOnly:'Je kunt niet deelnemen aan de Chatroom "%s": Je hebt onvoldoende rechten.',errorMaxOccupantsReached:'Je kunt niet deelnemen aan de Chatroom "%s": Het maximum aantal gebruikers is bereikt.',antiSpamMessage:"Het is niet toegestaan om veel berichten naar de server te versturen. Je bent voor een korte periode geblokkeerd."},es:{status:"Estado: %s",statusConnecting:"Conectando...",statusConnected:"Conectado",statusDisconnecting:"Desconectando...",statusDisconnected:"Desconectado",statusAuthfail:"Falló la autenticación",roomSubject:"Asunto:",messageSubmit:"Enviar",labelUsername:"Usuario:",labelPassword:"Clave:",loginSubmit:"Entrar",loginInvalid:"JID no válido",reason:"Razón:",subject:"Asunto:",reasonWas:"La razón fue: %s.",kickActionLabel:"Expulsar",youHaveBeenKickedBy:"Has sido expulsado de %1$s por %2$s",youHaveBeenKicked:"Has sido expulsado de %s",banActionLabel:"Prohibir",youHaveBeenBannedBy:"Has sido expulsado permanentemente de %1$s por %2$s",youHaveBeenBanned:"Has sido expulsado permanentemente de %s",privateActionLabel:"Chat privado",ignoreActionLabel:"Ignorar",unignoreActionLabel:"No ignorar",setSubjectActionLabel:"Cambiar asunto",administratorMessageSubject:"Administrador",userJoinedRoom:"%s se ha unido a la sala.",userLeftRoom:"%s ha dejado la sala.",userHasBeenKickedFromRoom:"%s ha sido expulsado de la sala.",userHasBeenBannedFromRoom:"%s ha sido expulsado permanentemente de la sala.",presenceUnknownWarningSubject:"Atención:",presenceUnknownWarning:"Éste usuario podría estar desconectado..",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderador",tooltipIgnored:"Ignoras a éste usuario",tooltipEmoticons:"Emoticonos",tooltipSound:"Reproducir un sonido para nuevos mensajes privados",tooltipAutoscroll:"Desplazamiento automático",tooltipStatusmessage:"Mostrar mensajes de estado",tooltipAdministration:"Administración de la sala",tooltipUsercount:"Usuarios en la sala",enterRoomPassword:'La sala "%s" está protegida mediante contraseña.',enterRoomPasswordSubmit:"Unirse a la sala",passwordEnteredInvalid:'Contraseña incorrecta para la sala "%s".',nicknameConflict:"El nombre de usuario ya está siendo utilizado. Por favor elija otro.",errorMembersOnly:'No se puede unir a la sala "%s": no tiene privilegios suficientes.',errorMaxOccupantsReached:'No se puede unir a la sala "%s": demasiados participantes.',antiSpamMessage:"Por favor, no hagas spam. Has sido bloqueado temporalmente."},cn:{status:"状态: %s",statusConnecting:"连接中...",statusConnected:"已连接",statusDisconnecting:"断开连接中...",statusDisconnected:"已断开连接",statusAuthfail:"认证失败",roomSubject:"主题:",messageSubmit:"发送",labelUsername:"用户名:",labelPassword:"密码:",loginSubmit:"登录",loginInvalid:"用户名不合法",reason:"原因:",subject:"主题:",reasonWas:"原因是: %s.",kickActionLabel:"踢除",youHaveBeenKickedBy:"你在 %1$s 被管理者 %2$s 请出房间",banActionLabel:"禁言",youHaveBeenBannedBy:"你在 %1$s 被管理者 %2$s 禁言",privateActionLabel:"单独对话",ignoreActionLabel:"忽略",unignoreActionLabel:"不忽略",setSubjectActionLabel:"变更主题",administratorMessageSubject:"管理员",userJoinedRoom:"%s 加入房间",userLeftRoom:"%s 离开房间",userHasBeenKickedFromRoom:"%s 被请出这个房间",userHasBeenBannedFromRoom:"%s 被管理者禁言",presenceUnknownWarningSubject:"注意:",presenceUnknownWarning:"这个会员可能已经下线,不能追踪到他的连接信息",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"管理",tooltipIgnored:"你忽略了这个会员",tooltipEmoticons:"表情",tooltipSound:"新消息发音",tooltipAutoscroll:"滚动条",tooltipStatusmessage:"禁用状态消息",tooltipAdministration:"房间管理",tooltipUsercount:"房间占有者",enterRoomPassword:'登录房间 "%s" 需要密码.',enterRoomPasswordSubmit:"加入房间",passwordEnteredInvalid:'登录房间 "%s" 的密码不正确',nicknameConflict:"用户名已经存在,请另选一个",errorMembersOnly:'您的权限不够,不能登录房间 "%s" ',errorMaxOccupantsReached:'房间 "%s" 的人数已达上限,您不能登录',antiSpamMessage:"因为您在短时间内发送过多的消息 服务器要阻止您一小段时间。"},ja:{status:"ステータス: %s",statusConnecting:"接続中…",statusConnected:"接続されました",statusDisconnecting:"ディスコネクト中…",statusDisconnected:"ディスコネクトされました",statusAuthfail:"認証に失敗しました",roomSubject:"トピック:",messageSubmit:"送信",labelUsername:"ユーザーネーム:",labelPassword:"パスワード:",loginSubmit:"ログイン",loginInvalid:"ユーザーネームが正しくありません",reason:"理由:",subject:"トピック:",reasonWas:"理由: %s。",kickActionLabel:"キック",youHaveBeenKickedBy:"あなたは%2$sにより%1$sからキックされました。",youHaveBeenKicked:"あなたは%sからキックされました。",banActionLabel:"アカウントバン",youHaveBeenBannedBy:"あなたは%2$sにより%1$sからアカウントバンされました。",youHaveBeenBanned:"あなたは%sからアカウントバンされました。",privateActionLabel:"プライベートメッセージ",ignoreActionLabel:"無視する",unignoreActionLabel:"無視をやめる",setSubjectActionLabel:"トピックを変える",administratorMessageSubject:"管理者",userJoinedRoom:"%sは入室しました。",userLeftRoom:"%sは退室しました。",userHasBeenKickedFromRoom:"%sは部屋からキックされました。",userHasBeenBannedFromRoom:"%sは部屋からアカウントバンされました。",presenceUnknownWarningSubject:"忠告:",presenceUnknownWarning:"このユーザーのステータスは不明です。",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"モデレーター",tooltipIgnored:"このユーザーを無視設定にしている",tooltipEmoticons:"絵文字",tooltipSound:"新しいメッセージが届くたびに音を鳴らす",tooltipAutoscroll:"オートスクロール",tooltipStatusmessage:"ステータスメッセージを表示",tooltipAdministration:"部屋の管理",tooltipUsercount:"この部屋の参加者の数",enterRoomPassword:'"%s"の部屋に入るにはパスワードが必要です。',enterRoomPasswordSubmit:"部屋に入る",passwordEnteredInvalid:'"%s"のパスワードと異なるパスワードを入力しました。',nicknameConflict:"このユーザーネームはすでに利用されているため、別のユーザーネームを選んでください。",errorMembersOnly:'"%s"の部屋に入ることができません: 利用権限を満たしていません。',errorMaxOccupantsReached:'"%s"の部屋に入ることができません: 参加者の数はすでに上限に達しました。',antiSpamMessage:"スパムなどの行為はやめてください。あなたは一時的にブロックされました。"},sv:{status:"Status: %s",statusConnecting:"Ansluter...",statusConnected:"Ansluten",statusDisconnecting:"Kopplar från...",statusDisconnected:"Frånkopplad",statusAuthfail:"Autentisering misslyckades",roomSubject:"Ämne:",messageSubmit:"Skicka",labelUsername:"Användarnamn:",labelPassword:"Lösenord:",loginSubmit:"Logga in",loginInvalid:"Ogiltigt JID",reason:"Anledning:",subject:"Ämne:",reasonWas:"Anledningen var: %s.",kickActionLabel:"Sparka ut",youHaveBeenKickedBy:"Du har blivit utsparkad från %2$s av %1$s",youHaveBeenKicked:"Du har blivit utsparkad från %s",banActionLabel:"Bannlys",youHaveBeenBannedBy:"Du har blivit bannlyst från %1$s av %2$s",youHaveBeenBanned:"Du har blivit bannlyst från %s",privateActionLabel:"Privat chatt",ignoreActionLabel:"Blockera",unignoreActionLabel:"Avblockera",setSubjectActionLabel:"Ändra ämne",administratorMessageSubject:"Administratör",userJoinedRoom:"%s kom in i rummet.",userLeftRoom:"%s har lämnat rummet.",userHasBeenKickedFromRoom:"%s har blivit utsparkad ur rummet.",userHasBeenBannedFromRoom:"%s har blivit bannlyst från rummet.",presenceUnknownWarningSubject:"Notera:",presenceUnknownWarning:"Denna användare kan vara offline. Vi kan inte följa dennes närvaro.",dateFormat:"yyyy-mm-dd",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Du blockerar denna användare",tooltipEmoticons:"Smilies",tooltipSound:"Spela upp ett ljud vid nytt privat meddelande",tooltipAutoscroll:"Autoskrolla",tooltipStatusmessage:"Visa statusmeddelanden",tooltipAdministration:"Rumadministrering",tooltipUsercount:"Antal användare i rummet",enterRoomPassword:'Rummet "%s" är lösenordsskyddat.',enterRoomPasswordSubmit:"Anslut till rum",passwordEnteredInvalid:'Ogiltigt lösenord för rummet "%s".',nicknameConflict:"Upptaget användarnamn. Var god välj ett annat.",errorMembersOnly:'Du kan inte ansluta till rummet "%s": Otillräckliga rättigheter.',errorMaxOccupantsReached:'Du kan inte ansluta till rummet "%s": Rummet är fullt.',antiSpamMessage:"Var god avstå från att spamma. Du har blivit blockerad för en kort stund."},it:{status:"Stato: %s",statusConnecting:"Connessione...",statusConnected:"Connessione",statusDisconnecting:"Disconnessione...",statusDisconnected:"Disconnesso",statusAuthfail:"Autenticazione fallita",roomSubject:"Oggetto:",messageSubmit:"Invia",labelUsername:"Nome utente:",labelPassword:"Password:",loginSubmit:"Login",loginInvalid:"JID non valido",reason:"Ragione:",subject:"Oggetto:",reasonWas:"Ragione precedente: %s.",kickActionLabel:"Espelli",youHaveBeenKickedBy:"Sei stato espulso da %2$s da %1$s",youHaveBeenKicked:"Sei stato espulso da %s",banActionLabel:"Escluso",youHaveBeenBannedBy:"Sei stato escluso da %1$s da %2$s",youHaveBeenBanned:"Sei stato escluso da %s",privateActionLabel:"Stanza privata",ignoreActionLabel:"Ignora",unignoreActionLabel:"Non ignorare",setSubjectActionLabel:"Cambia oggetto",administratorMessageSubject:"Amministratore",userJoinedRoom:"%s si è unito alla stanza.",userLeftRoom:"%s ha lasciato la stanza.",userHasBeenKickedFromRoom:"%s è stato espulso dalla stanza.",userHasBeenBannedFromRoom:"%s è stato escluso dalla stanza.",presenceUnknownWarningSubject:"Nota:",presenceUnknownWarning:"Questo utente potrebbe essere offline. Non possiamo tracciare la sua presenza.",dateFormat:"dd/mm/yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderatore",tooltipIgnored:"Stai ignorando questo utente",tooltipEmoticons:"Emoticons",tooltipSound:"Riproduci un suono quando arrivano messaggi privati",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Mostra messaggi di stato",tooltipAdministration:"Amministrazione stanza",tooltipUsercount:"Partecipanti alla stanza",enterRoomPassword:'La stanza "%s" è protetta da password.',enterRoomPasswordSubmit:"Unisciti alla stanza",passwordEnteredInvalid:'Password non valida per la stanza "%s".',nicknameConflict:"Nome utente già in uso. Scegline un altro.",errorMembersOnly:'Non puoi unirti alla stanza "%s": Permessi insufficienti.',errorMaxOccupantsReached:'Non puoi unirti alla stanza "%s": Troppi partecipanti.',antiSpamMessage:"Per favore non scrivere messaggi pubblicitari. Sei stato bloccato per un po' di tempo."},pt:{status:"Status: %s",statusConnecting:"Conectando...",statusConnected:"Conectado",statusDisconnecting:"Desligando...",statusDisconnected:"Desligado",statusAuthfail:"Falha na autenticação",roomSubject:"Assunto:",messageSubmit:"Enviar",labelUsername:"Usuário:",labelPassword:"Senha:",loginSubmit:"Entrar",loginInvalid:"JID inválido",reason:"Motivo:",subject:"Assunto:",reasonWas:"O motivo foi: %s.",kickActionLabel:"Excluir",youHaveBeenKickedBy:"Você foi excluido de %1$s por %2$s",youHaveBeenKicked:"Você foi excluido de %s",banActionLabel:"Bloquear",youHaveBeenBannedBy:"Você foi excluido permanentemente de %1$s por %2$s",youHaveBeenBanned:"Você foi excluido permanentemente de %s",privateActionLabel:"Bate-papo privado",ignoreActionLabel:"Ignorar",unignoreActionLabel:"Não ignorar",setSubjectActionLabel:"Trocar Assunto",administratorMessageSubject:"Administrador",userJoinedRoom:"%s entrou na sala.",userLeftRoom:"%s saiu da sala.",userHasBeenKickedFromRoom:"%s foi excluido da sala.",userHasBeenBannedFromRoom:"%s foi excluido permanentemente da sala.",presenceUnknownWarning:"Este usuário pode estar desconectado. Não é possível determinar o status.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderador",tooltipIgnored:"Você ignora este usuário",tooltipEmoticons:"Emoticons",tooltipSound:"Reproduzir o som para novas mensagens privados",tooltipAutoscroll:"Deslocamento automático",tooltipStatusmessage:"Mostrar mensagens de status",tooltipAdministration:"Administração da sala",tooltipUsercount:"Usuários na sala",enterRoomPassword:'A sala "%s" é protegida por senha.',enterRoomPasswordSubmit:"Junte-se à sala",passwordEnteredInvalid:'Senha incorreta para a sala "%s".',nicknameConflict:"O nome de usuário já está em uso. Por favor, escolha outro.",errorMembersOnly:'Você não pode participar da sala "%s": privilégios insuficientes.',errorMaxOccupantsReached:'Você não pode participar da sala "%s": muitos participantes.',antiSpamMessage:"Por favor, não envie spam. Você foi bloqueado temporariamente."},pt_br:{status:"Estado: %s",statusConnecting:"Conectando...",statusConnected:"Conectado",statusDisconnecting:"Desconectando...",statusDisconnected:"Desconectado",statusAuthfail:"Autenticação falhou",roomSubject:"Assunto:",messageSubmit:"Enviar",labelUsername:"Usuário:",labelPassword:"Senha:",loginSubmit:"Entrar",loginInvalid:"JID inválido",reason:"Motivo:",subject:"Assunto:",reasonWas:"Motivo foi: %s.",kickActionLabel:"Derrubar",youHaveBeenKickedBy:"Você foi derrubado de %2$s por %1$s",youHaveBeenKicked:"Você foi derrubado de %s",banActionLabel:"Banir",youHaveBeenBannedBy:"Você foi banido de %1$s por %2$s",youHaveBeenBanned:"Você foi banido de %s",privateActionLabel:"Conversa privada",ignoreActionLabel:"Ignorar",unignoreActionLabel:"Não ignorar",setSubjectActionLabel:"Mudar Assunto",administratorMessageSubject:"Administrador",userJoinedRoom:"%s entrou na sala.",userLeftRoom:"%s saiu da sala.",userHasBeenKickedFromRoom:"%s foi derrubado da sala.",userHasBeenBannedFromRoom:"%s foi banido da sala.",presenceUnknownWarningSubject:"Aviso:",presenceUnknownWarning:"Este usuário pode estar desconectado.. Não conseguimos rastrear sua presença..",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderador",tooltipIgnored:"Você ignora este usuário",tooltipEmoticons:"Emoticons",tooltipSound:"Tocar som para novas mensagens privadas",tooltipAutoscroll:"Auto-rolagem",tooltipStatusmessage:"Exibir mensagens de estados",tooltipAdministration:"Administração de Sala",tooltipUsercount:"Participantes da Sala",enterRoomPassword:'Sala "%s" é protegida por senha.',enterRoomPasswordSubmit:"Entrar na sala",passwordEnteredInvalid:'Senha inváida para sala "%s".',nicknameConflict:"Nome de usuário já em uso. Por favor escolha outro.",errorMembersOnly:'Você não pode entrar na sala "%s": privilégios insuficientes.',errorMaxOccupantsReached:'Você não pode entrar na sala "%s": máximo de participantes atingido.',antiSpamMessage:"Por favor, não faça spam. Você foi bloqueado temporariamente."},ru:{status:"Статус: %s",statusConnecting:"Подключение...",statusConnected:"Подключено",statusDisconnecting:"Отключение...",statusDisconnected:"Отключено",statusAuthfail:"Неверный логин",roomSubject:"Топик:",messageSubmit:"Послать",labelUsername:"Имя:",labelPassword:"Пароль:",loginSubmit:"Логин",loginInvalid:"Неверный JID",reason:"Причина:",subject:"Топик:",reasonWas:"Причина была: %s.",kickActionLabel:"Выбросить",youHaveBeenKickedBy:"Пользователь %1$s выбросил вас из чата %2$s",youHaveBeenKicked:"Вас выбросили из чата %s",banActionLabel:"Запретить доступ",youHaveBeenBannedBy:"Пользователь %1$s запретил вам доступ в чат %2$s",youHaveBeenBanned:"Вам запретили доступ в чат %s",privateActionLabel:"Один-на-один чат",ignoreActionLabel:"Игнорировать",unignoreActionLabel:"Отменить игнорирование",setSubjectActionLabel:"Изменить топик",administratorMessageSubject:"Администратор",userJoinedRoom:"%s вошёл в чат.",userLeftRoom:"%s вышел из чата.",userHasBeenKickedFromRoom:"%s выброшен из чата.",userHasBeenBannedFromRoom:"%s запрещён доступ в чат.",presenceUnknownWarningSubject:"Уведомление:",presenceUnknownWarning:"Этот пользователь вероятнее всего оффлайн.",dateFormat:"mm.dd.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Модератор",tooltipIgnored:"Вы игнорируете этого пользователя.",tooltipEmoticons:"Смайлики",tooltipSound:"Озвучивать новое частное сообщение",tooltipAutoscroll:"Авто-прокручивание",tooltipStatusmessage:"Показывать статус сообщения",tooltipAdministration:"Администрирование чат комнаты",tooltipUsercount:"Участники чата",enterRoomPassword:'Чат комната "%s" защищена паролем.',enterRoomPasswordSubmit:"Войти в чат",passwordEnteredInvalid:'Неверный пароль для комнаты "%s".',nicknameConflict:"Это имя уже используется. Пожалуйста выберите другое имя.",errorMembersOnly:'Вы не можете войти в чат "%s": Недостаточно прав доступа.',errorMaxOccupantsReached:'Вы не можете войти в чат "%s": Слишком много участников.',antiSpamMessage:"Пожалуйста не рассылайте спам. Вас заблокировали на короткое время."},ca:{status:"Estat: %s",statusConnecting:"Connectant...",statusConnected:"Connectat",statusDisconnecting:"Desconnectant...",statusDisconnected:"Desconnectat",statusAuthfail:"Ha fallat la autenticació",roomSubject:"Assumpte:",messageSubmit:"Enviar",labelUsername:"Usuari:",labelPassword:"Clau:",loginSubmit:"Entrar",loginInvalid:"JID no vàlid",reason:"Raó:",subject:"Assumpte:",reasonWas:"La raó ha estat: %s.",kickActionLabel:"Expulsar",youHaveBeenKickedBy:"Has estat expulsat de %1$s per %2$s",youHaveBeenKicked:"Has estat expulsat de %s",banActionLabel:"Prohibir",youHaveBeenBannedBy:"Has estat expulsat permanentment de %1$s per %2$s",youHaveBeenBanned:"Has estat expulsat permanentment de %s",privateActionLabel:"Xat privat",ignoreActionLabel:"Ignorar",unignoreActionLabel:"No ignorar",setSubjectActionLabel:"Canviar assumpte",administratorMessageSubject:"Administrador",userJoinedRoom:"%s ha entrat a la sala.",userLeftRoom:"%s ha deixat la sala.",userHasBeenKickedFromRoom:"%s ha estat expulsat de la sala.",userHasBeenBannedFromRoom:"%s ha estat expulsat permanentment de la sala.",presenceUnknownWarningSubject:"Atenció:",presenceUnknownWarning:"Aquest usuari podria estar desconnectat ...",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderador",tooltipIgnored:"Estàs ignorant aquest usuari",tooltipEmoticons:"Emoticones",tooltipSound:"Reproduir un so per a nous missatges",tooltipAutoscroll:"Desplaçament automàtic",tooltipStatusmessage:"Mostrar missatges d'estat",tooltipAdministration:"Administració de la sala",tooltipUsercount:"Usuaris dins la sala",enterRoomPassword:'La sala "%s" està protegida amb contrasenya.',enterRoomPasswordSubmit:"Entrar a la sala",passwordEnteredInvalid:'Contrasenya incorrecta per a la sala "%s".',nicknameConflict:"El nom d'usuari ja s'està utilitzant. Si us plau, escolleix-ne un altre.",errorMembersOnly:'No pots unir-te a la sala "%s": no tens prous privilegis.',errorMaxOccupantsReached:'No pots unir-te a la sala "%s": hi ha masses participants.',antiSpamMessage:"Si us plau, no facis spam. Has estat bloquejat temporalment."}}; + +//# sourceMappingURL=candy.min.map \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..f17bb3a --- /dev/null +++ b/index.html @@ -0,0 +1,69 @@ + + + + + IF XMPP chat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
            + + diff --git a/libs.min.js b/libs.min.js new file mode 100644 index 0000000..6c12560 --- /dev/null +++ b/libs.min.js @@ -0,0 +1,3 @@ +function b64_sha1(a){return binb2b64(core_sha1(str2binb(a),8*a.length))}function str_sha1(a){return binb2str(core_sha1(str2binb(a),8*a.length))}function b64_hmac_sha1(a,b){return binb2b64(core_hmac_sha1(a,b))}function str_hmac_sha1(a,b){return binb2str(core_hmac_sha1(a,b))}function core_sha1(a,b){a[b>>5]|=128<<24-b%32,a[(b+64>>9<<4)+15]=b;var c,d,e,f,g,h,i,j,k=new Array(80),l=1732584193,m=-271733879,n=-1732584194,o=271733878,p=-1009589776;for(c=0;cd;d++)k[d]=16>d?a[c+d]:rol(k[d-3]^k[d-8]^k[d-14]^k[d-16],1),e=safe_add(safe_add(rol(l,5),sha1_ft(d,m,n,o)),safe_add(safe_add(p,k[d]),sha1_kt(d))),p=o,o=n,n=rol(m,30),m=l,l=e;l=safe_add(l,f),m=safe_add(m,g),n=safe_add(n,h),o=safe_add(o,i),p=safe_add(p,j)}return[l,m,n,o,p]}function sha1_ft(a,b,c,d){return 20>a?b&c|~b&d:40>a?b^c^d:60>a?b&c|b&d|c&d:b^c^d}function sha1_kt(a){return 20>a?1518500249:40>a?1859775393:60>a?-1894007588:-899497514}function core_hmac_sha1(a,b){var c=str2binb(a);c.length>16&&(c=core_sha1(c,8*a.length));for(var d=new Array(16),e=new Array(16),f=0;16>f;f++)d[f]=909522486^c[f],e[f]=1549556828^c[f];var g=core_sha1(d.concat(str2binb(b)),512+8*b.length);return core_sha1(e.concat(g),672)}function safe_add(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c}function rol(a,b){return a<>>32-b}function str2binb(a){for(var b=[],c=255,d=0;d<8*a.length;d+=8)b[d>>5]|=(a.charCodeAt(d/8)&c)<<24-d%32;return b}function binb2str(a){for(var b="",c=255,d=0;d<32*a.length;d+=8)b+=String.fromCharCode(a[d>>5]>>>24-d%32&c);return b}function binb2b64(a){for(var b,c,d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",e="",f=0;f<4*a.length;f+=3)for(b=(a[f>>2]>>8*(3-f%4)&255)<<16|(a[f+1>>2]>>8*(3-(f+1)%4)&255)<<8|a[f+2>>2]>>8*(3-(f+2)%4)&255,c=0;4>c;c++)e+=8*f+6*c>32*a.length?"=":d.charAt(b>>6*(3-c)&63);return e}var Base64=function(){var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",b={encode:function(b){var c,d,e,f,g,h,i,j="",k=0;do c=b.charCodeAt(k++),d=b.charCodeAt(k++),e=b.charCodeAt(k++),f=c>>2,g=(3&c)<<4|d>>4,h=(15&d)<<2|e>>6,i=63&e,isNaN(d)?h=i=64:isNaN(e)&&(i=64),j=j+a.charAt(f)+a.charAt(g)+a.charAt(h)+a.charAt(i);while(k>4,d=(15&g)<<4|h>>2,e=(3&h)<<6|i,j+=String.fromCharCode(c),64!=h&&(j+=String.fromCharCode(d)),64!=i&&(j+=String.fromCharCode(e));while(k>16)+(b>>16)+(c>>16);return d<<16|65535&c},b=function(a,b){return a<>>32-b},c=function(a){for(var b=[],c=0;c<8*a.length;c+=8)b[c>>5]|=(255&a.charCodeAt(c/8))<>5]>>>c%32&255);return b},e=function(a){for(var b="0123456789abcdef",c="",d=0;d<4*a.length;d++)c+=b.charAt(a[d>>2]>>d%4*8+4&15)+b.charAt(a[d>>2]>>d%4*8&15);return c},f=function(c,d,e,f,g,h){return a(b(a(a(d,c),a(f,h)),g),e)},g=function(a,b,c,d,e,g,h){return f(b&c|~b&d,a,b,e,g,h)},h=function(a,b,c,d,e,g,h){return f(b&d|c&~d,a,b,e,g,h)},i=function(a,b,c,d,e,g,h){return f(b^c^d,a,b,e,g,h)},j=function(a,b,c,d,e,g,h){return f(c^(b|~d),a,b,e,g,h)},k=function(b,c){b[c>>5]|=128<>>9<<4)+14]=c;for(var d,e,f,k,l=1732584193,m=-271733879,n=-1732584194,o=271733878,p=0;pc?Math.ceil(c):Math.floor(c),0>c&&(c+=b);b>c;c++)if(c in this&&this[c]===a)return c;return-1}),function(a){function b(a,b){return new f.Builder(a,b)}function c(a){return new f.Builder("message",a)}function d(a){return new f.Builder("iq",a)}function e(a){return new f.Builder("presence",a)}var f;f={VERSION:"02c798f",NS:{HTTPBIND:"http://jabber.org/protocol/httpbind",BOSH:"urn:xmpp:xbosh",CLIENT:"jabber:client",AUTH:"jabber:iq:auth",ROSTER:"jabber:iq:roster",PROFILE:"jabber:iq:profile",DISCO_INFO:"http://jabber.org/protocol/disco#info",DISCO_ITEMS:"http://jabber.org/protocol/disco#items",MUC:"http://jabber.org/protocol/muc",SASL:"urn:ietf:params:xml:ns:xmpp-sasl",STREAM:"http://etherx.jabber.org/streams",BIND:"urn:ietf:params:xml:ns:xmpp-bind",SESSION:"urn:ietf:params:xml:ns:xmpp-session",VERSION:"jabber:iq:version",STANZAS:"urn:ietf:params:xml:ns:xmpp-stanzas",XHTML_IM:"http://jabber.org/protocol/xhtml-im",XHTML:"http://www.w3.org/1999/xhtml"},XHTML:{tags:["a","blockquote","br","cite","em","img","li","ol","p","span","strong","ul","body"],attributes:{a:["href"],blockquote:["style"],br:[],cite:["style"],em:[],img:["src","alt","style","height","width"],li:["style"],ol:["style"],p:["style"],span:["style"],strong:[],ul:["style"],body:[]},css:["background-color","color","font-family","font-size","font-style","font-weight","margin-left","margin-right","text-align","text-decoration"],validTag:function(a){for(var b=0;b0)for(var c=0;c/g,">"),a=a.replace(/'/g,"'"),a=a.replace(/"/g,""")},xmlTextNode:function(a){return f.xmlGenerator().createTextNode(a)},xmlHtmlNode:function(a){var b;if(window.DOMParser){var c=new DOMParser;b=c.parseFromString(a,"text/xml")}else b=new ActiveXObject("Microsoft.XMLDOM"),b.async="false",b.loadXML(a);return b},getText:function(a){if(!a)return null;var b="";0===a.childNodes.length&&a.nodeType==f.ElementType.TEXT&&(b+=a.nodeValue);for(var c=0;c0&&(h=i.join("; "),c.setAttribute(g,h))}else c.setAttribute(g,h);for(b=0;b/g,"\\3e").replace(/@/g,"\\40")},unescapeNode:function(a){return a.replace(/\\20/g," ").replace(/\\22/g,'"').replace(/\\26/g,"&").replace(/\\27/g,"'").replace(/\\2f/g,"/").replace(/\\3a/g,":").replace(/\\3c/g,"<").replace(/\\3e/g,">").replace(/\\40/g,"@").replace(/\\5c/g,"\\")},getNodeFromJid:function(a){return a.indexOf("@")<0?null:a.split("@")[0]},getDomainFromJid:function(a){var b=f.getBareJidFromJid(a);if(b.indexOf("@")<0)return b;var c=b.split("@");return c.splice(0,1),c.join("@")},getResourceFromJid:function(a){var b=a.split("/");return b.length<2?null:(b.splice(0,1),b.join("/"))},getBareJidFromJid:function(a){return a?a.split("/")[0]:null},log:function(){},debug:function(a){this.log(this.LogLevel.DEBUG,a)},info:function(a){this.log(this.LogLevel.INFO,a)},warn:function(a){this.log(this.LogLevel.WARN,a)},error:function(a){this.log(this.LogLevel.ERROR,a)},fatal:function(a){this.log(this.LogLevel.FATAL,a)},serialize:function(a){var b;if(!a)return null;"function"==typeof a.tree&&(a=a.tree());var c,d,e=a.nodeName;for(a.getAttribute("_realname")&&(e=a.getAttribute("_realname")),b="<"+e,c=0;c/g,">").replace(/0){for(b+=">",c=0;c"}b+=""}else b+="/>";return b},_requestId:0,_connectionPlugins:{},addConnectionPlugin:function(a,b){f._connectionPlugins[a]=b}},f.Builder=function(a,b){("presence"==a||"message"==a||"iq"==a)&&(b&&!b.xmlns?b.xmlns=f.NS.CLIENT:b||(b={xmlns:f.NS.CLIENT})),this.nodeTree=f.xmlElement(a,b),this.node=this.nodeTree},f.Builder.prototype={tree:function(){return this.nodeTree},toString:function(){return f.serialize(this.nodeTree)},up:function(){return this.node=this.node.parentNode,this},attrs:function(a){for(var b in a)a.hasOwnProperty(b)&&this.node.setAttribute(b,a[b]);return this},c:function(a,b,c){var d=f.xmlElement(a,b,c);return this.node.appendChild(d),c||(this.node=d),this},cnode:function(a){var b,c=f.xmlGenerator();try{b=void 0!==c.importNode}catch(d){b=!1}var e=b?c.importNode(a,!0):f.copyElement(a);return this.node.appendChild(e),this.node=e,this},t:function(a){var b=f.xmlTextNode(a);return this.node.appendChild(b),this},h:function(a){var b=document.createElement("body");b.innerHTML=a;for(var c=f.createHtml(b);c.childNodes.length>0;)this.node.appendChild(c.childNodes[0]);return this}},f.Handler=function(a,b,c,d,e,g,h){this.handler=a,this.ns=b,this.name=c,this.type=d,this.id=e,this.options=h||{matchBare:!1},this.options.matchBare||(this.options.matchBare=!1),this.from=this.options.matchBare?g?f.getBareJidFromJid(g):null:g,this.user=!0},f.Handler.prototype={isMatch:function(a){var b,c=null;if(c=this.options.matchBare?f.getBareJidFromJid(a.getAttribute("from")):a.getAttribute("from"),b=!1,this.ns){var d=this;f.forEachChild(a,null,function(a){a.getAttribute("xmlns")==d.ns&&(b=!0)}),b=b||a.getAttribute("xmlns")==this.ns}else b=!0;return!b||this.name&&!f.isTagEqual(a,this.name)||this.type&&a.getAttribute("type")!=this.type||this.id&&a.getAttribute("id")!=this.id||this.from&&c!=this.from?!1:!0},run:function(a){var b=null;try{b=this.handler(a)}catch(c){throw c.sourceURL?f.fatal("error: "+this.handler+" "+c.sourceURL+":"+c.line+" - "+c.name+": "+c.message):c.fileName?("undefined"!=typeof console&&(console.trace(),console.error(this.handler," - error - ",c,c.message)),f.fatal("error: "+this.handler+" "+c.fileName+":"+c.lineNumber+" - "+c.name+": "+c.message)):f.fatal("error: "+c.message+"\n"+c.stack),c}return b},toString:function(){return"{Handler: "+this.handler+"("+this.name+","+this.id+","+this.ns+")}"}},f.TimedHandler=function(a,b){this.period=a,this.handler=b,this.lastCalled=(new Date).getTime(),this.user=!0},f.TimedHandler.prototype={run:function(){return this.lastCalled=(new Date).getTime(),this.handler()},reset:function(){this.lastCalled=(new Date).getTime()},toString:function(){return"{TimedHandler: "+this.handler+"("+this.period+")}"}},f.Connection=function(a,b){this.service=a,this.options=b||{};var c=this.options.protocol||"";this._proto=0===a.indexOf("ws:")||0===a.indexOf("wss:")||0===c.indexOf("ws")?new f.Websocket(this):new f.Bosh(this),this.jid="",this.domain=null,this.features=null,this._sasl_data={},this.do_session=!1,this.do_bind=!1,this.timedHandlers=[],this.handlers=[],this.removeTimeds=[],this.removeHandlers=[],this.addTimeds=[],this.addHandlers=[],this._authentication={},this._idleTimeout=null,this._disconnectTimeout=null,this.do_authentication=!0,this.authenticated=!1,this.disconnecting=!1,this.connected=!1,this.errors=0,this.paused=!1,this._data=[],this._uniqueId=0,this._sasl_success_handler=null,this._sasl_failure_handler=null,this._sasl_challenge_handler=null,this.maxRetries=5,this._idleTimeout=setTimeout(this._onIdle.bind(this),100);for(var d in f._connectionPlugins)if(f._connectionPlugins.hasOwnProperty(d)){var e=f._connectionPlugins[d],g=function(){};g.prototype=e,this[d]=new g,this[d].init(this)}},f.Connection.prototype={reset:function(){this._proto._reset(),this.do_session=!1,this.do_bind=!1,this.timedHandlers=[],this.handlers=[],this.removeTimeds=[],this.removeHandlers=[],this.addTimeds=[],this.addHandlers=[],this._authentication={},this.authenticated=!1,this.disconnecting=!1,this.connected=!1,this.errors=0,this._requests=[],this._uniqueId=0},pause:function(){this.paused=!0},resume:function(){this.paused=!1},getUniqueId:function(a){return"string"==typeof a||"number"==typeof a?++this._uniqueId+":"+a:++this._uniqueId+""},connect:function(a,b,c,d,e,g){this.jid=a,this.authzid=f.getBareJidFromJid(this.jid),this.authcid=f.getNodeFromJid(this.jid),this.pass=b,this.servtype="xmpp",this.connect_callback=c,this.disconnecting=!1,this.connected=!1,this.authenticated=!1,this.errors=0,this.domain=f.getDomainFromJid(this.jid),this._changeConnectStatus(f.Status.CONNECTING,null),this._proto._connect(d,e,g)},attach:function(a,b,c,d,e,f,g){this._proto._attach(a,b,c,d,e,f,g)},xmlInput:function(){},xmlOutput:function(){},rawInput:function(){},rawOutput:function(){},send:function(a){if(null!==a){if("function"==typeof a.sort)for(var b=0;b0;)e=this.removeHandlers.pop(),d=this.handlers.indexOf(e),d>=0&&this.handlers.splice(d,1);for(;this.addHandlers.length>0;)this.handlers.push(this.addHandlers.pop());if(this.disconnecting&&this._proto._emptyQueue())return void this._doDisconnect();var g,h,i=c.getAttribute("type");if(null!==i&&"terminate"==i){if(this.disconnecting)return;return g=c.getAttribute("condition"),h=c.getElementsByTagName("conflict"),null!==g?("remote-stream-error"==g&&h.length>0&&(g="conflict"),this._changeConnectStatus(f.Status.CONNFAIL,g)):this._changeConnectStatus(f.Status.CONNFAIL,"unknown"),void this.disconnect("unknown stream-error")}var j=this;f.forEachChild(c,null,function(a){var b,c;for(c=j.handlers,j.handlers=[],b=0;b0;g||(g=d.getElementsByTagName("features").length>0);var h,i,j=d.getElementsByTagName("mechanism"),k=[],l=!1;if(!g)return void this._proto._no_auth_received(b);if(j.length>0)for(h=0;h0,(l=this._authentication.legacy_auth||k.length>0)?void(this.do_authentication!==!1&&this.authenticate(k)):void this._proto._no_auth_received(b)}}},authenticate:function(a){var c;for(c=0;ca[e].prototype.priority&&(e=g);if(e!=c){var h=a[c];a[c]=a[e],a[e]=h}}var i=!1;for(c=0;c0&&(b="conflict"),this._changeConnectStatus(f.Status.AUTHFAIL,b),!1}var e,g=a.getElementsByTagName("bind");return g.length>0?(e=g[0].getElementsByTagName("jid"),void(e.length>0&&(this.jid=f.getText(e[0]),this.do_session?(this._addSysHandler(this._sasl_session_cb.bind(this),null,null,null,"_session_auth_2"),this.send(d({type:"set",id:"_session_auth_2"}).c("session",{xmlns:f.NS.SESSION}).tree())):(this.authenticated=!0,this._changeConnectStatus(f.Status.CONNECTED,null))))):(f.info("SASL binding failed."),this._changeConnectStatus(f.Status.AUTHFAIL,null),!1)},_sasl_session_cb:function(a){if("result"==a.getAttribute("type"))this.authenticated=!0,this._changeConnectStatus(f.Status.CONNECTED,null);else if("error"==a.getAttribute("type"))return f.info("Session creation failed."),this._changeConnectStatus(f.Status.AUTHFAIL,null),!1;return!1},_sasl_failure_cb:function(){return this._sasl_success_handler&&(this.deleteHandler(this._sasl_success_handler),this._sasl_success_handler=null),this._sasl_challenge_handler&&(this.deleteHandler(this._sasl_challenge_handler),this._sasl_challenge_handler=null),this._sasl_mechanism&&this._sasl_mechanism.onFailure(),this._changeConnectStatus(f.Status.AUTHFAIL,null),!1},_auth2_cb:function(a){return"result"==a.getAttribute("type")?(this.authenticated=!0,this._changeConnectStatus(f.Status.CONNECTED,null)):"error"==a.getAttribute("type")&&(this._changeConnectStatus(f.Status.AUTHFAIL,null),this.disconnect("authentication failed")),!1},_addSysTimedHandler:function(a,b){var c=new f.TimedHandler(a,b);return c.user=!1,this.addTimeds.push(c),c},_addSysHandler:function(a,b,c,d,e){var g=new f.Handler(a,b,c,d,e);return g.user=!1,this.addHandlers.push(g),g},_onDisconnectTimeout:function(){return f.info("_onDisconnectTimeout was called"),this._proto._onDisconnectTimeout(),this._doDisconnect(),!1},_onIdle:function(){for(var a,b,c,d;this.addTimeds.length>0;)this.timedHandlers.push(this.addTimeds.pop());for(;this.removeTimeds.length>0;)b=this.removeTimeds.pop(),a=this.timedHandlers.indexOf(b),a>=0&&this.timedHandlers.splice(a,1);var e=(new Date).getTime();for(d=[],a=0;a=c-e?b.run()&&d.push(b):d.push(b));this.timedHandlers=d,clearTimeout(this._idleTimeout),this._proto._onIdle(),this.connected&&(this._idleTimeout=setTimeout(this._onIdle.bind(this),100))}},a&&a(f,b,c,d,e),f.SASLMechanism=function(a,b,c){this.name=a,this.isClientFirst=b,this.priority=c},f.SASLMechanism.prototype={test:function(){return!0},onStart:function(a){this._connection=a},onChallenge:function(){throw new Error("You should implement challenge handling!")},onFailure:function(){this._connection=null},onSuccess:function(){this._connection=null}},f.SASLAnonymous=function(){},f.SASLAnonymous.prototype=new f.SASLMechanism("ANONYMOUS",!1,10),f.SASLAnonymous.test=function(a){return null===a.authcid},f.Connection.prototype.mechanisms[f.SASLAnonymous.prototype.name]=f.SASLAnonymous,f.SASLPlain=function(){},f.SASLPlain.prototype=new f.SASLMechanism("PLAIN",!0,20),f.SASLPlain.test=function(a){return null!==a.authcid},f.SASLPlain.prototype.onChallenge=function(a){var b=a.authzid;return b+="\x00",b+=a.authcid,b+="\x00",b+=a.pass},f.Connection.prototype.mechanisms[f.SASLPlain.prototype.name]=f.SASLPlain,f.SASLSHA1=function(){},f.SASLSHA1.prototype=new f.SASLMechanism("SCRAM-SHA-1",!0,40),f.SASLSHA1.test=function(a){return null!==a.authcid},f.SASLSHA1.prototype.onChallenge=function(a,b,c){var d=c||MD5.hexdigest(1234567890*Math.random()),e="n="+a.authcid;return e+=",r=",e+=d,a._sasl_data.cnonce=d,a._sasl_data["client-first-message-bare"]=e,e="n,,"+e,this.onChallenge=function(a,b){for(var c,d,e,f,g,h,i,j,k,l,m,n="c=biws,",o=a._sasl_data["client-first-message-bare"]+","+b+",",p=a._sasl_data.cnonce,q=/([a-z]+)=([^,]+)(,|$)/;b.match(q);){var r=b.match(q);switch(b=b.replace(r[0],""),r[1]){case"r":c=r[2];break;case"s":d=r[2];break;case"i":e=r[2]}}if(c.substr(0,p.length)!==p)return a._sasl_data={},a._sasl_failure_cb();for(n+="r="+c,o+=n,d=Base64.decode(d),d+="\x00\x00\x00",f=h=core_hmac_sha1(a.pass,d),i=1;e>i;i++){for(g=core_hmac_sha1(a.pass,binb2str(h)),j=0;5>j;j++)f[j]^=g[j];h=g}for(f=binb2str(f),k=core_hmac_sha1(f,"Client Key"),l=str_hmac_sha1(f,"Server Key"),m=core_hmac_sha1(str_sha1(binb2str(k)),o),a._sasl_data["server-signature"]=b64_hmac_sha1(l,o),j=0;5>j;j++)k[j]^=m[j];return n+=",p="+Base64.encode(binb2str(k))}.bind(this),e},f.Connection.prototype.mechanisms[f.SASLSHA1.prototype.name]=f.SASLSHA1,f.SASLMD5=function(){},f.SASLMD5.prototype=new f.SASLMechanism("DIGEST-MD5",!1,30),f.SASLMD5.test=function(a){return null!==a.authcid},f.SASLMD5.prototype._quote=function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'},f.SASLMD5.prototype.onChallenge=function(a,b,c){for(var d,e=/([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/,f=c||MD5.hexdigest(""+1234567890*Math.random()),g="",h=null,i="",j="";b.match(e);)switch(d=b.match(e),b=b.replace(d[0],""),d[2]=d[2].replace(/^"(.+)"$/,"$1"),d[1]){case"realm":g=d[2]; +break;case"nonce":i=d[2];break;case"qop":j=d[2];break;case"host":h=d[2]}var k=a.servtype+"/"+a.domain;null!==h&&(k=k+"/"+h);var l=MD5.hash(a.authcid+":"+g+":"+this._connection.pass)+":"+i+":"+f,m="AUTHENTICATE:"+k,n="";return n+="charset=utf-8,",n+="username="+this._quote(a.authcid)+",",n+="realm="+this._quote(g)+",",n+="nonce="+this._quote(i)+",",n+="nc=00000001,",n+="cnonce="+this._quote(f)+",",n+="digest-uri="+this._quote(k)+",",n+="response="+MD5.hexdigest(MD5.hexdigest(l)+":"+i+":00000001:"+f+":auth:"+MD5.hexdigest(m))+",",n+="qop=auth",this.onChallenge=function(){return""}.bind(this),n},f.Connection.prototype.mechanisms[f.SASLMD5.prototype.name]=f.SASLMD5}(function(){window.Strophe=arguments[0],window.$build=arguments[1],window.$msg=arguments[2],window.$iq=arguments[3],window.$pres=arguments[4]}),Strophe.Request=function(a,b,c,d){this.id=++Strophe._requestId,this.xmlData=a,this.data=Strophe.serialize(a),this.origFunc=b,this.func=b,this.rid=c,this.date=0/0,this.sends=d||0,this.abort=!1,this.dead=null,this.age=function(){if(!this.date)return 0;var a=new Date;return(a-this.date)/1e3},this.timeDead=function(){if(!this.dead)return 0;var a=new Date;return(a-this.dead)/1e3},this.xhr=this._newXHR()},Strophe.Request.prototype={getResponse:function(){var a=null;if(this.xhr.responseXML&&this.xhr.responseXML.documentElement){if(a=this.xhr.responseXML.documentElement,"parsererror"==a.tagName)throw Strophe.error("invalid response received"),Strophe.error("responseText: "+this.xhr.responseText),Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML)),"parsererror"}else this.xhr.responseText&&(Strophe.error("invalid response received"),Strophe.error("responseText: "+this.xhr.responseText),Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML)));return a},_newXHR:function(){var a=null;return window.XMLHttpRequest?(a=new XMLHttpRequest,a.overrideMimeType&&a.overrideMimeType("text/xml")):window.ActiveXObject&&(a=new ActiveXObject("Microsoft.XMLHTTP")),a.onreadystatechange=this.func.bind(null,this),a}},Strophe.Bosh=function(a){this._conn=a,this.rid=Math.floor(4294967295*Math.random()),this.sid=null,this.hold=1,this.wait=60,this.window=5,this._requests=[]},Strophe.Bosh.prototype={strip:null,_buildBody:function(){var a=$build("body",{rid:this.rid++,xmlns:Strophe.NS.HTTPBIND});return null!==this.sid&&a.attrs({sid:this.sid}),a},_reset:function(){this.rid=Math.floor(4294967295*Math.random()),this.sid=null},_connect:function(a,b,c){this.wait=a||this.wait,this.hold=b||this.hold;var d=this._buildBody().attrs({to:this._conn.domain,"xml:lang":"en",wait:this.wait,hold:this.hold,content:"text/xml; charset=utf-8",ver:"1.6","xmpp:version":"1.0","xmlns:xmpp":Strophe.NS.BOSH});c&&d.attrs({route:c});var e=this._conn._connect_cb;this._requests.push(new Strophe.Request(d.tree(),this._onRequestStateChange.bind(this,e.bind(this._conn)),d.tree().getAttribute("rid"))),this._throttledRequestHandler()},_attach:function(a,b,c,d,e,f,g){this._conn.jid=a,this.sid=b,this.rid=c,this._conn.connect_callback=d,this._conn.domain=Strophe.getDomainFromJid(this._conn.jid),this._conn.authenticated=!0,this._conn.connected=!0,this.wait=e||this.wait,this.hold=f||this.hold,this.window=g||this.window,this._conn._changeConnectStatus(Strophe.Status.ATTACHED,null)},_connect_cb:function(a){var b,c,d=a.getAttribute("type");if(null!==d&&"terminate"==d)return Strophe.error("BOSH-Connection failed: "+b),b=a.getAttribute("condition"),c=a.getElementsByTagName("conflict"),null!==b?("remote-stream-error"==b&&c.length>0&&(b="conflict"),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,b)):this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown"),this._conn._doDisconnect(),Strophe.Status.CONNFAIL;this.sid||(this.sid=a.getAttribute("sid"));var e=a.getAttribute("requests");e&&(this.window=parseInt(e,10));var f=a.getAttribute("hold");f&&(this.hold=parseInt(f,10));var g=a.getAttribute("wait");g&&(this.wait=parseInt(g,10))},_disconnect:function(a){this._sendTerminate(a)},_doDisconnect:function(){this.sid=null,this.rid=Math.floor(4294967295*Math.random())},_emptyQueue:function(){return 0===this._requests.length},_hitError:function(a){this.errors++,Strophe.warn("request errored, status: "+a+", number of errors: "+this.errors),this.errors>4&&this._onDisconnectTimeout()},_no_auth_received:function(a){a=a?a.bind(this._conn):this._conn._connect_cb.bind(this._conn);var b=this._buildBody();this._requests.push(new Strophe.Request(b.tree(),this._onRequestStateChange.bind(this,a.bind(this._conn)),b.tree().getAttribute("rid"))),this._throttledRequestHandler()},_onDisconnectTimeout:function(){for(var a;this._requests.length>0;)a=this._requests.pop(),a.abort=!0,a.xhr.abort(),a.xhr.onreadystatechange=function(){}},_onIdle:function(){var a=this._conn._data;if(this._conn.authenticated&&0===this._requests.length&&0===a.length&&!this._conn.disconnecting&&(Strophe.info("no requests during idle cycle, sending blank request"),a.push(null)),this._requests.length<2&&a.length>0&&!this._conn.paused){for(var b=this._buildBody(),c=0;c0){var d=this._requests[0].age();null!==this._requests[0].dead&&this._requests[0].timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait)&&this._throttledRequestHandler(),d>Math.floor(Strophe.TIMEOUT*this.wait)&&(Strophe.warn("Request "+this._requests[0].id+" timed out, over "+Math.floor(Strophe.TIMEOUT*this.wait)+" seconds since last activity"),this._throttledRequestHandler())}},_onRequestStateChange:function(a,b){if(Strophe.debug("request id "+b.id+"."+b.sends+" state changed to "+b.xhr.readyState),b.abort)return void(b.abort=!1);var c;if(4==b.xhr.readyState){c=0;try{c=b.xhr.status}catch(d){}if("undefined"==typeof c&&(c=0),this.disconnecting&&c>=400)return void this._hitError(c);var e=this._requests[0]==b,f=this._requests[1]==b;(c>0&&500>c||b.sends>5)&&(this._removeRequest(b),Strophe.debug("request id "+b.id+" should now be removed")),200==c?((f||e&&this._requests.length>0&&this._requests[0].age()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait))&&this._restartRequest(0),Strophe.debug("request id "+b.id+"."+b.sends+" got 200"),a(b),this.errors=0):(Strophe.error("request id "+b.id+"."+b.sends+" error "+c+" happened"),(0===c||c>=400&&600>c||c>=12e3)&&(this._hitError(c),c>=400&&500>c&&(this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING,null),this._conn._doDisconnect()))),c>0&&500>c||b.sends>5||this._throttledRequestHandler()}},_processRequest:function(a){var b=this,c=this._requests[a],d=-1;try{4==c.xhr.readyState&&(d=c.xhr.status)}catch(e){Strophe.error("caught an error in _requests["+a+"], reqStatus: "+d)}if("undefined"==typeof d&&(d=-1),c.sends>this.maxRetries)return void this._onDisconnectTimeout();var f=c.age(),g=!isNaN(f)&&f>Math.floor(Strophe.TIMEOUT*this.wait),h=null!==c.dead&&c.timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait),i=4==c.xhr.readyState&&(1>d||d>=500);if((g||h||i)&&(h&&Strophe.error("Request "+this._requests[a].id+" timed out (secondary), restarting"),c.abort=!0,c.xhr.abort(),c.xhr.onreadystatechange=function(){},this._requests[a]=new Strophe.Request(c.xmlData,c.origFunc,c.rid,c.sends),c=this._requests[a]),0===c.xhr.readyState){Strophe.debug("request id "+c.id+"."+c.sends+" posting");try{c.xhr.open("POST",this._conn.service,this._conn.options.sync?!1:!0)}catch(j){return Strophe.error("XHR open failed."),this._conn.connected||this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"bad-service"),void this._conn.disconnect()}var k=function(){if(c.date=new Date,b._conn.options.customHeaders){var a=b._conn.options.customHeaders;for(var d in a)a.hasOwnProperty(d)&&c.xhr.setRequestHeader(d,a[d])}c.xhr.send(c.data)};if(c.sends>1){var l=1e3*Math.min(Math.floor(Strophe.TIMEOUT*this.wait),Math.pow(c.sends,3));setTimeout(k,l)}else k();c.sends++,this._conn.xmlOutput!==Strophe.Connection.prototype.xmlOutput&&this._conn.xmlOutput(c.xmlData.nodeName===this.strip&&c.xmlData.childNodes.length?c.xmlData.childNodes[0]:c.xmlData),this._conn.rawOutput!==Strophe.Connection.prototype.rawOutput&&this._conn.rawOutput(c.data)}else Strophe.debug("_processRequest: "+(0===a?"first":"second")+" request has readyState of "+c.xhr.readyState)},_removeRequest:function(a){Strophe.debug("removing request");var b;for(b=this._requests.length-1;b>=0;b--)a==this._requests[b]&&this._requests.splice(b,1);a.xhr.onreadystatechange=function(){},this._throttledRequestHandler()},_restartRequest:function(a){var b=this._requests[a];null===b.dead&&(b.dead=new Date),this._processRequest(a)},_reqToData:function(a){try{return a.getResponse()}catch(b){if("parsererror"!=b)throw b;this._conn.disconnect("strophe-parsererror")}},_sendTerminate:function(a){Strophe.info("_sendTerminate was called");var b=this._buildBody().attrs({type:"terminate"});a&&b.cnode(a.tree());var c=new Strophe.Request(b.tree(),this._onRequestStateChange.bind(this,this._conn._dataRecv.bind(this._conn)),b.tree().getAttribute("rid"));this._requests.push(c),this._throttledRequestHandler()},_send:function(){clearTimeout(this._conn._idleTimeout),this._throttledRequestHandler(),this._conn._idleTimeout=setTimeout(this._conn._onIdle.bind(this._conn),100)},_sendRestart:function(){this._throttledRequestHandler(),clearTimeout(this._conn._idleTimeout)},_throttledRequestHandler:function(){Strophe.debug(this._requests?"_throttledRequestHandler called with "+this._requests.length+" requests":"_throttledRequestHandler called with undefined requests"),this._requests&&0!==this._requests.length&&(this._requests.length>0&&this._processRequest(0),this._requests.length>1&&Math.abs(this._requests[0].rid-this._requests[1].rid)\s*)*/,"");if(""===b)return;b=a.data.replace(//,"");var c=(new DOMParser).parseFromString(b,"text/xml").documentElement;this._conn.xmlInput(c),this._conn.rawInput(a.data),this._handleStreamStart(c)&&(this._connect_cb(c),this.streamStart=a.data.replace(/^$/,""))}else{if(""===a.data)return this._conn.rawInput(a.data),this._conn.xmlInput(document.createElement("stream:stream")),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"Received closing stream"),void this._conn._doDisconnect();var d=this._streamWrap(a.data),e=(new DOMParser).parseFromString(d,"text/xml").documentElement;this.socket.onmessage=this._onMessage.bind(this),this._conn._connect_cb(e,null,a.data)}},_disconnect:function(a){if(this.socket.readyState!==WebSocket.CLOSED){a&&this._conn.send(a);var b="";this._conn.xmlOutput(document.createElement("stream:stream")),this._conn.rawOutput(b);try{this.socket.send(b)}catch(c){Strophe.info("Couldn't send closing stream tag.")}}this._conn._doDisconnect()},_doDisconnect:function(){Strophe.info("WebSockets _doDisconnect was called"),this._closeSocket()},_streamWrap:function(a){return this.streamStart+a+""},_closeSocket:function(){if(this.socket)try{this.socket.close()}catch(a){}this.socket=null},_emptyQueue:function(){return!0},_onClose:function(){this._conn.connected&&!this._conn.disconnecting?(Strophe.error("Websocket closed unexcectedly"),this._conn._doDisconnect()):Strophe.info("Websocket closed")},_no_auth_received:function(a){Strophe.error("Server did not send any auth methods"),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"Server did not send any auth methods"),a&&(a=a.bind(this._conn))(),this._conn._doDisconnect()},_onDisconnectTimeout:function(){},_onError:function(a){Strophe.error("Websocket error "+a),this._conn._changeConnectStatus(Strophe.Status.CONNFAIL,"The WebSocket connection could not be established was disconnected."),this._disconnect()},_onIdle:function(){var a=this._conn._data;if(a.length>0&&!this._conn.paused){for(var b=0;b"===a.data){var d="";return this._conn.rawInput(d),this._conn.xmlInput(document.createElement("stream:stream")),void(this._conn.disconnecting||this._conn._doDisconnect())}if(0===a.data.search("/,""),b=(new DOMParser).parseFromString(c,"text/xml").documentElement,!this._handleStreamStart(b))return}else c=this._streamWrap(a.data),b=(new DOMParser).parseFromString(c,"text/xml").documentElement;if(!this._check_streamerror(b,Strophe.Status.ERROR))return this._conn.disconnecting&&"presence"===b.firstChild.nodeName&&"unavailable"===b.firstChild.getAttribute("type")?(this._conn.xmlInput(b),void this._conn.rawInput(Strophe.serialize(b))):void this._conn._dataRecv(b,a.data)},_onOpen:function(){Strophe.info("Websocket open");var a=this._buildStream();this._conn.xmlOutput(a.tree());var b=this._removeClosingTag(a);this._conn.rawOutput(b),this.socket.send(b)},_removeClosingTag:function(a){var b=Strophe.serialize(a);return b=b.replace(/<(stream:stream .*[^\/])\/>$/,"<$1>")},_reqToData:function(a){return a},_send:function(){this._conn.flush()},_sendRestart:function(){clearTimeout(this._conn._idleTimeout),this._conn._onIdle.bind(this._conn)()}},function(){var a,b,c,d=function(a,b){return function(){return a.apply(b,arguments)}};Strophe.addConnectionPlugin("muc",{_connection:null,rooms:{},roomNames:[],init:function(a){return this._connection=a,this._muc_handler=null,Strophe.addNamespace("MUC_OWNER",Strophe.NS.MUC+"#owner"),Strophe.addNamespace("MUC_ADMIN",Strophe.NS.MUC+"#admin"),Strophe.addNamespace("MUC_USER",Strophe.NS.MUC+"#user"),Strophe.addNamespace("MUC_ROOMCONF",Strophe.NS.MUC+"#roomconfig")},join:function(a,b,d,e,f,g,h){var i,j;return j=this.test_append_nick(a,b),i=$pres({from:this._connection.jid,to:j}).c("x",{xmlns:Strophe.NS.MUC}),null!=h&&(i=i.c("history",h).up),null!=g&&i.cnode(Strophe.xmlElement("password",[],g)),"undefined"!=typeof extended_presence&&null!==extended_presence&&i.up.cnode(extended_presence),null==this._muc_handler&&(this._muc_handler=this._connection.addHandler(function(b){return function(c){var d,e,f,g,h,i,j,k,l,m;if(d=c.getAttribute("from"),!d)return!0;if(h=d.split("/")[0],!b.rooms[h])return!0;if(a=b.rooms[h],f={},"message"===c.nodeName)f=a._message_handlers;else if("presence"===c.nodeName&&(k=c.getElementsByTagName("x"),k.length>0))for(l=0,m=k.length;m>l;l++)if(i=k[l],j=i.getAttribute("xmlns"),j&&j.match(Strophe.NS.MUC)){f=a._presence_handlers;break}for(g in f)e=f[g],e(c,a)||delete f[g];return!0}}(this))),this.rooms.hasOwnProperty(a)||(this.rooms[a]=new c(this,a,b,g),this.roomNames.push(a)),e&&this.rooms[a].addHandler("presence",e),d&&this.rooms[a].addHandler("message",d),f&&this.rooms[a].addHandler("roster",f),this._connection.send(i)},leave:function(a,b,c,d){var e,f,g,h;return e=this.roomNames.indexOf(a),delete this.rooms[a],e>=0&&(this.roomNames.splice(e,1),0===this.roomNames.length&&(this._connection.deleteHandler(this._muc_handler),this._muc_handler=null)),h=this.test_append_nick(a,b),g=this._connection.getUniqueId(),f=$pres({type:"unavailable",id:g,from:this._connection.jid,to:h}),null!=d&&f.c("status",d),null!=c&&this._connection.addHandler(c,null,"presence",null,g),this._connection.send(f),g},message:function(a,b,c,d,e){var f,g,h,i;return i=this.test_append_nick(a,b),e=e||(null!=b?"chat":"groupchat"),g=this._connection.getUniqueId(),f=$msg({to:i,from:this._connection.jid,type:e,id:g}).c("body",{xmlns:Strophe.NS.CLIENT}).t(c),f.up(),null!=d&&(f.c("html",{xmlns:Strophe.NS.XHTML_IM}).c("body",{xmlns:Strophe.NS.XHTML}).h(d),0===f.node.childNodes.length?(h=f.node.parentNode,f.up().up(),f.node.removeChild(h)):f.up().up()),f.c("x",{xmlns:"jabber:x:event"}).c("composing"),this._connection.send(f),g},groupchat:function(a,b,c){return this.message(a,null,b,c)},invite:function(a,b,c){var d,e;return e=this._connection.getUniqueId(),d=$msg({from:this._connection.jid,to:a,id:e}).c("x",{xmlns:Strophe.NS.MUC_USER}).c("invite",{to:b}),null!=c&&d.c("reason",c),this._connection.send(d),e},directInvite:function(a,b,c,d){var e,f,g;return g=this._connection.getUniqueId(),e={xmlns:"jabber:x:conference",jid:a},null!=c&&(e.reason=c),null!=d&&(e.password=d),f=$msg({from:this._connection.jid,to:b,id:g}).c("x",e),this._connection.send(f),g},queryOccupants:function(a,b,c){var d,e;return d={xmlns:Strophe.NS.DISCO_ITEMS},e=$iq({from:this._connection.jid,to:a,type:"get"}).c("query",d),this._connection.sendIQ(e,b,c)},configure:function(a,b,c){var d,e;return d=$iq({to:a,type:"get"}).c("query",{xmlns:Strophe.NS.MUC_OWNER}),e=d.tree(),this._connection.sendIQ(e,b,c)},cancelConfigure:function(a){var b,c;return b=$iq({to:a,type:"set"}).c("query",{xmlns:Strophe.NS.MUC_OWNER}).c("x",{xmlns:"jabber:x:data",type:"cancel"}),c=b.tree(),this._connection.sendIQ(c)},saveConfiguration:function(a,b,c,d){var e,f,g,h,i;if(f=$iq({to:a,type:"set"}).c("query",{xmlns:Strophe.NS.MUC_OWNER}),"undefined"!=typeof Form&&b instanceof Form)b.type="submit",f.cnode(b.toXML());else for(f.c("x",{xmlns:"jabber:x:data",type:"submit"}),h=0,i=b.length;i>h;h++)e=b[h],f.cnode(e).up();return g=f.tree(),this._connection.sendIQ(g,c,d)},createInstantRoom:function(a,b,c){var d;return d=$iq({to:a,type:"set"}).c("query",{xmlns:Strophe.NS.MUC_OWNER}).c("x",{xmlns:"jabber:x:data",type:"submit"}),this._connection.sendIQ(d.tree(),b,c)},setTopic:function(a,b){var c;return c=$msg({to:a,from:this._connection.jid,type:"groupchat"}).c("subject",{xmlns:"jabber:client"}).t(b),this._connection.send(c.tree())},_modifyPrivilege:function(a,b,c,d,e){var f;return f=$iq({to:a,type:"set"}).c("query",{xmlns:Strophe.NS.MUC_ADMIN}).cnode(b.node),null!=c&&f.c("reason",c),this._connection.sendIQ(f.tree(),d,e)},modifyRole:function(a,b,c,d,e,f){var g;return g=$build("item",{nick:b,role:c}),this._modifyPrivilege(a,g,d,e,f)},kick:function(a,b,c,d,e){return this.modifyRole(a,b,"none",c,d,e)},voice:function(a,b,c,d,e){return this.modifyRole(a,b,"participant",c,d,e)},mute:function(a,b,c,d,e){return this.modifyRole(a,b,"visitor",c,d,e)},op:function(a,b,c,d,e){return this.modifyRole(a,b,"moderator",c,d,e)},deop:function(a,b,c,d,e){return this.modifyRole(a,b,"participant",c,d,e)},modifyAffiliation:function(a,b,c,d,e,f){var g;return g=$build("item",{jid:b,affiliation:c}),this._modifyPrivilege(a,g,d,e,f)},ban:function(a,b,c,d,e){return this.modifyAffiliation(a,b,"outcast",c,d,e)},member:function(a,b,c,d,e){return this.modifyAffiliation(a,b,"member",c,d,e)},revoke:function(a,b,c,d,e){return this.modifyAffiliation(a,b,"none",c,d,e)},owner:function(a,b,c,d,e){return this.modifyAffiliation(a,b,"owner",c,d,e)},admin:function(a,b,c,d,e){return this.modifyAffiliation(a,b,"admin",c,d,e)},changeNick:function(a,b){var c,d;return d=this.test_append_nick(a,b),c=$pres({from:this._connection.jid,to:d,id:this._connection.getUniqueId()}),this._connection.send(c.tree())},setStatus:function(a,b,c,d){var e,f;return f=this.test_append_nick(a,b),e=$pres({from:this._connection.jid,to:f}),null!=c&&e.c("show",c).up(),null!=d&&e.c("status",d),this._connection.send(e.tree())},listRooms:function(a,b,c){var d;return d=$iq({to:a,from:this._connection.jid,type:"get"}).c("query",{xmlns:Strophe.NS.DISCO_ITEMS}),this._connection.sendIQ(d,b,c)},test_append_nick:function(a,b){var c,d;return d=Strophe.escapeNode(Strophe.getNodeFromJid(a)),c=Strophe.getDomainFromJid(a),d+"@"+c+(null!=b?"/"+b:"")}}),c=function(){function b(a,b,c,e){this.client=a,this.name=b,this.nick=c,this.password=e,this._roomRosterHandler=d(this._roomRosterHandler,this),this._addOccupant=d(this._addOccupant,this),this.roster={},this._message_handlers={},this._presence_handlers={},this._roster_handlers={},this._handler_ids=0,a.muc&&(this.client=a.muc),this.name=Strophe.getBareJidFromJid(b),this.addHandler("presence",this._roomRosterHandler)}return b.prototype.join=function(a,b,c){return this.client.join(this.name,this.nick,a,b,c,this.password)},b.prototype.leave=function(a,b){return this.client.leave(this.name,this.nick,a,b),delete this.client.rooms[this.name]},b.prototype.message=function(a,b,c,d){return this.client.message(this.name,a,b,c,d)},b.prototype.groupchat=function(a,b){return this.client.groupchat(this.name,a,b)},b.prototype.invite=function(a,b){return this.client.invite(this.name,a,b)},b.prototype.directInvite=function(a,b){return this.client.directInvite(this.name,a,b,this.password)},b.prototype.configure=function(a){return this.client.configure(this.name,a)},b.prototype.cancelConfigure=function(){return this.client.cancelConfigure(this.name)},b.prototype.saveConfiguration=function(a){return this.client.saveConfiguration(this.name,a)},b.prototype.queryOccupants=function(a,b){return this.client.queryOccupants(this.name,a,b)},b.prototype.setTopic=function(a){return this.client.setTopic(this.name,a)},b.prototype.modifyRole=function(a,b,c,d,e){return this.client.modifyRole(this.name,a,b,c,d,e)},b.prototype.kick=function(a,b,c,d){return this.client.kick(this.name,a,b,c,d)},b.prototype.voice=function(a,b,c,d){return this.client.voice(this.name,a,b,c,d)},b.prototype.mute=function(a,b,c,d){return this.client.mute(this.name,a,b,c,d)},b.prototype.op=function(a,b,c,d){return this.client.op(this.name,a,b,c,d)},b.prototype.deop=function(a,b,c,d){return this.client.deop(this.name,a,b,c,d)},b.prototype.modifyAffiliation=function(a,b,c,d,e){return this.client.modifyAffiliation(this.name,a,b,c,d,e)},b.prototype.ban=function(a,b,c,d){return this.client.ban(this.name,a,b,c,d)},b.prototype.member=function(a,b,c,d){return this.client.member(this.name,a,b,c,d)},b.prototype.revoke=function(a,b,c,d){return this.client.revoke(this.name,a,b,c,d)},b.prototype.owner=function(a,b,c,d){return this.client.owner(this.name,a,b,c,d)},b.prototype.admin=function(a,b,c,d){return this.client.admin(this.name,a,b,c,d)},b.prototype.changeNick=function(a){return this.nick=a,this.client.changeNick(this.name,a)},b.prototype.setStatus=function(a,b){return this.client.setStatus(this.name,this.nick,a,b)},b.prototype.addHandler=function(a,b){var c;switch(c=this._handler_ids++,a){case"presence":this._presence_handlers[c]=b;break;case"message":this._message_handlers[c]=b;break;case"roster":this._roster_handlers[c]=b;break;default:return this._handler_ids--,null}return c},b.prototype.removeHandler=function(a){return delete this._presence_handlers[a],delete this._message_handlers[a],delete this._roster_handlers[a]},b.prototype._addOccupant=function(b){var c;return c=new a(b,this),this.roster[c.nick]=c,c},b.prototype._roomRosterHandler=function(a){var c,d,e,f,g,h;switch(c=b._parsePresence(a),g=c.nick,f=c.newnick||null,c.type){case"error":return;case"unavailable":f&&(c.nick=f,this.roster[g]&&this.roster[f]&&(this.roster[g].update(this.roster[f]),this.roster[f]=this.roster[g]),this.roster[g]&&!this.roster[f]&&(this.roster[f]=this.roster[g].update(c))),delete this.roster[g];break;default:this.roster[g]?this.roster[g].update(c):this._addOccupant(c)}h=this._roster_handlers;for(e in h)d=h[e],d(this.roster,this)||delete this._roster_handlers[e];return!0},b._parsePresence=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q;for(e={},b=a.attributes,e.nick=Strophe.getResourceFromJid(b.from.textContent),e.type=(null!=(j=b.type)?j.textContent:void 0)||null,e.states=[],k=a.childNodes,f=0,h=k.length;h>f;f++)switch(c=k[f],c.nodeName){case"status":e.status=c.textContent||null;break;case"show":e.show=c.textContent||null;break;case"x":if(b=c.attributes,(null!=(l=b.xmlns)?l.textContent:void 0)===Strophe.NS.MUC_USER)for(m=c.childNodes,g=0,i=m.length;i>g;g++)switch(d=m[g],d.nodeName){case"item":b=d.attributes,e.affiliation=(null!=(n=b.affiliation)?n.textContent:void 0)||null,e.role=(null!=(o=b.role)?o.textContent:void 0)||null,e.jid=(null!=(p=b.jid)?p.textContent:void 0)||null,e.newnick=(null!=(q=b.nick)?q.textContent:void 0)||null;break;case"status":d.attributes.code&&e.states.push(d.attributes.code.textContent)}}return e},b}(),b=function(){function a(a){this.parse=d(this.parse,this),null!=a&&this.parse(a)}return a.prototype.parse=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n;for(g=a.getElementsByTagName("query")[0].childNodes,this.identities=[],this.features=[],this.x=[],h=0,k=g.length;k>h;h++)switch(d=g[h],c=d.attributes,d.nodeName){case"identity":for(f={},i=0,l=c.length;l>i;i++)b=c[i],f[b.name]=b.textContent;this.identities.push(f);break;case"feature":this.features.push(c["var"].textContent);break;case"x":if(c=d.childNodes[0].attributes,"FORM_TYPE"===!c["var"].textContent||"hidden"===!c.type.textContent)break;for(n=d.childNodes,j=0,m=n.length;m>j;j++)e=n[j],e.attributes.type||(c=e.attributes,this.x.push({"var":c["var"].textContent,label:c.label.textContent||"",value:e.firstChild.textContent||""}))}return{identities:this.identities,features:this.features,x:this.x}},a}(),a=function(){function a(a,b){this.room=b,this.update=d(this.update,this),this.admin=d(this.admin,this),this.owner=d(this.owner,this),this.revoke=d(this.revoke,this),this.member=d(this.member,this),this.ban=d(this.ban,this),this.modifyAffiliation=d(this.modifyAffiliation,this),this.deop=d(this.deop,this),this.op=d(this.op,this),this.mute=d(this.mute,this),this.voice=d(this.voice,this),this.kick=d(this.kick,this),this.modifyRole=d(this.modifyRole,this),this.update(a)}return a.prototype.modifyRole=function(a,b,c,d){return this.room.modifyRole(this.nick,a,b,c,d)},a.prototype.kick=function(a,b,c){return this.room.kick(this.nick,a,b,c)},a.prototype.voice=function(a,b,c){return this.room.voice(this.nick,a,b,c)},a.prototype.mute=function(a,b,c){return this.room.mute(this.nick,a,b,c)},a.prototype.op=function(a,b,c){return this.room.op(this.nick,a,b,c)},a.prototype.deop=function(a,b,c){return this.room.deop(this.nick,a,b,c)},a.prototype.modifyAffiliation=function(a,b,c,d){return this.room.modifyAffiliation(this.jid,a,b,c,d)},a.prototype.ban=function(a,b,c){return this.room.ban(this.jid,a,b,c)},a.prototype.member=function(a,b,c){return this.room.member(this.jid,a,b,c)},a.prototype.revoke=function(a,b,c){return this.room.revoke(this.jid,a,b,c)},a.prototype.owner=function(a,b,c){return this.room.owner(this.jid,a,b,c)},a.prototype.admin=function(a,b,c){return this.room.admin(this.jid,a,b,c)},a.prototype.update=function(a){return this.nick=a.nick||null,this.affiliation=a.affiliation||null,this.role=a.role||null,this.jid=a.jid||null,this.status=a.status||null,this.show=a.show||null,this},a}()}.call(this),Strophe.addConnectionPlugin("disco",{_connection:null,_identities:[],_features:[],_items:[],init:function(a){this._connection=a,this._identities=[],this._features=[],this._items=[],a.addHandler(this._onDiscoInfo.bind(this),Strophe.NS.DISCO_INFO,"iq","get",null,null),a.addHandler(this._onDiscoItems.bind(this),Strophe.NS.DISCO_ITEMS,"iq","get",null,null)},addIdentity:function(a,b,c,d){for(var e=0;ef;f++){var g=b[f];a+=g.category+"/"+g.type+"/"+g.lang+"/"+g.name+"<"}for(var f=0;e>f;f++)a+=d[f]+"<";return this._ver=b64_sha1(a),this._ver},getCapabilitiesByJid:function(a){return this._jidVerIndex[a]?this._knownCapabilities[this._jidVerIndex[a]]:null},_delegateCapabilities:function(a){var b=a.getAttribute("from"),c=a.querySelector("c"),d=c.getAttribute("ver"),e=c.getAttribute("node");return this._knownCapabilities[d]?(this._jidVerIndex[b]=d,this._jidVerIndex[b]&&!this._jidVerIndex[b]===d||(this._jidVerIndex[b]=d),!0):this._requestCapabilities(b,e,d)},_requestCapabilities:function(a,b,c){if(a!==this._connection.jid){var d=this._connection.disco.info(a,b+"#"+c);this._connection.addHandler(this._handleDiscoInfoReply.bind(this),Strophe.NS.DISCO_INFO,"iq","result",d,a)}return!0},_handleDiscoInfoReply:function(a){var b=a.querySelector("query"),c=b.getAttribute("node").split("#"),d=c[1],e=a.getAttribute("from");if(this._knownCapabilities[d])this._jidVerIndex[e]&&!this._jidVerIndex[e]===d||(this._jidVerIndex[e]=d);else{var f=b.childNodes,g=f.length;this._knownCapabilities[d]=[];for(var h=0;g>h;h++){var c=f[h];this._knownCapabilities[d].push({name:c.nodeName,attributes:c.attributes})}this._jidVerIndex[e]=d}return!1},_sortIdentities:function(a,b){return a.category>b.category?1:a.categoryb.type?1:a.typeb.lang?1:a.lang|\\{|%)?([^\\/#\\^]+?)\\1?"+e.ctag+"+","g")},g=f(),h=function(a,d,h){switch(d){case"!":return"";case"=":return e.set_delimiters(h),g=f(),"";case">":return e.render_partial(h,b,c);case"{":return e.find(h,b);default:return e.escape(e.find(h,b))}},i=a.split("\n"),j=0;j\\]/g,function(a){switch(a){case"&":return"&";case"\\":return"\\\\";case'"':return""";case"'":return"'";case"<":return"<";case">":return">";default:return a}})},create_context:function(a){if(this.is_object(a))return a;var b=".";this.pragmas["IMPLICIT-ITERATOR"]&&(b=this.pragmas["IMPLICIT-ITERATOR"].iterator);var c={};return c[b]=a,c},is_object:function(a){return a&&"object"==typeof a},is_array:function(a){return"[object Array]"===Object.prototype.toString.call(a)},trim:function(a){return a.replace(/^\s*|\s*$/g,"")},map:function(a,b){if("function"==typeof a.map)return a.map(b);for(var c=[],d=a.length,e=0;d>e;e++)c.push(b(a[e]));return c}},{name:"mustache.js",version:"0.3.1-dev",to_html:function(b,c,d,e){var f=new a;return e&&(f.send=e),f.render(b,c,d),e?void 0:f.buffer.join("\n")}}}();!function(a){var b=Array.prototype.slice,c={dict:null,load:function(b){null!==this.dict?a.extend(this.dict,b):this.dict=b},_:function(a){return dict=this.dict,dict&&dict.hasOwnProperty(a)&&(a=dict[a]),args=b.call(arguments),args[0]=a,this.printf.apply(this,args)},printf:function(c,d){return arguments.length<2?c:(d=a.isArray(d)?d:b.call(arguments,1),c.replace(/([^%]|^)%(?:(\d+)\$)?s/g,function(a,b,c){return c?b+d[parseInt(c)-1]:b+d.shift()}).replace(/%%s/g,"%s"))}};a.fn._t=function(){return a(this).html(c._.apply(c,arguments))},a.i18n=c}(jQuery);var dateFormat=function(){var a=/d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,b=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,c=/[^-+\dA-Z]/g,d=function(a,b){for(a=String(a),b=b||2;a.length99?Math.round(q/10):q),t:12>n?"a":"p",tt:12>n?"am":"pm",T:12>n?"A":"P",TT:12>n?"AM":"PM",Z:g?"UTC":(String(e).match(b)||[""]).pop().replace(c,""),o:(r>0?"-":"+")+d(100*Math.floor(Math.abs(r)/60)+Math.abs(r)%60,4),S:["th","st","nd","rd"][j%10>3?0:(j%100-j%10!=10)*j%10]};return f.replace(a,function(a){return a in s?s[a]:a.slice(1,a.length-1)})}}();dateFormat.masks={"default":"ddd mmm dd yyyy HH:MM:ss",shortDate:"m/d/yy",mediumDate:"mmm d, yyyy",longDate:"mmmm d, yyyy",fullDate:"dddd, mmmm d, yyyy",shortTime:"h:MM TT",mediumTime:"h:MM:ss TT",longTime:"h:MM:ss TT Z",isoDate:"yyyy-mm-dd",isoTime:"HH:MM:ss",isoDateTime:"yyyy-mm-dd'T'HH:MM:ss",isoUtcDateTime:"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"},dateFormat.i18n={dayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","January","February","March","April","May","June","July","August","September","October","November","December"]},Date.prototype.format=function(a,b){return dateFormat(this,a,b)}; \ No newline at end of file diff --git a/res/audioplayer.swf b/res/audioplayer.swf new file mode 100644 index 0000000..72390d4 Binary files /dev/null and b/res/audioplayer.swf differ diff --git a/res/default.css b/res/default.css new file mode 100644 index 0000000..a780826 --- /dev/null +++ b/res/default.css @@ -0,0 +1,674 @@ +/** + * Chat CSS + * + * @author Michael + * @author Patrick + + * @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; +} diff --git a/res/img/action/autoscroll-off.png b/res/img/action/autoscroll-off.png new file mode 100644 index 0000000..a0b8aa6 Binary files /dev/null and b/res/img/action/autoscroll-off.png differ diff --git a/res/img/action/autoscroll-on.png b/res/img/action/autoscroll-on.png new file mode 100644 index 0000000..3f55052 Binary files /dev/null and b/res/img/action/autoscroll-on.png differ diff --git a/res/img/action/ban.png b/res/img/action/ban.png new file mode 100644 index 0000000..b335cb1 Binary files /dev/null and b/res/img/action/ban.png differ diff --git a/res/img/action/emoticons.png b/res/img/action/emoticons.png new file mode 100644 index 0000000..ade4318 Binary files /dev/null and b/res/img/action/emoticons.png differ diff --git a/res/img/action/ignore.png b/res/img/action/ignore.png new file mode 100644 index 0000000..08f2493 Binary files /dev/null and b/res/img/action/ignore.png differ diff --git a/res/img/action/kick.png b/res/img/action/kick.png new file mode 100644 index 0000000..bce1c97 Binary files /dev/null and b/res/img/action/kick.png differ diff --git a/res/img/action/menu.png b/res/img/action/menu.png new file mode 100644 index 0000000..be4540c Binary files /dev/null and b/res/img/action/menu.png differ diff --git a/res/img/action/private.png b/res/img/action/private.png new file mode 100644 index 0000000..39433cf Binary files /dev/null and b/res/img/action/private.png differ diff --git a/res/img/action/settings.png b/res/img/action/settings.png new file mode 100644 index 0000000..327fdf4 Binary files /dev/null and b/res/img/action/settings.png differ diff --git a/res/img/action/sound-off.png b/res/img/action/sound-off.png new file mode 100644 index 0000000..7ba81fe Binary files /dev/null and b/res/img/action/sound-off.png differ diff --git a/res/img/action/sound-on.png b/res/img/action/sound-on.png new file mode 100644 index 0000000..b435160 Binary files /dev/null and b/res/img/action/sound-on.png differ diff --git a/res/img/action/statusmessage-off.png b/res/img/action/statusmessage-off.png new file mode 100644 index 0000000..03eb01d Binary files /dev/null and b/res/img/action/statusmessage-off.png differ diff --git a/res/img/action/statusmessage-on.png b/res/img/action/statusmessage-on.png new file mode 100644 index 0000000..063e8dc Binary files /dev/null and b/res/img/action/statusmessage-on.png differ diff --git a/res/img/action/subject.png b/res/img/action/subject.png new file mode 100644 index 0000000..7bc9233 Binary files /dev/null and b/res/img/action/subject.png differ diff --git a/res/img/action/unignore.png b/res/img/action/unignore.png new file mode 100644 index 0000000..89c8129 Binary files /dev/null and b/res/img/action/unignore.png differ diff --git a/res/img/action/usercount.png b/res/img/action/usercount.png new file mode 100644 index 0000000..7fb4e1f Binary files /dev/null and b/res/img/action/usercount.png differ diff --git a/res/img/emoticons/Angel.png b/res/img/emoticons/Angel.png new file mode 100644 index 0000000..0cf707b Binary files /dev/null and b/res/img/emoticons/Angel.png differ diff --git a/res/img/emoticons/Angry.png b/res/img/emoticons/Angry.png new file mode 100644 index 0000000..9ae5d18 Binary files /dev/null and b/res/img/emoticons/Angry.png differ diff --git a/res/img/emoticons/Aww.png b/res/img/emoticons/Aww.png new file mode 100644 index 0000000..3512863 Binary files /dev/null and b/res/img/emoticons/Aww.png differ diff --git a/res/img/emoticons/Aww_2.png b/res/img/emoticons/Aww_2.png new file mode 100644 index 0000000..60510bb Binary files /dev/null and b/res/img/emoticons/Aww_2.png differ diff --git a/res/img/emoticons/Blushing.png b/res/img/emoticons/Blushing.png new file mode 100644 index 0000000..ab03ee8 Binary files /dev/null and b/res/img/emoticons/Blushing.png differ diff --git a/res/img/emoticons/Childish.png b/res/img/emoticons/Childish.png new file mode 100644 index 0000000..1a31c50 Binary files /dev/null and b/res/img/emoticons/Childish.png differ diff --git a/res/img/emoticons/Confused.png b/res/img/emoticons/Confused.png new file mode 100644 index 0000000..08ba7d3 Binary files /dev/null and b/res/img/emoticons/Confused.png differ diff --git a/res/img/emoticons/Creepy.png b/res/img/emoticons/Creepy.png new file mode 100644 index 0000000..5615058 Binary files /dev/null and b/res/img/emoticons/Creepy.png differ diff --git a/res/img/emoticons/Crying.png b/res/img/emoticons/Crying.png new file mode 100644 index 0000000..2532976 Binary files /dev/null and b/res/img/emoticons/Crying.png differ diff --git a/res/img/emoticons/Cthulhu.png b/res/img/emoticons/Cthulhu.png new file mode 100644 index 0000000..fafc4b3 Binary files /dev/null and b/res/img/emoticons/Cthulhu.png differ diff --git a/res/img/emoticons/Cute.png b/res/img/emoticons/Cute.png new file mode 100644 index 0000000..a883ac3 Binary files /dev/null and b/res/img/emoticons/Cute.png differ diff --git a/res/img/emoticons/Cute_Winking.png b/res/img/emoticons/Cute_Winking.png new file mode 100644 index 0000000..ad3383d Binary files /dev/null and b/res/img/emoticons/Cute_Winking.png differ diff --git a/res/img/emoticons/Devil.png b/res/img/emoticons/Devil.png new file mode 100644 index 0000000..afc5c2c Binary files /dev/null and b/res/img/emoticons/Devil.png differ diff --git a/res/img/emoticons/Gah.png b/res/img/emoticons/Gah.png new file mode 100644 index 0000000..b03ee1b Binary files /dev/null and b/res/img/emoticons/Gah.png differ diff --git a/res/img/emoticons/Gah_2.png b/res/img/emoticons/Gah_2.png new file mode 100644 index 0000000..b682458 Binary files /dev/null and b/res/img/emoticons/Gah_2.png differ diff --git a/res/img/emoticons/Gasping.png b/res/img/emoticons/Gasping.png new file mode 100644 index 0000000..b6655ce Binary files /dev/null and b/res/img/emoticons/Gasping.png differ diff --git a/res/img/emoticons/Greedy.png b/res/img/emoticons/Greedy.png new file mode 100644 index 0000000..a179638 Binary files /dev/null and b/res/img/emoticons/Greedy.png differ diff --git a/res/img/emoticons/Grinning.png b/res/img/emoticons/Grinning.png new file mode 100644 index 0000000..85ff915 Binary files /dev/null and b/res/img/emoticons/Grinning.png differ diff --git a/res/img/emoticons/Grinning_Winking.png b/res/img/emoticons/Grinning_Winking.png new file mode 100644 index 0000000..5b1d5b7 Binary files /dev/null and b/res/img/emoticons/Grinning_Winking.png differ diff --git a/res/img/emoticons/Happy.png b/res/img/emoticons/Happy.png new file mode 100644 index 0000000..51cf1a2 Binary files /dev/null and b/res/img/emoticons/Happy.png differ diff --git a/res/img/emoticons/Happy_2.png b/res/img/emoticons/Happy_2.png new file mode 100644 index 0000000..1332686 Binary files /dev/null and b/res/img/emoticons/Happy_2.png differ diff --git a/res/img/emoticons/Happy_3.png b/res/img/emoticons/Happy_3.png new file mode 100644 index 0000000..be79df0 Binary files /dev/null and b/res/img/emoticons/Happy_3.png differ diff --git a/res/img/emoticons/Heart.png b/res/img/emoticons/Heart.png new file mode 100644 index 0000000..dcd28b9 Binary files /dev/null and b/res/img/emoticons/Heart.png differ diff --git a/res/img/emoticons/Huh.png b/res/img/emoticons/Huh.png new file mode 100644 index 0000000..241f50f Binary files /dev/null and b/res/img/emoticons/Huh.png differ diff --git a/res/img/emoticons/Huh_2.png b/res/img/emoticons/Huh_2.png new file mode 100644 index 0000000..a1a54e4 Binary files /dev/null and b/res/img/emoticons/Huh_2.png differ diff --git a/res/img/emoticons/Laughing.png b/res/img/emoticons/Laughing.png new file mode 100644 index 0000000..edefc95 Binary files /dev/null and b/res/img/emoticons/Laughing.png differ diff --git a/res/img/emoticons/Lips_Sealed.png b/res/img/emoticons/Lips_Sealed.png new file mode 100644 index 0000000..46e4701 Binary files /dev/null and b/res/img/emoticons/Lips_Sealed.png differ diff --git a/res/img/emoticons/Madness.png b/res/img/emoticons/Madness.png new file mode 100644 index 0000000..1c0946c Binary files /dev/null and b/res/img/emoticons/Madness.png differ diff --git a/res/img/emoticons/Malicious.png b/res/img/emoticons/Malicious.png new file mode 100644 index 0000000..23f2579 Binary files /dev/null and b/res/img/emoticons/Malicious.png differ diff --git a/res/img/emoticons/README b/res/img/emoticons/README new file mode 100644 index 0000000..208db2c --- /dev/null +++ b/res/img/emoticons/README @@ -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 diff --git a/res/img/emoticons/Sick.png b/res/img/emoticons/Sick.png new file mode 100644 index 0000000..6f73e2f Binary files /dev/null and b/res/img/emoticons/Sick.png differ diff --git a/res/img/emoticons/Smiling.png b/res/img/emoticons/Smiling.png new file mode 100644 index 0000000..725eef5 Binary files /dev/null and b/res/img/emoticons/Smiling.png differ diff --git a/res/img/emoticons/Speechless.png b/res/img/emoticons/Speechless.png new file mode 100644 index 0000000..4fc4246 Binary files /dev/null and b/res/img/emoticons/Speechless.png differ diff --git a/res/img/emoticons/Spiteful.png b/res/img/emoticons/Spiteful.png new file mode 100644 index 0000000..195ced8 Binary files /dev/null and b/res/img/emoticons/Spiteful.png differ diff --git a/res/img/emoticons/Stupid.png b/res/img/emoticons/Stupid.png new file mode 100644 index 0000000..3fcea49 Binary files /dev/null and b/res/img/emoticons/Stupid.png differ diff --git a/res/img/emoticons/Sunglasses.png b/res/img/emoticons/Sunglasses.png new file mode 100644 index 0000000..cad8379 Binary files /dev/null and b/res/img/emoticons/Sunglasses.png differ diff --git a/res/img/emoticons/Terrified.png b/res/img/emoticons/Terrified.png new file mode 100644 index 0000000..fad2e06 Binary files /dev/null and b/res/img/emoticons/Terrified.png differ diff --git a/res/img/emoticons/Thumb_Down.png b/res/img/emoticons/Thumb_Down.png new file mode 100644 index 0000000..4f70696 Binary files /dev/null and b/res/img/emoticons/Thumb_Down.png differ diff --git a/res/img/emoticons/Thumb_Up.png b/res/img/emoticons/Thumb_Up.png new file mode 100644 index 0000000..2ca0e0d Binary files /dev/null and b/res/img/emoticons/Thumb_Up.png differ diff --git a/res/img/emoticons/Tired.png b/res/img/emoticons/Tired.png new file mode 100644 index 0000000..13f7d12 Binary files /dev/null and b/res/img/emoticons/Tired.png differ diff --git a/res/img/emoticons/Tongue_Out.png b/res/img/emoticons/Tongue_Out.png new file mode 100644 index 0000000..3d154f9 Binary files /dev/null and b/res/img/emoticons/Tongue_Out.png differ diff --git a/res/img/emoticons/Tongue_Out_Laughing.png b/res/img/emoticons/Tongue_Out_Laughing.png new file mode 100644 index 0000000..fba5d75 Binary files /dev/null and b/res/img/emoticons/Tongue_Out_Laughing.png differ diff --git a/res/img/emoticons/Tongue_Out_Left.png b/res/img/emoticons/Tongue_Out_Left.png new file mode 100644 index 0000000..8015de7 Binary files /dev/null and b/res/img/emoticons/Tongue_Out_Left.png differ diff --git a/res/img/emoticons/Tongue_Out_Up.png b/res/img/emoticons/Tongue_Out_Up.png new file mode 100644 index 0000000..46328fb Binary files /dev/null and b/res/img/emoticons/Tongue_Out_Up.png differ diff --git a/res/img/emoticons/Tongue_Out_Up_Left.png b/res/img/emoticons/Tongue_Out_Up_Left.png new file mode 100644 index 0000000..b67b69f Binary files /dev/null and b/res/img/emoticons/Tongue_Out_Up_Left.png differ diff --git a/res/img/emoticons/Tongue_Out_Winking.png b/res/img/emoticons/Tongue_Out_Winking.png new file mode 100644 index 0000000..2a22cf6 Binary files /dev/null and b/res/img/emoticons/Tongue_Out_Winking.png differ diff --git a/res/img/emoticons/Uncertain.png b/res/img/emoticons/Uncertain.png new file mode 100644 index 0000000..7176856 Binary files /dev/null and b/res/img/emoticons/Uncertain.png differ diff --git a/res/img/emoticons/Uncertain_2.png b/res/img/emoticons/Uncertain_2.png new file mode 100644 index 0000000..a7f5370 Binary files /dev/null and b/res/img/emoticons/Uncertain_2.png differ diff --git a/res/img/emoticons/Unhappy.png b/res/img/emoticons/Unhappy.png new file mode 100644 index 0000000..79fc0c0 Binary files /dev/null and b/res/img/emoticons/Unhappy.png differ diff --git a/res/img/emoticons/Winking.png b/res/img/emoticons/Winking.png new file mode 100644 index 0000000..1e01f94 Binary files /dev/null and b/res/img/emoticons/Winking.png differ diff --git a/res/img/favicon.png b/res/img/favicon.png new file mode 100644 index 0000000..d384cc4 Binary files /dev/null and b/res/img/favicon.png differ diff --git a/res/img/modal-spinner.gif b/res/img/modal-spinner.gif new file mode 100644 index 0000000..5b6a68d Binary files /dev/null and b/res/img/modal-spinner.gif differ diff --git a/res/img/overlay.png b/res/img/overlay.png new file mode 100644 index 0000000..0593fcf Binary files /dev/null and b/res/img/overlay.png differ diff --git a/res/img/roster/affiliation-owner.png b/res/img/roster/affiliation-owner.png new file mode 100644 index 0000000..b88c857 Binary files /dev/null and b/res/img/roster/affiliation-owner.png differ diff --git a/res/img/roster/ignore.png b/res/img/roster/ignore.png new file mode 100644 index 0000000..08f2493 Binary files /dev/null and b/res/img/roster/ignore.png differ diff --git a/res/img/roster/role-moderator.png b/res/img/roster/role-moderator.png new file mode 100644 index 0000000..0d064d1 Binary files /dev/null and b/res/img/roster/role-moderator.png differ diff --git a/res/img/tab-transitions.png b/res/img/tab-transitions.png new file mode 100644 index 0000000..c45d24c Binary files /dev/null and b/res/img/tab-transitions.png differ diff --git a/res/img/tooltip-arrows.gif b/res/img/tooltip-arrows.gif new file mode 100644 index 0000000..6faa6fd Binary files /dev/null and b/res/img/tooltip-arrows.gif differ diff --git a/res/notify.mp3 b/res/notify.mp3 new file mode 100644 index 0000000..c00d997 Binary files /dev/null and b/res/notify.mp3 differ