├── xmpp
├── __init__.py
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ └── ejabberd_auth.py
├── templatetags
│ ├── __init__.py
│ └── xmpp_tags.py
├── admin.py
├── tests.py
├── static
│ ├── images
│ │ ├── user.png
│ │ ├── favicon.ico
│ │ ├── header.jpg
│ │ ├── overlay.png
│ │ ├── bitcoin_qr_code.png
│ │ ├── arrow.svg
│ │ ├── dark-arrow.svg
│ │ ├── bgbl.svg
│ │ └── bgtr.svg
│ ├── sounds
│ │ ├── msg_received.mp3
│ │ └── msg_received.ogg
│ ├── fonticons
│ │ ├── fonts
│ │ │ ├── icomoon.eot
│ │ │ ├── icomoon.ttf
│ │ │ ├── icomoon.woff
│ │ │ └── icomoon.svg
│ │ └── style.css
│ ├── js
│ │ └── converse_functions.js
│ └── css
│ │ └── converse.min.css
├── urls.py
├── templates
│ └── conversejs_initialize.html
├── client.py
├── utils.py
├── views.py
└── models.py
├── MANIFEST.in
├── .gitignore
├── setup.py
├── README.rst
└── LICENSE
/xmpp/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xmpp/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xmpp/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xmpp/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.rst
2 | include LICENSE
3 | recursive-include xmpp *
4 |
--------------------------------------------------------------------------------
/xmpp/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/xmpp/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/xmpp/static/images/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/images/user.png
--------------------------------------------------------------------------------
/xmpp/static/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/images/favicon.ico
--------------------------------------------------------------------------------
/xmpp/static/images/header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/images/header.jpg
--------------------------------------------------------------------------------
/xmpp/static/images/overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/images/overlay.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.o
3 | *.pyc
4 | .DS_Store
5 | db.sqlite3
6 | .ropeproject
7 | dist
8 | build
9 | *.egg-info
10 |
--------------------------------------------------------------------------------
/xmpp/static/sounds/msg_received.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/sounds/msg_received.mp3
--------------------------------------------------------------------------------
/xmpp/static/sounds/msg_received.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/sounds/msg_received.ogg
--------------------------------------------------------------------------------
/xmpp/static/images/bitcoin_qr_code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/images/bitcoin_qr_code.png
--------------------------------------------------------------------------------
/xmpp/static/fonticons/fonts/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/fonticons/fonts/icomoon.eot
--------------------------------------------------------------------------------
/xmpp/static/fonticons/fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/fonticons/fonts/icomoon.ttf
--------------------------------------------------------------------------------
/xmpp/static/fonticons/fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fpytloun/django-xmpp/HEAD/xmpp/static/fonticons/fonts/icomoon.woff
--------------------------------------------------------------------------------
/xmpp/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import re_path
2 | import xmpp.views as views
3 |
4 | urlpatterns = [
5 | re_path(r'^xhr/search/user/$', views.XhrUserSearchView.as_view(), name='xmpp_xhr_user_search'),
6 | re_path(r'^xhr/autojoin/$', views.XhrAutoJoinView.as_view(), name='xmpp_xhr_autojoin'),
7 | ]
8 |
--------------------------------------------------------------------------------
/xmpp/static/images/arrow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xmpp/static/images/dark-arrow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xmpp/templates/conversejs_initialize.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 | {% if conversejs_settings %}
5 |
6 |
7 |
8 |
13 | {% endif %}
14 |
--------------------------------------------------------------------------------
/xmpp/templatetags/xmpp_tags.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from django import template
4 | from ..utils import get_conversejs_context
5 | from django.conf import settings
6 |
7 | register = template.Library()
8 |
9 |
10 | @register.inclusion_tag('conversejs_initialize.html', takes_context=True)
11 | def conversejs_initialize(context):
12 | return get_conversejs_context(context)
13 |
14 |
15 | @register.simple_tag
16 | def xmpp_domain():
17 | return settings.XMPP_DOMAIN
18 |
19 |
20 | @register.simple_tag
21 | def xmpp_jid(user):
22 | return '%s@%s' % (user.username.lower(), xmpp_domain())
23 |
24 |
25 | @register.simple_tag
26 | def xmpp_domain_muc():
27 | return getattr(settings, 'XMPP_DOMAIN_MUC', 'conference.%s' % settings.XMPP_DOMAIN)
28 |
--------------------------------------------------------------------------------
/xmpp/static/images/bgbl.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/xmpp/static/images/bgtr.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/xmpp/client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from sleekxmpp import ClientXMPP
4 |
5 |
6 | class XMPPConnection(ClientXMPP):
7 | def __init__(self, jid, password):
8 | ClientXMPP.__init__(self, jid, password)
9 | self.register_plugin('xep_0054')
10 | self.register_plugin('xep_0084')
11 | self.register_plugin('xep_0153')
12 |
13 | self.connect()
14 | self.process(block=False)
15 |
16 | def set_vcard(self, name=None, url=None):
17 | vcard = self['xep_0054'].stanza.VCardTemp()
18 | vcard['JABBERID'] = self.boundjid.bare
19 |
20 | if name:
21 | vcard['FN'] = name
22 | vcard['NICKNAME'] = name
23 |
24 | if url:
25 | vcard['URL'] = url
26 |
27 | self['xep_0054'].publish_vcard(vcard)
28 |
29 | def set_avatar(self, avatar_data, mime_type='image/png'):
30 | if avatar_data:
31 | avatar_id = self['xep_0084'].generate_id(avatar_data)
32 | info = {
33 | 'id': avatar_id,
34 | 'type': mime_type,
35 | 'bytes': len(avatar_data)
36 | }
37 | self['xep_0084'].publish_avatar(avatar_data)
38 | self['xep_0084'].publish_avatar_metadata(items=[info])
39 | self['xep_0153'].set_avatar(avatar=avatar_data, mtype=mime_type)
40 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import os
5 | from setuptools import setup
6 |
7 | f = open(os.path.join(os.path.dirname(__file__), 'README.rst'))
8 | readme = f.read()
9 | f.close()
10 |
11 | setup(
12 | name='django-xmpp',
13 | version='0.4',
14 | description='XMPP integration for Django app made simple',
15 | long_description=readme,
16 | author="Filip Pytloun",
17 | author_email='filip@pytloun.cz',
18 | url='https://github.com/fpytloun/django-xmpp',
19 | license='GPLv2',
20 | packages=['xmpp', 'xmpp.templatetags', 'xmpp.management',
21 | 'xmpp.management.commands'],
22 | include_package_data=True,
23 | install_requires=['django', 'sleekxmpp', 'dnspython', 'pyasn1',
24 | 'pyasn1_modules', 'django-gravatar2'],
25 | zip_safe=False,
26 | classifiers=[
27 | 'Development Status :: 4 - Beta',
28 | 'Environment :: Web Environment',
29 | 'Framework :: Django',
30 | 'Framework :: Django :: 1.8',
31 | 'Intended Audience :: Developers',
32 | 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
33 | 'Operating System :: OS Independent',
34 | 'Programming Language :: Python',
35 | 'Programming Language :: Python :: 2',
36 | 'Programming Language :: Python :: 2.7',
37 | ],
38 | keywords='django xmpp conversejs jabber chat ejabberd',
39 | )
40 |
--------------------------------------------------------------------------------
/xmpp/utils.py:
--------------------------------------------------------------------------------
1 | import json
2 | from django.conf import settings
3 | from django.urls import reverse
4 |
5 | from .models import XMPPAccount
6 |
7 |
8 | def get_conversejs_settings(settings_dict=None):
9 | converse_settings = {
10 | 'bosh_service_url': settings.XMPP_BOSH_SERVICE_URL,
11 | 'domain_placeholder': settings.XMPP_DOMAIN,
12 | 'debug': settings.DEBUG,
13 | 'authentication': getattr(settings, 'XMPP_CONVERSEJS_AUTH', 'login'),
14 | 'keepalive': True,
15 | 'auto_login': True,
16 | }
17 |
18 | try:
19 | converse_settings.update(settings.XMPP_CONVERSEJS_SETTINGS)
20 | except AttributeError:
21 | pass
22 |
23 | if settings:
24 | converse_settings.update(settings_dict)
25 |
26 | if converse_settings.get('xhr_user_search', None):
27 | converse_settings['xhr_user_search_url'] = reverse('xmpp_xhr_user_search')
28 |
29 | return converse_settings
30 |
31 |
32 | def get_conversejs_context(context):
33 | context['xmpp_enabled'] = settings.XMPP_ENABLED
34 |
35 | if not settings.XMPP_ENABLED:
36 | # XMPP disabled entirely
37 | return context
38 |
39 | request = context.get('request')
40 | if not request.user.is_active:
41 | # User is not logged in
42 | return context
43 |
44 | # Setup authentication
45 | auth_type = getattr(settings, 'XMPP_CONVERSEJS_AUTH', None)
46 | settings_auth = {}
47 | if auth_type in ['login', 'prebind']:
48 | # We need to ensure XMPPAccount for both login and prebind auth
49 | xmpp_account = XMPPAccount.get_or_create(request.user)
50 | settings_auth['jid'] = xmpp_account.jid
51 |
52 | if auth_type == 'login':
53 | settings_auth['password'] = xmpp_account.password
54 | elif auth_type == 'preauth':
55 | raise NotImplementedError('preauth is not implemented yet')
56 |
57 | context['conversejs_settings'] = json.dumps(get_conversejs_settings(settings_auth))
58 |
59 | return context
60 |
--------------------------------------------------------------------------------
/xmpp/static/js/converse_functions.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | $("*[data-require=conversejs]").hide();
3 |
4 | require(['converse'], function (converse) {
5 | // Converse event callbacks
6 | converse.listen.on('ready', function (event) {
7 | // When Converse is initialized, show elements that require it
8 | $("*[data-require=conversejs]").show();
9 |
10 | // Load auto-join rooms and try to join
11 | // TODO: hard-coded auto-join URL
12 | $.getJSON("/xmpp/xhr/autojoin/", function(response) {
13 | $.each(response, function(key, value) {
14 | box = converse.rooms.open(value.jid);
15 | box.minimize();
16 | });
17 | });
18 | });
19 | $("*[data-require=conversejs]").show();
20 |
21 | converse.listen.on('chatRoomOpened', function(event, chatbox) {
22 | // Add room into auto join rooms
23 | var jid = chatbox.getRoomJIDAndNick().split("/")[0];
24 | // TODO: hard-coded auto-join URL
25 | $.post("/xmpp/xhr/autojoin/", {'action': 'add', 'jid': jid});
26 | });
27 |
28 | converse.listen.on('chatBoxClosed', function(event, chatbox) {
29 | // Remove room from auto join rooms
30 | try {
31 | var jid = chatbox.getRoomJIDAndNick().split("/")[0];
32 | // TODO: hard-coded auto-join URL
33 | $.post("/xmpp/xhr/autojoin/", {'action': 'remove', 'jid': jid});
34 | } catch (err) {
35 | // chatbox is not room so it probably doesn't have
36 | // getRoomJIDAndNich function
37 | console.log(err);
38 | }
39 | });
40 | });
41 | });
42 |
43 | function converse_add_open(jid, fullname) {
44 | // Add JID into contacts and open chat
45 | converse.contacts.add(jid, fullname);
46 | // TODO: event is triggered too soon before contact is available so this
47 | // will end up in error :-(
48 | converse.listen.once('roster', function (event) {
49 | try {
50 | converse.chats.open(jid);
51 | } catch (err) {
52 | console.log(err);
53 | }
54 | });
55 | }
56 |
57 | $('a[data-function=converse_add_open]').click(function(e) {
58 | // Add XMPP contact and open chat window
59 | e.preventDefault();
60 | converse_add_open($(this).attr('href'), $(this).attr('data-displayname'));
61 | });
62 |
63 | $('a[data-function=converse_muc_join]').click(function(e) {
64 | // Join MUC and open room window
65 | e.preventDefault();
66 | room = converse.rooms.open($(this).attr('href'), $(this).attr('data-displayname'));
67 | room.maximize();
68 | });
69 |
--------------------------------------------------------------------------------
/xmpp/views.py:
--------------------------------------------------------------------------------
1 | from django.views.generic import View
2 | from django.http import HttpResponse, HttpResponseBadRequest
3 | from django.conf import settings
4 | from django.utils.decorators import method_decorator
5 | from django.contrib.auth.decorators import login_required
6 |
7 | from django.db.models import Q
8 | from django.contrib.auth.models import User
9 |
10 | from .models import XMPPAccount, XMPPAutoJoin
11 |
12 | import json
13 |
14 |
15 | class XhrUserSearchView(View):
16 | @method_decorator(login_required)
17 | def get(self, *args, **kwargs):
18 | query = self.request.GET.get('q', '')
19 | users = User.objects.filter(Q(username__icontains=query) | Q(first_name__icontains=query) | Q(last_name__icontains=query))
20 | users_jid = map(lambda user: {
21 | 'id': '%s@%s' % (user.username.lower(), settings.XMPP_DOMAIN),
22 | 'fullname': user.get_full_name() or user.username,
23 | }, users)
24 |
25 | return HttpResponse(json.dumps(users_jid), 'application/javascript')
26 |
27 |
28 | class XhrAutoJoinView(View):
29 | """
30 | Toggle auto-join to XMPP jid
31 | """
32 | @method_decorator(login_required)
33 | def get(self, *args, **kwargs):
34 | account = XMPPAccount.get_or_create(self.request.user)
35 | auto_join = account.auto_join.all()
36 | if auto_join:
37 | jids = map(lambda join: {
38 | 'jid': join.jid
39 | }, auto_join)
40 | else:
41 | jids = []
42 | return HttpResponse(json.dumps(jids), 'application/javascript')
43 |
44 | @method_decorator(login_required)
45 | def post(self, *args, **kwargs):
46 | """
47 | Add, remove or toggle auto-join to given jid
48 | """
49 | try:
50 | action = self.request.POST['action']
51 | if action not in ['add', 'remove', 'toggle']:
52 | return HttpResponseBadRequest("Unknown action '%s'" % action)
53 | except KeyError:
54 | action = 'toggle'
55 |
56 | try:
57 | jid = self.request.POST['jid']
58 | except KeyError:
59 | return HttpResponseBadRequest('Missing data: jid')
60 | # TODO: check jid name with regex
61 |
62 | account = XMPPAccount.get_or_create(self.request.user)
63 | msg = None
64 | try:
65 | join_obj = XMPPAutoJoin.objects.get(account=account, jid=jid)
66 | if action in ['remove', 'toggle']:
67 | join_obj.delete()
68 | msg = "Auto join to '%s' removed" % jid
69 | except XMPPAutoJoin.DoesNotExist:
70 | if action == 'remove':
71 | msg = "Auto join to '%s' does not exist" % jid
72 | pass
73 | elif action in ['add', 'toggle']:
74 | msg = "Added auto join to '%s'" % jid
75 | join_obj = XMPPAutoJoin(account=account, jid=jid)
76 | join_obj.save()
77 |
78 | res = {
79 | 'status': 200,
80 | 'action': action,
81 | 'msg': msg,
82 | }
83 |
84 | return HttpResponse(json.dumps(res), 'application/javascript')
85 |
--------------------------------------------------------------------------------
/xmpp/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.conf import settings
3 | import datetime
4 | import uuid
5 |
6 | from .client import XMPPConnection
7 | from django.utils import timezone
8 |
9 | try:
10 | from django_gravatar.helpers import get_gravatar_url, has_gravatar
11 | gravatar_available = True
12 | except ImportError:
13 | gravatar_available = False
14 |
15 | import urllib
16 |
17 | import logging
18 | lg = logging.getLogger(__name__)
19 |
20 |
21 | class XMPPAccount(models.Model):
22 | user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='xmpp', on_delete=models.CASCADE)
23 | jid = models.CharField(max_length=300)
24 | password = models.CharField(max_length=1024)
25 | created = models.DateTimeField('created', auto_now_add=True)
26 | updated = models.DateTimeField('updated', blank=True, null=True)
27 |
28 | def __unicode__(self):
29 | return u'{0}/{1}'.format(self.user, self.jid)
30 |
31 | @staticmethod
32 | def get_or_create(user):
33 | """
34 | Get existing account or create it
35 | """
36 | try:
37 | xmpp_account = XMPPAccount.objects.get(user=user)
38 | except XMPPAccount.DoesNotExist:
39 | # Need to generate XMPPAccount object with password that will be later
40 | # used by ejabberd to authenticate webapp
41 | xmpp_jid = '%s@%s' % (user.username.lower(), settings.XMPP_DOMAIN)
42 | # get a random uuid as password
43 | xmpp_password = uuid.uuid4().hex
44 | xmpp_account = XMPPAccount.objects.create(jid=xmpp_jid,
45 | password=xmpp_password,
46 | user=user)
47 | xmpp_account.save()
48 |
49 | xmpp_account.update_vcard()
50 | return xmpp_account
51 |
52 | def update_vcard(self, force=False):
53 | """
54 | Update vcard if not updated within `XMPP_UPDATE_VCARD_HOURS` (default False)
55 | or if XMPP_UPDATE_VCARD is not False
56 | """
57 | if not getattr(settings, 'XMPP_UPDATE_VCARD', True):
58 | # Never ever update vCard
59 | return False
60 |
61 | update_delta = getattr(settings, 'XMPP_UPDATE_VCARD_HOURS', False)
62 | if not update_delta:
63 | return False
64 |
65 | if not force:
66 | if self.updated and self.updated > timezone.now()-datetime.timedelta(hours=update_delta):
67 | return False
68 |
69 | lg.info("Updating vCard for %s" % self.jid)
70 | try:
71 | con = self.get_connection()
72 | con.set_vcard(self.user.get_full_name() or self.user.username)
73 | if gravatar_available and has_gravatar(self.user.email):
74 | try:
75 | avatar_data = urllib.urlopen(get_gravatar_url(self.user.email)).read()
76 | con.set_avatar(avatar_data, mime_type='image/jpeg')
77 | except Exception as e:
78 | lg.exception("Failed to set XMPP avatar for %s" % self.jid, e)
79 | con.disconnect()
80 | except Exception as e:
81 | lg.exception("Failed to update vCard for %s" % self.jid, e)
82 |
83 | self.updated = timezone.now()
84 | self.save()
85 |
86 | def get_connection(self):
87 | return XMPPConnection(self.jid, self.password)
88 |
89 |
90 | class XMPPAutoJoin(models.Model):
91 | account = models.ForeignKey(XMPPAccount, related_name='auto_join', on_delete=models.CASCADE)
92 | jid = models.CharField(max_length=300)
93 | created = models.DateTimeField('created', auto_now_add=True)
94 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ===========
2 | django-xmpp
3 | ===========
4 |
5 | XMPP integration for Django app made simple!
6 |
7 | .. attention:: This application is in early development stage. Every help or feedback is appreciated.
8 |
9 | Features
10 | --------
11 |
12 | - `ConverseJS `_ web chat integration
13 |
14 | - surely best available XMPP web client
15 | - inspired by `TracyWebTech/django-conversejs `_
16 |
17 | - Support for MUC auto join
18 |
19 | - Support for users query
20 |
21 | - Ejabberd Django authentication using ejabberd_auth management command
22 |
23 | - inspired by `ffalcinelli/django-ejabberd-bridge `_
24 |
25 | - Single sign on functionality without storing user's credentials
26 | (requires using ejabberd_auth)
27 |
28 | - Set avatar using gravatar and vCard during first login
29 |
30 | Installation
31 | ------------
32 |
33 | Install ``django-xmpp`` via pip::
34 |
35 | pip install django-xmpp
36 |
37 | Add ``xmpp`` and ``django_gravatar`` into INSTALLED_APPS::
38 |
39 | INSTALLED_APPS = (
40 | ...
41 | 'django_gravatar',
42 | 'xmpp',
43 | )
44 |
45 | Setup most important variables::
46 |
47 | XMPP_DOMAIN = 'example.com'
48 | XMPP_BOSH_SERVICE_URL = 'https://xmpp.example.com:5280/http-bind'
49 |
50 | Optionally setup ConverseJS to suit your needs::
51 |
52 | XMPP_CONVERSEJS_SETTINGS = {
53 | 'allow_contact_removal': False,
54 | 'allow_contact_requests': True,
55 | 'auto_subscribe': True,
56 | 'allow_logout': False,
57 | 'allow_muc': True,
58 | 'allow_otr': False,
59 | 'allow_registration': False,
60 | 'message_carbons': True,
61 | 'hide_muc_server': True,
62 | 'use_vcards': True,
63 | 'animate': True,
64 | 'play_sounds': True,
65 | 'xhr_user_search': True,
66 | 'sounds_path': '%ssounds/' % STATIC_URL,
67 | 'visible_toolbar_buttons': {
68 | 'call': False,
69 | 'clear': False,
70 | 'emoticons': True,
71 | 'toggle_participants': False,
72 | }
73 | }
74 |
75 | Include ``xmpp.urls`` in your ``urls.py``::
76 |
77 | urlpatterns = [
78 | ...
79 | url(r'^xmpp/', include("xmpp.urls")),
80 | ]
81 |
82 | Use ConverseJS in your base template::
83 |
84 | {% load xmpp_tags %}
85 | {% conversejs_initialize %}
86 |
87 | Ejabberd Django authentication
88 | ------------------------------
89 |
90 | Create ``ejaberd_auth.sh`` file that will simply call ``ejabberd_auth``
91 | management command. Adjust to suit your environment (eg. virtualenv)::
92 |
93 | #!/bin/bash
94 | cd
95 | python manage.py ejabberd_auth $@
96 |
97 | Edit ejabberd.yml and add external auth script, eg.::
98 |
99 | host_config:
100 | "example.com":
101 | auth_method: external
102 | extauth_program: "//ejabberd_auth.sh"
103 |
104 | Settings
105 | --------
106 |
107 | These are all available settings you may use.
108 |
109 | XMPP_BOSH_SERVICE_URL
110 | URL for ConverseJS BOSH connection
111 |
112 | XMPP_DOMAIN
113 | Default XMPP domain
114 |
115 | XMPP_DOMAIN_MUC
116 | Domain for multi user chats (default converence.)
117 |
118 | XMPP_CONVERSEJS_AUTH
119 | Authentication type for ConverseJS (prebind is not
120 | supported so login is the only option)
121 |
122 | XMPP_CONVERSEJS_SETTINGS
123 | dictionary of settings passed to converse.initialize.
124 | For more list of available options see `Converse.js docs
125 | `_
126 |
127 | XMPP_ENABLED
128 | Enable or disable XMPP at all
129 |
130 | XMPP_UPDATE_VCARD
131 | Enable or disable vCard update
132 |
133 | XMPP_UPDATE_VCARD_HOURS
134 | Update vCard every n hours (default False)
135 |
136 | A note on usernames
137 | -------------------
138 |
139 | Jabber IDs are case-insensitive (so "MyUser@domain.com" and "myuser@domain.com" are the same account). By contrast, the ``username`` field in the default Django ``User`` model is case-sensitive (see `this Django ticket `_). This means two separate "MyUser" and "myuser" accounts in Django will have the same JID on the XMPP server. The ``ejabberd_auth`` management command will not authenticate such users, and they will both see "Authentication failed" in Converse and other XMPP clients.
140 |
141 | To avoid such conflicts, it is recommended to use a custom ``User`` model that enforces unique lowercase usernames with a ``RegexField``. Other characters not allowed in a Jabber ID should be excluded as well. See `this guide `_ for details.
142 |
--------------------------------------------------------------------------------
/xmpp/management/commands/ejabberd_auth.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # Taken and modified, original source:
4 | # https://raw.githubusercontent.com/ffalcinelli/django-ejabberd-bridge
5 | #
6 | # Copyright (C) 2013 Fabio Falcinelli
7 | #
8 | # This program is free software: you can redistribute it and/or modify
9 | # it under the terms of the GNU General Public License as published by
10 | # the Free Software Foundation, either version 3 of the License, or
11 | # (at your option) any later version.
12 | #
13 | # This program is distributed in the hope that it will be useful,
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | # GNU General Public License for more details.
17 | #
18 | # You should have received a copy of the GNU General Public License
19 | # along with this program. If not, see .
20 | import logging
21 | import struct
22 | import sys
23 | from django.contrib.auth import authenticate, get_user_model
24 | from django.contrib.auth.models import User
25 | from django.core.management.base import BaseCommand
26 |
27 | from xmpp.models import XMPPAccount
28 |
29 | __author__ = "fabio"
30 |
31 |
32 | class Command(BaseCommand):
33 | logger = logging.getLogger(__name__)
34 |
35 | def from_ejabberd(self, encoding="utf-8"):
36 | """
37 | Reads data from stdin as passed by eJabberd
38 | """
39 | input_length = sys.stdin.read(2).encode(encoding)
40 | (size,) = struct.unpack(">h", input_length)
41 | return sys.stdin.read(size).split(":")
42 |
43 | def to_ejabberd(self, answer=False):
44 | """
45 | Converts the response into eJabberd format
46 | """
47 | b = struct.pack('>hh',
48 | 2,
49 | 1 if answer else 0)
50 | self.logger.debug("To jabber: %s" % b)
51 | sys.stdout.write(b.decode("utf-8"))
52 | sys.stdout.flush()
53 |
54 | def auth(self, username=None, server="localhost", password=None):
55 | self.logger.debug("Authenticating %s with password %s on server %s" % (username, password, server))
56 | try:
57 | # First try authenticating with generated webapp account password
58 | xmpp_account = XMPPAccount.objects.get(user__username__iexact=username, password=password)
59 | user = xmpp_account.user
60 | self.logger.info("Authenticated account %s with webapp XMPPAccount" % username)
61 | except XMPPAccount.DoesNotExist:
62 | user = authenticate(username=username, password=password)
63 | self.logger.info("Authenticated user %s with password" % username)
64 |
65 | return user and user.is_active
66 |
67 | def isuser(self, username=None, server="localhost"):
68 | """
69 | Checks if the user exists and is active
70 | """
71 | self.logger.debug("Validating %s on server %s" % (username, server))
72 | try:
73 | user = get_user_model().objects.get(username__iexact=username)
74 | if user.is_active:
75 | return True
76 | else:
77 | self.logger.warning("User %s is disabled" % username)
78 | return False
79 | except User.DoesNotExist:
80 | return False
81 |
82 | def setpass(self, username=None, server="localhost", password=None):
83 | """
84 | Handles password change
85 | """
86 | self.logger.debug("Changing password to %s with new password %s on server %s" % (username, password, server))
87 | try:
88 | user = get_user_model().objects.get(username__iexact=username)
89 | user.set_password(password)
90 | user.save()
91 | return True
92 | except User.DoesNotExist:
93 | return False
94 |
95 | def handle(self, *args, **options):
96 | """
97 | Gathers parameters from eJabberd and executes authentication
98 | against django backend
99 | """
100 | self.logger.debug("Starting serving authentication requests for eJabberd")
101 | success = False
102 | try:
103 | while True:
104 | success = False
105 | data = self.from_ejabberd()
106 | self.logger.debug("Command is %s" % data[0])
107 | if data[0] == "auth":
108 | success = self.auth(data[1], data[2], data[3])
109 | elif data[0] == "isuser":
110 | success = self.isuser(data[1], data[2])
111 | elif data[0] == "setpass":
112 | success = self.setpass(data[1], data[2], data[3])
113 | self.to_ejabberd(success)
114 |
115 | if not options.get("run_forever", True):
116 | break
117 | except Exception as e:
118 | self.logger.error("An error has occurred during eJabberd external authentication: %s" % e)
119 | self.to_ejabberd(success)
120 |
--------------------------------------------------------------------------------
/xmpp/static/fonticons/style.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'icomoon';
3 | src:url('fonts/icomoon.eot?dvaucx');
4 | src:url('fonts/icomoon.eot?#iefixdvaucx') format('embedded-opentype'),
5 | url('fonts/icomoon.ttf?dvaucx') format('truetype'),
6 | url('fonts/icomoon.woff?dvaucx') format('woff'),
7 | url('fonts/icomoon.svg?dvaucx#icomoon') format('svg');
8 | font-weight: normal;
9 | font-style: normal;
10 | }
11 |
12 | [class^="icon-"], [class*=" icon-"] {
13 | font-family: 'icomoon';
14 | speak: none;
15 | font-style: normal;
16 | font-weight: normal;
17 | font-variant: normal;
18 | text-transform: none;
19 | line-height: 1;
20 |
21 | /* Better Font Rendering =========== */
22 | -webkit-font-smoothing: antialiased;
23 | -moz-osx-font-smoothing: grayscale;
24 | }
25 |
26 | .icon-xa:before {
27 | content: "\e602";
28 | }
29 | .icon-conversejs:before {
30 | content: "\e600";
31 | }
32 | .icon-closed:before {
33 | content: "\25ba";
34 | }
35 | .icon-opened:before {
36 | content: "\25bc";
37 | }
38 | .icon-checkmark:before {
39 | content: "\2713";
40 | }
41 | .icon-home:before {
42 | content: "\e000";
43 | }
44 | .icon-pencil:before {
45 | content: "\270e";
46 | }
47 | .icon-camera:before {
48 | content: "\e003";
49 | }
50 | .icon-camera-2:before {
51 | content: "\2616";
52 | }
53 | .icon-play:before {
54 | content: "\25d9";
55 | }
56 | .icon-music:before {
57 | content: "\266b";
58 | }
59 | .icon-headphones:before {
60 | content: "\266c";
61 | }
62 | .icon-phone:before {
63 | content: "\260f";
64 | }
65 | .icon-phone-hang-up:before {
66 | content: "\260e";
67 | }
68 | .icon-address-book:before {
69 | content: "\270f";
70 | }
71 | .icon-notebook:before {
72 | content: "\2710";
73 | }
74 | .icon-envelop:before {
75 | content: "\2709";
76 | }
77 | .icon-pushpin:before {
78 | content: "\e012";
79 | }
80 | .icon-online:before {
81 | content: "\25fc";
82 | }
83 | .icon-away:before {
84 | content: "\25fb";
85 | }
86 | .icon-bubbles:before {
87 | content: "\e015";
88 | }
89 | .icon-bubbles2:before {
90 | content: "\e016";
91 | }
92 | .icon-bubbles3:before {
93 | content: "\e017";
94 | }
95 | .icon-user:before {
96 | content: "\e01a";
97 | }
98 | .icon-hide-users:before {
99 | content: "\e01c";
100 | }
101 | .icon-show-users:before {
102 | content: "\e01e";
103 | }
104 | .icon-users:before {
105 | content: "\e01b";
106 | }
107 | .icon-quotes-left:before {
108 | content: "\e01d";
109 | }
110 | .icon-spinner:before {
111 | content: "\231b";
112 | }
113 | .icon-search:before {
114 | content: "\e021";
115 | }
116 | .icon-cogs:before {
117 | content: "\e022";
118 | }
119 | .icon-wrench:before {
120 | content: "\e024";
121 | }
122 | .icon-unlocked:before {
123 | content: "\e025";
124 | }
125 | .icon-lock:before {
126 | content: "\e026";
127 | }
128 | .icon-lock-2:before {
129 | content: "\e027";
130 | }
131 | .icon-key:before {
132 | content: "\e028";
133 | }
134 | .icon-key-2:before {
135 | content: "\e029";
136 | }
137 | .icon-zoomout:before {
138 | content: "\e02a";
139 | }
140 | .icon-zoomin:before {
141 | content: "\e02b";
142 | }
143 | .icon-cog:before {
144 | content: "\e02f";
145 | }
146 | .icon-remove:before {
147 | content: "\e02d";
148 | }
149 | .icon-eye:before {
150 | content: "\e030";
151 | }
152 | .icon-eye-blocked:before {
153 | content: "\e031";
154 | }
155 | .icon-attachment:before {
156 | content: "\e032";
157 | }
158 | .icon-globe:before {
159 | content: "\e033";
160 | }
161 | .icon-heart:before {
162 | content: "\2764";
163 | }
164 | .icon-happy:before {
165 | content: "\263b";
166 | }
167 | .icon-thumbs-up:before {
168 | content: "\261d";
169 | }
170 | .icon-smiley:before {
171 | content: "\263a";
172 | }
173 | .icon-tongue:before {
174 | content: "\e038";
175 | }
176 | .icon-sad:before {
177 | content: "\2639";
178 | }
179 | .icon-wink:before {
180 | content: "\e03a";
181 | }
182 | .icon-wondering:before {
183 | content: "\2369";
184 | }
185 | .icon-confused:before {
186 | content: "\2368";
187 | }
188 | .icon-shocked:before {
189 | content: "\2364";
190 | }
191 | .icon-evil:before {
192 | content: "\261f";
193 | }
194 | .icon-angry:before {
195 | content: "\e03f";
196 | }
197 | .icon-cool:before {
198 | content: "\e040";
199 | }
200 | .icon-grin:before {
201 | content: "\e041";
202 | }
203 | .icon-info:before {
204 | content: "\2360";
205 | }
206 | .icon-notification:before {
207 | content: "\e01f";
208 | }
209 | .icon-warning:before {
210 | content: "\26a0";
211 | }
212 | .icon-spell-check:before {
213 | content: "\e045";
214 | }
215 | .icon-volume-high:before {
216 | content: "\e046";
217 | }
218 | .icon-volume-medium:before {
219 | content: "\e047";
220 | }
221 | .icon-volume-low:before {
222 | content: "\e048";
223 | }
224 | .icon-volume-mute:before {
225 | content: "\e049";
226 | }
227 | .icon-volume-mute2:before {
228 | content: "\e04a";
229 | }
230 | .icon-volume-decrease:before {
231 | content: "\e04b";
232 | }
233 | .icon-volume-increase:before {
234 | content: "\e04c";
235 | }
236 | .icon-bold:before {
237 | content: "\e04d";
238 | }
239 | .icon-underline:before {
240 | content: "\e04e";
241 | }
242 | .icon-italic:before {
243 | content: "\e04f";
244 | }
245 | .icon-strikethrough:before {
246 | content: "\e050";
247 | }
248 | .icon-newtab:before {
249 | content: "\e053";
250 | }
251 | .icon-youtube:before {
252 | content: "\e055";
253 | }
254 | .icon-close:before {
255 | content: "\2715";
256 | }
257 | .icon-blocked:before {
258 | content: "\2718";
259 | }
260 | .icon-cancel-circle:before {
261 | content: "\e058";
262 | }
263 | .icon-minus:before {
264 | content: "\e05a";
265 | }
266 | .icon-plus:before {
267 | content: "\271a";
268 | }
269 | .icon-checkbox-checked:before {
270 | content: "\2611";
271 | }
272 | .icon-checkbox-unchecked:before {
273 | content: "\2b27";
274 | }
275 | .icon-checkbox-partial:before {
276 | content: "\2b28";
277 | }
278 | .icon-radio-checked:before {
279 | content: "\2b26";
280 | }
281 | .icon-radio-unchecked:before {
282 | content: "\2b25";
283 | }
284 | .icon-room-info:before {
285 | content: "\e059";
286 | }
287 | .icon-newspaper:before {
288 | content: "\e001";
289 | }
290 | .icon-image:before {
291 | content: "\2b14";
292 | }
293 | .icon-offline:before {
294 | content: "\e002";
295 | }
296 | .icon-busy:before {
297 | content: "\e004";
298 | }
299 | .icon-exit:before {
300 | content: "\e601";
301 | }
302 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/xmpp/static/fonticons/fonts/icomoon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/xmpp/static/css/converse.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Converse.js (Web-based XMPP instant messaging client)
3 | * http://conversejs.org
4 | *
5 | * Copyright (c) 2012-2014, JC Brand
6 | * Licensed under the Mozilla Public License
7 | */
8 | /*
9 | Color scheme helpers:
10 | https://coolors.co/app/264653-2a9d8f-e9c46a-f4a261-e76f51
11 | http://paletton.com/#uid=53f0u0knsvIdILAj5Cftgu3uBmZ
12 | */
13 | /* $font-path: "../fonticons/fonts/" !default; */
14 | @font-face {
15 | font-family: 'Converse-js';
16 | src: url("https://cdn.conversejs.org/fonticons/fonts/icomoon.eot?-mnoxh0");
17 | src: url("https://cdn.conversejs.org/fonticons/fonts/icomoon.eot?#iefix-mnoxh0") format("embedded-opentype"), url("https://cdn.conversejs.org/fonticons/fonts/icomoon.woff?-mnoxh0") format("woff"), url("https://cdn.conversejs.org/fonticons/fonts/icomoon.ttf?-mnoxh0") format("truetype"), url("https://cdn.conversejs.org/fonticons/fonts/icomoon.svg?-mnoxh0#icomoon") format("svg");
18 | font-weight: normal;
19 | font-style: normal; }
20 | .icon-conversejs {
21 | font-family: 'Converse-js';
22 | speak: none;
23 | font-style: normal;
24 | font-weight: normal;
25 | font-variant: normal;
26 | text-transform: none;
27 | line-height: 1;
28 | /* Better Font Rendering =========== */
29 | -webkit-font-smoothing: antialiased;
30 | -moz-osx-font-smoothing: grayscale; }
31 |
32 | .icon-conversejs:before {
33 | content: "\e600"; }
34 |
35 | #conversejs .icon-address-book:before {
36 | content: "\270f"; }
37 | #conversejs .icon-angry:before {
38 | content: "\e03f"; }
39 | #conversejs .icon-attachment:before {
40 | content: "\e032"; }
41 | #conversejs .icon-away:before {
42 | content: "\25fb"; }
43 | #conversejs .icon-blocked:before {
44 | content: "\2718"; }
45 | #conversejs .icon-bold:before {
46 | content: "\e04d"; }
47 | #conversejs .icon-bubbles-2:before {
48 | content: "\e016"; }
49 | #conversejs .icon-bubbles-3:before {
50 | content: "\e017"; }
51 | #conversejs .icon-bubbles:before {
52 | content: "\e015"; }
53 | #conversejs .icon-camera-2:before {
54 | content: "\2616"; }
55 | #conversejs .icon-camera:before {
56 | content: "\e003"; }
57 | #conversejs .icon-cancel-circle:before {
58 | content: "\e058"; }
59 | #conversejs .icon-checkbox-checked:before {
60 | content: "\2611"; }
61 | #conversejs .icon-checkbox-partial:before {
62 | content: "\2b28"; }
63 | #conversejs .icon-checkbox-unchecked:before {
64 | content: "\2b27"; }
65 | #conversejs .icon-checkmark:before {
66 | content: "\2713"; }
67 | #conversejs .icon-close:before {
68 | content: "\2715"; }
69 | #conversejs .icon-closed:before {
70 | content: "\25ba"; }
71 | #conversejs .icon-cog:before {
72 | content: "\e02f"; }
73 | #conversejs .icon-cogs:before {
74 | content: "\e022"; }
75 | #conversejs .icon-confused:before {
76 | content: "\2368"; }
77 | #conversejs .icon-cool:before {
78 | content: "\e040"; }
79 | #conversejs .icon-dnd:before {
80 | content: "\e004"; }
81 | #conversejs .icon-envelop:before {
82 | content: "\2709"; }
83 | #conversejs .icon-evil:before {
84 | content: "\261f"; }
85 | #conversejs .icon-eye-blocked:before {
86 | content: "\e031"; }
87 | #conversejs .icon-eye:before {
88 | content: "\e030"; }
89 | #conversejs .icon-globe:before {
90 | content: "\e033"; }
91 | #conversejs .icon-grin:before {
92 | content: "\e041"; }
93 | #conversejs .icon-happy:before {
94 | content: "\263b"; }
95 | #conversejs .icon-headphones:before {
96 | content: "\266c"; }
97 | #conversejs .icon-heart:before {
98 | content: "\2764"; }
99 | #conversejs .icon-hide-users:before {
100 | content: "\e01c"; }
101 | #conversejs .icon-home:before {
102 | content: "\e000"; }
103 | #conversejs .icon-image:before {
104 | content: "\2b14"; }
105 | #conversejs .icon-info:before {
106 | content: "\2360"; }
107 | #conversejs .icon-info-2:before {
108 | content: "i"; }
109 | #conversejs .icon-italic:before {
110 | content: "\e04f"; }
111 | #conversejs .icon-key-2:before {
112 | content: "\e029"; }
113 | #conversejs .icon-key:before {
114 | content: "\e028"; }
115 | #conversejs .icon-lock-2:before {
116 | content: "\e027"; }
117 | #conversejs .icon-lock:before {
118 | content: "\e026"; }
119 | #conversejs .icon-logout:before {
120 | content: "\e601"; }
121 | #conversejs .icon-minus:before {
122 | content: "\e05a"; }
123 | #conversejs .icon-music:before {
124 | content: "\266b"; }
125 | #conversejs .icon-new-tab:before {
126 | content: "\e053"; }
127 | #conversejs .icon-newspaper:before {
128 | content: "\e001"; }
129 | #conversejs .icon-notebook:before {
130 | content: "\2710"; }
131 | #conversejs .icon-notification:before {
132 | content: "\e01f"; }
133 | #conversejs .icon-online:before {
134 | content: "\25fc"; }
135 | #conversejs .icon-chat:before {
136 | content: "\25fc"; }
137 | #conversejs .icon-opened:before {
138 | content: "\25bc"; }
139 | #conversejs .icon-pencil:before {
140 | content: "\270e"; }
141 | #conversejs .icon-phone-hang-up:before {
142 | content: "\260e"; }
143 | #conversejs .icon-phone:before {
144 | content: "\260f"; }
145 | #conversejs .icon-play:before {
146 | content: "\25d9"; }
147 | #conversejs .icon-plus:before {
148 | content: "\271a"; }
149 | #conversejs .icon-pushpin:before {
150 | content: "\e012"; }
151 | #conversejs .icon-quotes-left:before {
152 | content: "\e01d"; }
153 | #conversejs .icon-radio-checked:before {
154 | content: "\2b26"; }
155 | #conversejs .icon-radio-unchecked:before {
156 | content: "\2b25"; }
157 | #conversejs .icon-remove:before {
158 | content: "\e02d"; }
159 | #conversejs .icon-room-info:before {
160 | content: "\e059"; }
161 | #conversejs .icon-sad:before {
162 | content: "\2639"; }
163 | #conversejs .icon-search:before {
164 | content: "\e021"; }
165 | #conversejs .icon-shocked:before {
166 | content: "\2364"; }
167 | #conversejs .icon-show-users:before {
168 | content: "\e01e"; }
169 | #conversejs .icon-smiley:before {
170 | content: "\263a"; }
171 | #conversejs .icon-spell-check:before {
172 | content: "\e045"; }
173 | #conversejs .icon-spinner:before {
174 | content: "\231b"; }
175 | #conversejs .icon-strikethrough:before {
176 | content: "\e050"; }
177 | #conversejs .icon-thumbs-up:before {
178 | content: "\261d"; }
179 | #conversejs .icon-tongue:before {
180 | content: "\e038"; }
181 | #conversejs .icon-underline:before {
182 | content: "\e04e"; }
183 | #conversejs .icon-unlocked:before {
184 | content: "\e025"; }
185 | #conversejs .icon-user:before {
186 | content: "\e01a"; }
187 | #conversejs .icon-users:before {
188 | content: "\e01b"; }
189 | #conversejs .icon-volume-decrease:before {
190 | content: "\e04b"; }
191 | #conversejs .icon-volume-high:before {
192 | content: "\e046"; }
193 | #conversejs .icon-volume-increase:before {
194 | content: "\e04c"; }
195 | #conversejs .icon-volume-low:before {
196 | content: "\e048"; }
197 | #conversejs .icon-volume-medium:before {
198 | content: "\e047"; }
199 | #conversejs .icon-volume-mute-2:before {
200 | content: "\e04a"; }
201 | #conversejs .icon-volume-mute:before {
202 | content: "\e049"; }
203 | #conversejs .icon-warning:before {
204 | content: "\26a0"; }
205 | #conversejs .icon-wink:before {
206 | content: "\e03a"; }
207 | #conversejs .icon-wondering:before {
208 | content: "\2369"; }
209 | #conversejs .icon-wrench:before {
210 | content: "\e024"; }
211 | #conversejs .icon-xa:before {
212 | content: "\e602"; }
213 | #conversejs .icon-unavailable:before,
214 | #conversejs .icon-offline:before {
215 | content: "\e002"; }
216 | #conversejs .icon-youtube:before {
217 | content: "\e055"; }
218 | #conversejs .icon-zoom-in:before {
219 | content: "\e02b"; }
220 | #conversejs .icon-zoom-out:before {
221 | content: "\e02a"; }
222 | #conversejs [data-icon]:before {
223 | content: attr(data-icon);
224 | font-family: 'Converse-js';
225 | font-variant: normal;
226 | font-weight: normal;
227 | line-height: 1;
228 | speak: none;
229 | text-transform: none;
230 | /* Better Font Rendering =========== */
231 | -webkit-font-smoothing: antialiased;
232 | -moz-osx-font-smoothing: grayscale; }
233 | #conversejs [class^="icon-"]:before, #conversejs [class*=" icon-"]:before {
234 | background-position: 14px 14px;
235 | background-image: none;
236 | font-family: 'Converse-js';
237 | font-style: normal;
238 | font-variant: normal;
239 | font-weight: normal;
240 | width: auto;
241 | height: auto;
242 | line-height: 1;
243 | speak: none;
244 | text-transform: none;
245 | /* Better Font Rendering =========== */
246 | -webkit-font-smoothing: antialiased;
247 | -moz-osx-font-smoothing: grayscale; }
248 |
249 | #conversejs {
250 | /*!
251 | Pure v0.6.1-pre
252 | Copyright 2014 Yahoo! Inc. All rights reserved.
253 | Licensed under the BSD License.
254 | https://github.com/yahoo/pure/blob/master/LICENSE.md
255 | */
256 | /*!
257 | normalize.css v^3.0 | MIT License | git.io/normalize
258 | Copyright (c) Nicolas Gallagher and Jonathan Neal
259 | */
260 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
261 | /**
262 | * 1. Set default font family to sans-serif.
263 | * 2. Prevent iOS and IE text size adjust after device orientation change,
264 | * without disabling user zoom.
265 | */
266 | /**
267 | * Remove default margin.
268 | */
269 | /* HTML5 display definitions
270 | ========================================================================== */
271 | /**
272 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
273 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
274 | * and Firefox.
275 | * Correct `block` display not defined for `main` in IE 11.
276 | */
277 | /**
278 | * 1. Correct `inline-block` display not defined in IE 8/9.
279 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
280 | */
281 | /**
282 | * Prevent modern browsers from displaying `audio` without controls.
283 | * Remove excess height in iOS 5 devices.
284 | */
285 | /**
286 | * Address `[hidden]` styling not present in IE 8/9/10.
287 | * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
288 | */
289 | /* Links
290 | ========================================================================== */
291 | /**
292 | * Remove the gray background color from active links in IE 10.
293 | */
294 | /**
295 | * Improve readability of focused elements when they are also in an
296 | * active/hover state.
297 | */
298 | /* Text-level semantics
299 | ========================================================================== */
300 | /**
301 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
302 | */
303 | /**
304 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
305 | */
306 | /**
307 | * Address styling not present in Safari and Chrome.
308 | */
309 | /**
310 | * Address variable `h1` font-size and margin within `section` and `article`
311 | * contexts in Firefox 4+, Safari, and Chrome.
312 | */
313 | /**
314 | * Address styling not present in IE 8/9.
315 | */
316 | /**
317 | * Address inconsistent and variable font size in all browsers.
318 | */
319 | /**
320 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
321 | */
322 | /* Embedded content
323 | ========================================================================== */
324 | /**
325 | * Remove border when inside `a` element in IE 8/9/10.
326 | */
327 | /**
328 | * Correct overflow not hidden in IE 9/10/11.
329 | */
330 | /* Grouping content
331 | ========================================================================== */
332 | /**
333 | * Address margin not present in IE 8/9 and Safari.
334 | */
335 | /**
336 | * Address differences between Firefox and other browsers.
337 | */
338 | /**
339 | * Contain overflow in all browsers.
340 | */
341 | /**
342 | * Address odd `em`-unit font size rendering in all browsers.
343 | */
344 | /* Forms
345 | ========================================================================== */
346 | /**
347 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
348 | * styling of `select`, unless a `border` property is set.
349 | */
350 | /**
351 | * 1. Correct color not being inherited.
352 | * Known issue: affects color of disabled elements.
353 | * 2. Correct font properties not being inherited.
354 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
355 | */
356 | /**
357 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
358 | */
359 | /**
360 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
361 | * All other form control elements do not inherit `text-transform` values.
362 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
363 | * Correct `select` style inheritance in Firefox.
364 | */
365 | /**
366 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
367 | * and `video` controls.
368 | * 2. Correct inability to style clickable `input` types in iOS.
369 | * 3. Improve usability and consistency of cursor style between image-type
370 | * `input` and others.
371 | */
372 | /**
373 | * Re-set default cursor for disabled elements.
374 | */
375 | /**
376 | * Remove inner padding and border in Firefox 4+.
377 | */
378 | /**
379 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
380 | * the UA stylesheet.
381 | */
382 | /**
383 | * It's recommended that you don't attempt to style these elements.
384 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
385 | *
386 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
387 | * 2. Remove excess padding in IE 8/9/10.
388 | */
389 | /**
390 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
391 | * `font-size` values of the `input`, it causes the cursor style of the
392 | * decrement button to change from `default` to `text`.
393 | */
394 | /**
395 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
396 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
397 | */
398 | /**
399 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
400 | * Safari (but not Chrome) clips the cancel button when the search input has
401 | * padding (and `textfield` appearance).
402 | */
403 | /**
404 | * Define consistent border, margin, and padding.
405 | */
406 | /**
407 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
408 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
409 | */
410 | /**
411 | * Remove default vertical scrollbar in IE 8/9/10/11.
412 | */
413 | /**
414 | * Don't inherit the `font-weight` (applied by a rule above).
415 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
416 | */
417 | /* Tables
418 | ========================================================================== */
419 | /**
420 | * Remove most spacing between table cells.
421 | */
422 | /*csslint important:false*/
423 | /* ==========================================================================
424 | Pure Base Extras
425 | ========================================================================== */
426 | /**
427 | * Extra rules that Pure adds on top of Normalize.css
428 | */
429 | /**
430 | * Always hide an element when it has the `hidden` HTML attribute.
431 | */
432 | /**
433 | * Add this class to an image to make it fit within it's fluid parent wrapper while maintaining
434 | * aspect ratio.
435 | */
436 | /*!
437 | Pure v0.6.1-pre
438 | Copyright 2014 Yahoo! Inc. All rights reserved.
439 | Licensed under the BSD License.
440 | https://github.com/yahoo/pure/blob/master/LICENSE.md
441 | */
442 | /*csslint box-model:false*/
443 | /*
444 | Box-model set to false because we're setting a height on select elements, which
445 | also have border and padding. This is done because some browsers don't render
446 | the padding. We explicitly set the box-model for select elements to border-box,
447 | so we can ignore the csslint warning.
448 | */
449 | /*
450 | Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
451 | since IE8 won't execute CSS that contains a CSS3 selector.
452 | */
453 | /* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */
454 | /* May be able to remove this tweak as color inputs become more standardized across browsers. */
455 | /*
456 | Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
457 | since IE8 won't execute CSS that contains a CSS3 selector.
458 | */
459 | /*
460 | Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
461 | since IE8 won't execute CSS that contains a CSS3 selector.
462 | */
463 | /*
464 | Need to separate out the :not() selector from the rest of the CSS 2.1 selectors
465 | since IE8 won't execute CSS that contains a CSS3 selector.
466 | */
467 | /* Aligned Forms */
468 | /* Rounded Inputs */
469 | /* Grouped Inputs */
470 | /* Inline help for forms */
471 | /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */
472 | /* Block help for forms */
473 | /*!
474 | Pure v0.6.1-pre
475 | Copyright 2014 Yahoo! Inc. All rights reserved.
476 | Licensed under the BSD License.
477 | https://github.com/yahoo/pure/blob/master/LICENSE.md
478 | */
479 | /* Firefox: Get rid of the inner focus border */
480 | /*csslint outline-none:false*/
481 | /* Firefox: Get rid of the inner focus border */
482 | -webkit-box-sizing: border-box;
483 | -moz-box-sizing: border-box;
484 | box-sizing: border-box; }
485 | #conversejs html {
486 | font-family: sans-serif;
487 | /* 1 */
488 | -ms-text-size-adjust: 100%;
489 | /* 2 */
490 | -webkit-text-size-adjust: 100%;
491 | /* 2 */ }
492 | #conversejs body {
493 | margin: 0; }
494 | #conversejs article,
495 | #conversejs aside,
496 | #conversejs details,
497 | #conversejs figcaption,
498 | #conversejs figure,
499 | #conversejs footer,
500 | #conversejs header,
501 | #conversejs hgroup,
502 | #conversejs main,
503 | #conversejs menu,
504 | #conversejs nav,
505 | #conversejs section,
506 | #conversejs summary {
507 | display: block; }
508 | #conversejs audio,
509 | #conversejs canvas,
510 | #conversejs progress,
511 | #conversejs video {
512 | display: inline-block;
513 | /* 1 */
514 | vertical-align: baseline;
515 | /* 2 */ }
516 | #conversejs audio:not([controls]) {
517 | display: none;
518 | height: 0; }
519 | #conversejs [hidden],
520 | #conversejs template {
521 | display: none; }
522 | #conversejs a {
523 | background-color: transparent; }
524 | #conversejs a:active,
525 | #conversejs a:hover {
526 | outline: 0; }
527 | #conversejs abbr[title] {
528 | border-bottom: 1px dotted; }
529 | #conversejs b,
530 | #conversejs strong {
531 | font-weight: bold; }
532 | #conversejs dfn {
533 | font-style: italic; }
534 | #conversejs h1 {
535 | font-size: 2em;
536 | margin: 0.67em 0; }
537 | #conversejs mark {
538 | background: #ff0;
539 | color: #000; }
540 | #conversejs small {
541 | font-size: 80%; }
542 | #conversejs sub,
543 | #conversejs sup {
544 | font-size: 75%;
545 | line-height: 0;
546 | position: relative;
547 | vertical-align: baseline; }
548 | #conversejs sup {
549 | top: -0.5em; }
550 | #conversejs sub {
551 | bottom: -0.25em; }
552 | #conversejs img {
553 | border: 0; }
554 | #conversejs svg:not(:root) {
555 | overflow: hidden; }
556 | #conversejs figure {
557 | margin: 1em 40px; }
558 | #conversejs hr {
559 | box-sizing: content-box;
560 | height: 0; }
561 | #conversejs pre {
562 | overflow: auto; }
563 | #conversejs code,
564 | #conversejs kbd,
565 | #conversejs pre,
566 | #conversejs samp {
567 | font-family: monospace, monospace;
568 | font-size: 1em; }
569 | #conversejs button,
570 | #conversejs input,
571 | #conversejs optgroup,
572 | #conversejs select,
573 | #conversejs textarea {
574 | color: inherit;
575 | /* 1 */
576 | font: inherit;
577 | /* 2 */
578 | margin: 0;
579 | /* 3 */ }
580 | #conversejs button {
581 | overflow: visible; }
582 | #conversejs button,
583 | #conversejs select {
584 | text-transform: none; }
585 | #conversejs button,
586 | #conversejs html input[type="button"],
587 | #conversejs input[type="reset"],
588 | #conversejs input[type="submit"] {
589 | -webkit-appearance: button;
590 | /* 2 */
591 | cursor: pointer;
592 | /* 3 */ }
593 | #conversejs button[disabled],
594 | #conversejs html input[disabled] {
595 | cursor: default; }
596 | #conversejs button::-moz-focus-inner,
597 | #conversejs input::-moz-focus-inner {
598 | border: 0;
599 | padding: 0; }
600 | #conversejs input {
601 | line-height: normal; }
602 | #conversejs input[type="checkbox"],
603 | #conversejs input[type="radio"] {
604 | box-sizing: border-box;
605 | /* 1 */
606 | padding: 0;
607 | /* 2 */ }
608 | #conversejs input[type="number"]::-webkit-inner-spin-button,
609 | #conversejs input[type="number"]::-webkit-outer-spin-button {
610 | height: auto; }
611 | #conversejs input[type="search"] {
612 | -webkit-appearance: textfield;
613 | /* 1 */
614 | box-sizing: content-box;
615 | /* 2 */ }
616 | #conversejs input[type="search"]::-webkit-search-cancel-button,
617 | #conversejs input[type="search"]::-webkit-search-decoration {
618 | -webkit-appearance: none; }
619 | #conversejs fieldset {
620 | border: 1px solid #c0c0c0;
621 | margin: 0 2px;
622 | padding: 0.35em 0.625em 0.75em; }
623 | #conversejs legend {
624 | border: 0;
625 | /* 1 */
626 | padding: 0;
627 | /* 2 */ }
628 | #conversejs textarea {
629 | overflow: auto; }
630 | #conversejs optgroup {
631 | font-weight: bold; }
632 | #conversejs table {
633 | border-collapse: collapse;
634 | border-spacing: 0; }
635 | #conversejs td,
636 | #conversejs th {
637 | padding: 0; }
638 | #conversejs .hidden,
639 | #conversejs [hidden] {
640 | display: none !important; }
641 | #conversejs .pure-img {
642 | max-width: 100%;
643 | height: auto;
644 | display: block; }
645 | #conversejs .pure-form input[type="text"],
646 | #conversejs .pure-form input[type="password"],
647 | #conversejs .pure-form input[type="email"],
648 | #conversejs .pure-form input[type="url"],
649 | #conversejs .pure-form input[type="date"],
650 | #conversejs .pure-form input[type="month"],
651 | #conversejs .pure-form input[type="time"],
652 | #conversejs .pure-form input[type="datetime"],
653 | #conversejs .pure-form input[type="datetime-local"],
654 | #conversejs .pure-form input[type="week"],
655 | #conversejs .pure-form input[type="number"],
656 | #conversejs .pure-form input[type="search"],
657 | #conversejs .pure-form input[type="tel"],
658 | #conversejs .pure-form input[type="color"],
659 | #conversejs .pure-form select,
660 | #conversejs .pure-form textarea {
661 | padding: 0.5em 0.6em;
662 | display: inline-block;
663 | border: 1px solid #ccc;
664 | box-shadow: inset 0 1px 3px #ddd;
665 | border-radius: 4px;
666 | vertical-align: middle;
667 | -webkit-box-sizing: border-box;
668 | -moz-box-sizing: border-box;
669 | box-sizing: border-box; }
670 | #conversejs .pure-form input:not([type]) {
671 | padding: 0.5em 0.6em;
672 | display: inline-block;
673 | border: 1px solid #ccc;
674 | box-shadow: inset 0 1px 3px #ddd;
675 | border-radius: 4px;
676 | -webkit-box-sizing: border-box;
677 | -moz-box-sizing: border-box;
678 | box-sizing: border-box; }
679 | #conversejs .pure-form input[type="color"] {
680 | padding: 0.2em 0.5em; }
681 | #conversejs .pure-form input[type="text"]:focus,
682 | #conversejs .pure-form input[type="password"]:focus,
683 | #conversejs .pure-form input[type="email"]:focus,
684 | #conversejs .pure-form input[type="url"]:focus,
685 | #conversejs .pure-form input[type="date"]:focus,
686 | #conversejs .pure-form input[type="month"]:focus,
687 | #conversejs .pure-form input[type="time"]:focus,
688 | #conversejs .pure-form input[type="datetime"]:focus,
689 | #conversejs .pure-form input[type="datetime-local"]:focus,
690 | #conversejs .pure-form input[type="week"]:focus,
691 | #conversejs .pure-form input[type="number"]:focus,
692 | #conversejs .pure-form input[type="search"]:focus,
693 | #conversejs .pure-form input[type="tel"]:focus,
694 | #conversejs .pure-form input[type="color"]:focus,
695 | #conversejs .pure-form select:focus,
696 | #conversejs .pure-form textarea:focus {
697 | outline: 0;
698 | border-color: #1A9707; }
699 | #conversejs .pure-form input:not([type]):focus {
700 | outline: 0;
701 | border-color: #1A9707; }
702 | #conversejs .pure-form input[type="file"]:focus,
703 | #conversejs .pure-form input[type="radio"]:focus,
704 | #conversejs .pure-form input[type="checkbox"]:focus {
705 | outline: thin solid #1A9707;
706 | outline: 1px auto #1A9707; }
707 | #conversejs .pure-form .pure-checkbox,
708 | #conversejs .pure-form .pure-radio {
709 | margin: 0.5em 0;
710 | display: block; }
711 | #conversejs .pure-form input[type="text"][disabled],
712 | #conversejs .pure-form input[type="password"][disabled],
713 | #conversejs .pure-form input[type="email"][disabled],
714 | #conversejs .pure-form input[type="url"][disabled],
715 | #conversejs .pure-form input[type="date"][disabled],
716 | #conversejs .pure-form input[type="month"][disabled],
717 | #conversejs .pure-form input[type="time"][disabled],
718 | #conversejs .pure-form input[type="datetime"][disabled],
719 | #conversejs .pure-form input[type="datetime-local"][disabled],
720 | #conversejs .pure-form input[type="week"][disabled],
721 | #conversejs .pure-form input[type="number"][disabled],
722 | #conversejs .pure-form input[type="search"][disabled],
723 | #conversejs .pure-form input[type="tel"][disabled],
724 | #conversejs .pure-form input[type="color"][disabled],
725 | #conversejs .pure-form select[disabled],
726 | #conversejs .pure-form textarea[disabled] {
727 | cursor: not-allowed;
728 | background-color: #eaeded;
729 | color: #cad2d3; }
730 | #conversejs .pure-form input:not([type])[disabled] {
731 | cursor: not-allowed;
732 | background-color: #eaeded;
733 | color: #cad2d3; }
734 | #conversejs .pure-form input[readonly],
735 | #conversejs .pure-form select[readonly],
736 | #conversejs .pure-form textarea[readonly] {
737 | background-color: #eee;
738 | /* menu hover bg color */
739 | color: #777;
740 | /* menu text color */
741 | border-color: #ccc; }
742 | #conversejs .pure-form input:focus:invalid,
743 | #conversejs .pure-form textarea:focus:invalid,
744 | #conversejs .pure-form select:focus:invalid {
745 | color: #b94a48;
746 | border-color: #e9322d; }
747 | #conversejs .pure-form input[type="file"]:focus:invalid:focus,
748 | #conversejs .pure-form input[type="radio"]:focus:invalid:focus,
749 | #conversejs .pure-form input[type="checkbox"]:focus:invalid:focus {
750 | outline-color: #e9322d; }
751 | #conversejs .pure-form select {
752 | /* Normalizes the height; padding is not sufficient. */
753 | height: 2.25em;
754 | border: 1px solid #ccc;
755 | background-color: white; }
756 | #conversejs .pure-form select[multiple] {
757 | height: auto; }
758 | #conversejs .pure-form label {
759 | margin: 0.5em 0 0.2em; }
760 | #conversejs .pure-form fieldset {
761 | margin: 0;
762 | padding: 0.35em 0 0.35em;
763 | border: 0; }
764 | #conversejs .pure-form legend {
765 | display: block;
766 | width: 100%;
767 | padding: 0.3em 0;
768 | margin-bottom: 0.3em;
769 | color: #333;
770 | border-bottom: 1px solid #e5e5e5; }
771 | #conversejs .pure-form-stacked input[type="text"],
772 | #conversejs .pure-form-stacked input[type="password"],
773 | #conversejs .pure-form-stacked input[type="email"],
774 | #conversejs .pure-form-stacked input[type="url"],
775 | #conversejs .pure-form-stacked input[type="date"],
776 | #conversejs .pure-form-stacked input[type="month"],
777 | #conversejs .pure-form-stacked input[type="time"],
778 | #conversejs .pure-form-stacked input[type="datetime"],
779 | #conversejs .pure-form-stacked input[type="datetime-local"],
780 | #conversejs .pure-form-stacked input[type="week"],
781 | #conversejs .pure-form-stacked input[type="number"],
782 | #conversejs .pure-form-stacked input[type="search"],
783 | #conversejs .pure-form-stacked input[type="tel"],
784 | #conversejs .pure-form-stacked input[type="color"],
785 | #conversejs .pure-form-stacked input[type="file"],
786 | #conversejs .pure-form-stacked select,
787 | #conversejs .pure-form-stacked label,
788 | #conversejs .pure-form-stacked textarea {
789 | display: block;
790 | margin: 0.25em 0; }
791 | #conversejs .pure-form-stacked input:not([type]) {
792 | display: block;
793 | margin: 0.25em 0; }
794 | #conversejs .pure-form-aligned input,
795 | #conversejs .pure-form-aligned textarea,
796 | #conversejs .pure-form-aligned select,
797 | #conversejs .pure-form-aligned .pure-help-inline,
798 | #conversejs .pure-form-message-inline {
799 | display: inline-block;
800 | *display: inline;
801 | *zoom: 1;
802 | vertical-align: middle; }
803 | #conversejs .pure-form-aligned textarea {
804 | vertical-align: top; }
805 | #conversejs .pure-form-aligned .pure-control-group {
806 | margin-bottom: 0.5em; }
807 | #conversejs .pure-form-aligned .pure-control-group label {
808 | text-align: right;
809 | display: inline-block;
810 | vertical-align: middle;
811 | width: 10em;
812 | margin: 0 1em 0 0; }
813 | #conversejs .pure-form-aligned .pure-controls {
814 | margin: 1.5em 0 0 11em; }
815 | #conversejs .pure-form input.pure-input-rounded,
816 | #conversejs .pure-form .pure-input-rounded {
817 | border-radius: 2em;
818 | padding: 0.5em 1em; }
819 | #conversejs .pure-form .pure-group fieldset {
820 | margin-bottom: 10px; }
821 | #conversejs .pure-form .pure-group input,
822 | #conversejs .pure-form .pure-group textarea {
823 | display: block;
824 | padding: 10px;
825 | margin: 0 0 -1px;
826 | border-radius: 0;
827 | position: relative;
828 | top: -1px; }
829 | #conversejs .pure-form .pure-group input:focus,
830 | #conversejs .pure-form .pure-group textarea:focus {
831 | z-index: 3; }
832 | #conversejs .pure-form .pure-group input:first-child,
833 | #conversejs .pure-form .pure-group textarea:first-child {
834 | top: 1px;
835 | border-radius: 4px 4px 0 0;
836 | margin: 0; }
837 | #conversejs .pure-form .pure-group input:first-child:last-child,
838 | #conversejs .pure-form .pure-group textarea:first-child:last-child {
839 | top: 1px;
840 | border-radius: 4px;
841 | margin: 0; }
842 | #conversejs .pure-form .pure-group input:last-child,
843 | #conversejs .pure-form .pure-group textarea:last-child {
844 | top: -2px;
845 | border-radius: 0 0 4px 4px;
846 | margin: 0; }
847 | #conversejs .pure-form .pure-group button {
848 | margin: 0.35em 0; }
849 | #conversejs .pure-form .pure-input-1 {
850 | width: 100%; }
851 | #conversejs .pure-form .pure-input-3-4 {
852 | width: 75%; }
853 | #conversejs .pure-form .pure-input-2-3 {
854 | width: 66%; }
855 | #conversejs .pure-form .pure-input-1-2 {
856 | width: 50%; }
857 | #conversejs .pure-form .pure-input-1-3 {
858 | width: 33%; }
859 | #conversejs .pure-form .pure-input-1-4 {
860 | width: 25%; }
861 | #conversejs .pure-form .pure-help-inline,
862 | #conversejs .pure-form-message-inline {
863 | display: inline-block;
864 | padding-left: 0.3em;
865 | color: #666;
866 | vertical-align: middle;
867 | font-size: 0.875em; }
868 | #conversejs .pure-form-message {
869 | display: block;
870 | color: #666;
871 | font-size: 0.875em; }
872 | @media only screen and (max-width: 480px) {
873 | #conversejs {
874 | /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ }
875 | #conversejs .pure-form button[type="submit"] {
876 | margin: 0.7em 0 0; }
877 | #conversejs .pure-form input:not([type]),
878 | #conversejs .pure-form input[type="text"],
879 | #conversejs .pure-form input[type="password"],
880 | #conversejs .pure-form input[type="email"],
881 | #conversejs .pure-form input[type="url"],
882 | #conversejs .pure-form input[type="date"],
883 | #conversejs .pure-form input[type="month"],
884 | #conversejs .pure-form input[type="time"],
885 | #conversejs .pure-form input[type="datetime"],
886 | #conversejs .pure-form input[type="datetime-local"],
887 | #conversejs .pure-form input[type="week"],
888 | #conversejs .pure-form input[type="number"],
889 | #conversejs .pure-form input[type="search"],
890 | #conversejs .pure-form input[type="tel"],
891 | #conversejs .pure-form input[type="color"],
892 | #conversejs .pure-form label {
893 | margin-bottom: 0.3em;
894 | display: block; }
895 | #conversejs .pure-group input:not([type]),
896 | #conversejs .pure-group input[type="text"],
897 | #conversejs .pure-group input[type="password"],
898 | #conversejs .pure-group input[type="email"],
899 | #conversejs .pure-group input[type="url"],
900 | #conversejs .pure-group input[type="date"],
901 | #conversejs .pure-group input[type="month"],
902 | #conversejs .pure-group input[type="time"],
903 | #conversejs .pure-group input[type="datetime"],
904 | #conversejs .pure-group input[type="datetime-local"],
905 | #conversejs .pure-group input[type="week"],
906 | #conversejs .pure-group input[type="number"],
907 | #conversejs .pure-group input[type="search"],
908 | #conversejs .pure-group input[type="tel"],
909 | #conversejs .pure-group input[type="color"] {
910 | margin-bottom: 0; }
911 | #conversejs .pure-form-aligned .pure-control-group label {
912 | margin-bottom: 0.3em;
913 | text-align: left;
914 | display: block;
915 | width: 100%; }
916 | #conversejs .pure-form-aligned .pure-controls {
917 | margin: 1.5em 0 0 0; }
918 | #conversejs .pure-form .pure-help-inline,
919 | #conversejs .pure-form-message-inline,
920 | #conversejs .pure-form-message {
921 | display: block;
922 | font-size: 0.75em;
923 | /* Increased bottom padding to make it group with its related input element. */
924 | padding: 0.2em 0 0.8em; } }
925 | #conversejs .pure-button {
926 | /* Structure */
927 | display: inline-block;
928 | zoom: 1;
929 | line-height: normal;
930 | white-space: nowrap;
931 | vertical-align: middle;
932 | text-align: center;
933 | cursor: pointer;
934 | -webkit-user-drag: none;
935 | -webkit-user-select: none;
936 | -moz-user-select: none;
937 | -ms-user-select: none;
938 | user-select: none;
939 | -webkit-box-sizing: border-box;
940 | -moz-box-sizing: border-box;
941 | box-sizing: border-box; }
942 | #conversejs .pure-button::-moz-focus-inner {
943 | padding: 0;
944 | border: 0; }
945 | #conversejs .pure-button {
946 | font-family: inherit;
947 | font-size: 100%;
948 | padding: 0.5em 1em;
949 | color: #444;
950 | /* rgba not supported (IE 8) */
951 | color: rgba(0, 0, 0, 0.8);
952 | /* rgba supported */
953 | border: 1px solid #999;
954 | /*IE 6/7/8*/
955 | border: none transparent;
956 | /*IE9 + everything else*/
957 | background-color: #E6E6E6;
958 | text-decoration: none;
959 | border-radius: 2px; }
960 | #conversejs .pure-button-hover,
961 | #conversejs .pure-button:hover,
962 | #conversejs .pure-button:focus {
963 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000',GradientType=0);
964 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0, 0, 0, 0.05)), to(rgba(0, 0, 0, 0.1)));
965 | background-image: -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.1));
966 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.1));
967 | background-image: -o-linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.1));
968 | background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.1)); }
969 | #conversejs .pure-button:focus {
970 | outline: 0; }
971 | #conversejs .pure-button-active,
972 | #conversejs .pure-button:active {
973 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 0 6px rgba(0, 0, 0, 0.2) inset;
974 | border-color: #000 \9; }
975 | #conversejs .pure-button[disabled],
976 | #conversejs .pure-button-disabled,
977 | #conversejs .pure-button-disabled:hover,
978 | #conversejs .pure-button-disabled:focus,
979 | #conversejs .pure-button-disabled:active {
980 | border: none;
981 | background-image: none;
982 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
983 | filter: alpha(opacity=40);
984 | -khtml-opacity: 0.40;
985 | -moz-opacity: 0.40;
986 | opacity: 0.40;
987 | cursor: not-allowed;
988 | box-shadow: none; }
989 | #conversejs .pure-button-hidden {
990 | display: none; }
991 | #conversejs .pure-button::-moz-focus-inner {
992 | padding: 0;
993 | border: 0; }
994 | #conversejs .pure-button-primary,
995 | #conversejs .pure-button-selected,
996 | #conversejs a.pure-button-primary,
997 | #conversejs a.pure-button-selected {
998 | background-color: #0078e7;
999 | color: #fff; }
1000 | #conversejs *, #conversejs *:before, #conversejs *:after {
1001 | -webkit-box-sizing: border-box;
1002 | -moz-box-sizing: border-box;
1003 | box-sizing: border-box; }
1004 | @media screen and (max-width: 480px) {
1005 | #conversejs {
1006 | margin: 0;
1007 | right: 10px;
1008 | left: 10px;
1009 | bottom: 5px; } }
1010 | @media screen and (max-height: 450px) {
1011 | #conversejs {
1012 | margin: 0;
1013 | right: 10px;
1014 | left: 10px;
1015 | bottom: 5px; } }
1016 | #conversejs ul li {
1017 | height: auto; }
1018 | #conversejs div, #conversejs span, #conversejs h1, #conversejs h2, #conversejs h3, #conversejs h4, #conversejs h5, #conversejs h6, #conversejs p, #conversejs blockquote,
1019 | #conversejs pre, #conversejs a, #conversejs em, #conversejs img, #conversejs strong, #conversejs dl, #conversejs dt, #conversejs dd, #conversejs ol, #conversejs ul, #conversejs li,
1020 | #conversejs fieldset, #conversejs form, #conversejs label, #conversejs legend, #conversejs table, #conversejs caption, #conversejs tbody,
1021 | #conversejs tfoot, #conversejs thead, #conversejs tr, #conversejs th, #conversejs td, #conversejs article, #conversejs aside, #conversejs canvas, #conversejs details,
1022 | #conversejs embed, #conversejs figure, #conversejs figcaption, #conversejs footer, #conversejs header, #conversejs hgroup, #conversejs menu,
1023 | #conversejs nav, #conversejs output, #conversejs ruby, #conversejs section, #conversejs summary, #conversejs time, #conversejs mark, #conversejs audio, #conversejs video {
1024 | margin: 0;
1025 | padding: 0;
1026 | border: 0;
1027 | font: inherit;
1028 | vertical-align: baseline; }
1029 | #conversejs textarea,
1030 | #conversejs input[type=submit], #conversejs input[type=button],
1031 | #conversejs input[type=text], #conversejs input[type=password],
1032 | #conversejs button {
1033 | font-size: 14px;
1034 | padding: 0.25em;
1035 | min-height: 0; }
1036 | #conversejs strong {
1037 | font-weight: 700; }
1038 | #conversejs ol, #conversejs ul {
1039 | list-style: none; }
1040 | #conversejs li {
1041 | height: 10px; }
1042 | #conversejs ul, #conversejs ol, #conversejs dl {
1043 | font: inherit;
1044 | margin: 0; }
1045 | #conversejs a, #conversejs a:visited {
1046 | text-decoration: none;
1047 | color: #2A9D8F;
1048 | text-shadow: none; }
1049 |
1050 | #conversejs {
1051 | bottom: 0;
1052 | color: #818479;
1053 | direction: ltr;
1054 | display: block;
1055 | font-size: 14px;
1056 | height: 35px;
1057 | position: fixed;
1058 | right: 0;
1059 | width: auto;
1060 | z-index: 1031; }
1061 | @media screen and (max-height: 450px) {
1062 | #conversejs {
1063 | width: 100%;
1064 | width: 100vw; } }
1065 | @media screen and (max-width: 480px) {
1066 | #conversejs {
1067 | width: 100%;
1068 | width: 100vw; } }
1069 | #conversejs ::selection {
1070 | background-color: #DCF9F6; }
1071 | #conversejs ::-moz-selection {
1072 | background-color: #DCF9F6; }
1073 | #conversejs .no-text-select {
1074 | -webkit-touch-callout: none;
1075 | -webkit-user-select: none;
1076 | -moz-user-select: none;
1077 | -ms-user-select: none;
1078 | user-select: none; }
1079 | #conversejs .emoticon {
1080 | font-size: 14px; }
1081 | #conversejs .left {
1082 | float: left; }
1083 | #conversejs .right {
1084 | float: right; }
1085 | #conversejs .centered {
1086 | text-align: center;
1087 | display: block;
1088 | margin: 5em auto; }
1089 | #conversejs .hor_centered {
1090 | text-align: center;
1091 | display: block;
1092 | margin: 0 auto;
1093 | clear: both; }
1094 | #conversejs .hidden {
1095 | display: none; }
1096 | #conversejs .locked {
1097 | padding-right: 22px; }
1098 | @-webkit-keyframes spin {
1099 | from {
1100 | -webkit-transform: rotate(0deg); }
1101 | to {
1102 | -webkit-transform: rotate(359deg); } }
1103 | @-moz-keyframes spin {
1104 | from {
1105 | -moz-transform: rotate(0deg); }
1106 | to {
1107 | -moz-transform: rotate(359deg); } }
1108 | @keyframes spin {
1109 | from {
1110 | -webkit-transform: rotate(0deg);
1111 | -moz-transform: rotate(0deg);
1112 | -ms-transform: rotate(0deg);
1113 | -o-transform: rotate(0deg);
1114 | transform: rotate(0deg); }
1115 | to {
1116 | -webkit-transform: rotate(359deg);
1117 | -moz-transform: rotate(359deg);
1118 | -ms-transform: rotate(359deg);
1119 | -o-transform: rotate(359deg);
1120 | transform: rotate(359deg); } }
1121 | #conversejs .spinner {
1122 | -webkit-animation: spin 2s infinite, linear;
1123 | -moz-animation: spin 2s infinite, linear;
1124 | animation: spin 2s infinite, linear;
1125 | display: block;
1126 | text-align: center;
1127 | margin: 5px; }
1128 | #conversejs .spinner:before {
1129 | font-size: 24px;
1130 | font-family: 'Converse-js' !important;
1131 | content: "\231b"; }
1132 | #conversejs .button-group,
1133 | #conversejs .input-button-group {
1134 | display: table; }
1135 | #conversejs .button-group {
1136 | width: 100%; }
1137 | #conversejs .input-button-group button,
1138 | #conversejs .input-button-group input {
1139 | display: table-cell; }
1140 | #conversejs .error {
1141 | color: red; }
1142 | #conversejs .reg-feedback {
1143 | font-size: 85%; }
1144 | #conversejs .reg-feedback,
1145 | #conversejs #converse-login .conn-feedback {
1146 | display: block;
1147 | text-align: center;
1148 | width: 100%; }
1149 | #conversejs a.restore-chat {
1150 | padding: 1px 0 1px 5px;
1151 | color: white;
1152 | line-height: 15px;
1153 | display: block;
1154 | overflow: hidden;
1155 | text-overflow: ellipsis;
1156 | white-space: nowrap; }
1157 | #conversejs a.restore-chat:visited {
1158 | color: white; }
1159 | #conversejs .activated {
1160 | display: block !important; }
1161 | #conversejs .pure-button {
1162 | border-radius: 4px; }
1163 | #conversejs .button-primary {
1164 | color: white;
1165 | background-color: #2AC611; }
1166 | #conversejs .button-secondary {
1167 | color: white;
1168 | background-color: #83A0D6; }
1169 | #conversejs .button-cancel {
1170 | color: white;
1171 | background-color: #D24E2B; }
1172 | #conversejs form.pure-form.converse-form {
1173 | background: white;
1174 | margin: 1em; }
1175 | #conversejs form.pure-form.converse-form legend {
1176 | color: #818479; }
1177 | #conversejs form.pure-form.converse-form label {
1178 | margin-top: 1em; }
1179 | #conversejs form.pure-form.converse-form input[type=text],
1180 | #conversejs form.pure-form.converse-form input[type=password],
1181 | #conversejs form.pure-form.converse-form input[type=number],
1182 | #conversejs form.pure-form.converse-form input[type=button],
1183 | #conversejs form.pure-form.converse-form input[type=submit] {
1184 | height: 2.2em; }
1185 | #conversejs form.pure-form.converse-form input[type=button],
1186 | #conversejs form.pure-form.converse-form input[type=submit] {
1187 | padding-left: 1em;
1188 | padding-right: 1em;
1189 | margin-right: 1em; }
1190 | #conversejs form.pure-form.converse-form input.error {
1191 | border: 1px solid red;
1192 | color: #818479; }
1193 | #conversejs form.pure-form.converse-form .form-help {
1194 | color: gray;
1195 | font-size: 85%;
1196 | padding-top: 0.5em; }
1197 | #conversejs form.pure-form.converse-form .form-help:hover {
1198 | color: #818479; }
1199 | #conversejs .chat-textarea-chatbox-selected {
1200 | border: 1px solid #578308;
1201 | margin: 0; }
1202 | #conversejs .chat-textarea-chatroom-selected {
1203 | border: 2px solid #2A9D8F;
1204 | margin: 0; }
1205 | #conversejs .dropdown dt,
1206 | #conversejs .dropdown ul {
1207 | margin: 0;
1208 | padding: 0; }
1209 |
1210 | #conversejs .flyout {
1211 | border-radius: 4px;
1212 | bottom: 6px;
1213 | display: block;
1214 | position: absolute; }
1215 | @media screen and (max-height: 450px) {
1216 | #conversejs .flyout {
1217 | border-radius: 0; } }
1218 | @media screen and (max-width: 480px) {
1219 | #conversejs .flyout {
1220 | border-radius: 0; } }
1221 | @media screen and (max-height: 450px) {
1222 | #conversejs .flyout {
1223 | bottom: 0; } }
1224 | @media screen and (max-width: 480px) {
1225 | #conversejs .flyout {
1226 | bottom: 0; } }
1227 | #conversejs .chat-head {
1228 | border-top-left-radius: 4px;
1229 | border-top-right-radius: 4px;
1230 | color: #ffffff;
1231 | font-size: 100%;
1232 | height: 55px;
1233 | margin: 0;
1234 | padding: 5px;
1235 | position: relative; }
1236 | @media screen and (max-height: 450px) {
1237 | #conversejs .chat-head {
1238 | border-top-left-radius: 0;
1239 | border-top-right-radius: 0; } }
1240 | @media screen and (max-width: 480px) {
1241 | #conversejs .chat-head {
1242 | border-top-left-radius: 0;
1243 | border-top-right-radius: 0; } }
1244 | #conversejs .chat-head .avatar {
1245 | margin-right: 0.5em;
1246 | border-radius: 50%;
1247 | float: left; }
1248 | #conversejs .chat-head.chat-head-chatbox {
1249 | background-color: #F4A261; }
1250 | #conversejs .chat-head .user-custom-message {
1251 | clear: left;
1252 | color: white;
1253 | font-size: 80%;
1254 | font-style: italic;
1255 | height: 1.3em;
1256 | overflow: hidden;
1257 | text-overflow: ellipsis;
1258 | white-space: nowrap;
1259 | margin: 0;
1260 | padding-top: 0.2em; }
1261 | #conversejs .chatbox-btn {
1262 | border-radius: 50%;
1263 | border: 1px solid white;
1264 | color: white;
1265 | cursor: pointer;
1266 | display: inline-block;
1267 | float: right;
1268 | font-size: 9px;
1269 | margin: 0;
1270 | margin-right: 0.2em;
1271 | padding: 0.5em 0.5em 0.3em 0.5em;
1272 | text-decoration: none; }
1273 | #conversejs .chatbox-btn:active {
1274 | position: relative;
1275 | top: 1px; }
1276 | #conversejs .chatbox {
1277 | display: block;
1278 | float: right;
1279 | height: 35px;
1280 | margin: 0 0.5em;
1281 | width: 200px; }
1282 | @media screen and (max-height: 450px) {
1283 | #conversejs .chatbox {
1284 | margin: 0;
1285 | width: 100%; } }
1286 | @media screen and (max-width: 480px) {
1287 | #conversejs .chatbox {
1288 | margin: 0;
1289 | width: 100%; } }
1290 | #conversejs .chatbox .box-flyout {
1291 | background-color: white;
1292 | box-shadow: 1px 3px 5px 3px rgba(0, 0, 0, 0.4);
1293 | height: 450px;
1294 | min-height: 225px;
1295 | min-width: 200px;
1296 | width: 200px;
1297 | z-index: 1; }
1298 | @media screen and (max-height: 450px) {
1299 | #conversejs .chatbox .box-flyout {
1300 | height: 400px;
1301 | width: 100%;
1302 | height: 100vh; } }
1303 | @media screen and (max-width: 480px) {
1304 | #conversejs .chatbox .box-flyout {
1305 | height: 400px;
1306 | width: 100%;
1307 | height: 100vh; } }
1308 | #conversejs .chatbox .chat-title {
1309 | color: white;
1310 | line-height: 15px;
1311 | display: block;
1312 | text-overflow: ellipsis;
1313 | overflow: hidden;
1314 | height: 2em; }
1315 | #conversejs .chatbox .chat-title a {
1316 | color: white;
1317 | width: 100%; }
1318 | #conversejs .chatbox .chat-body {
1319 | background-color: white;
1320 | border-bottom-left-radius: 4px;
1321 | border-bottom-right-radius: 4px;
1322 | border-top: 0;
1323 | height: 289px;
1324 | height: -webkit-calc(100% - 55px);
1325 | height: calc(100% - 55px); }
1326 | @media screen and (max-height: 450px) {
1327 | #conversejs .chatbox .chat-body {
1328 | border-bottom-left-radius: 0;
1329 | border-bottom-right-radius: 0; } }
1330 | @media screen and (max-width: 480px) {
1331 | #conversejs .chatbox .chat-body {
1332 | border-bottom-left-radius: 0;
1333 | border-bottom-right-radius: 0; } }
1334 | #conversejs .chatbox .chat-body p {
1335 | color: #818479;
1336 | font-size: 14px;
1337 | margin: 0;
1338 | padding: 5px; }
1339 | #conversejs .chatbox .chat-body .chat-info {
1340 | color: #D24E2B;
1341 | margin: 0.3em; }
1342 | #conversejs .chatbox .chat-body .chat-info.chat-event {
1343 | clear: left;
1344 | font-style: italic; }
1345 | #conversejs .chatbox .chat-body .chat-info.chat-error {
1346 | color: #D24E2B;
1347 | font-weight: bold; }
1348 | #conversejs .chatbox .chat-body .chat-info.chat-date {
1349 | display: inline-block;
1350 | margin-top: 1em; }
1351 | #conversejs .chatbox .chat-body .chat-image {
1352 | max-width: 100%;
1353 | max-height: 100%; }
1354 | #conversejs .chatbox .chat-body .chat-message {
1355 | margin: 0.3em; }
1356 | #conversejs .chatbox .chat-body .chat-message span {
1357 | display: inline-block; }
1358 | #conversejs .chatbox .chat-body .chat-message span.chat-msg-author {
1359 | max-width: 100%;
1360 | font-weight: bold;
1361 | white-space: nowrap;
1362 | float: left;
1363 | text-overflow: ellipsis;
1364 | overflow: hidden; }
1365 | #conversejs .chatbox .chat-body .chat-message span.chat-msg-them {
1366 | color: #1A9707; }
1367 | #conversejs .chatbox .chat-body .chat-message span.chat-msg-me {
1368 | color: #2A9D8F; }
1369 | #conversejs .chatbox .chat-body .chat-message span.chat-msg-content {
1370 | max-width: 100%;
1371 | word-wrap: break-word; }
1372 | #conversejs .chatbox .chat-body .delayed .chat-msg-them {
1373 | color: #FB5D50; }
1374 | #conversejs .chatbox .chat-body .delayed .chat-msg-me {
1375 | color: #7EABBB; }
1376 | #conversejs .chatbox .new-msgs-indicator {
1377 | position: absolute;
1378 | width: 100%;
1379 | cursor: pointer;
1380 | background-color: #F4A261;
1381 | color: #FCFDFD;
1382 | padding: 0.3em;
1383 | font-size: 0.9em;
1384 | text-align: center;
1385 | z-index: 20; }
1386 | #conversejs .chatbox .chat-content {
1387 | position: relative;
1388 | padding: 0.5em;
1389 | font-size: 13px;
1390 | color: #818479;
1391 | overflow-y: auto;
1392 | border: 0;
1393 | background-color: #ffffff;
1394 | line-height: 1.3em;
1395 | height: 206px;
1396 | height: calc(100% - 96px); }
1397 | #conversejs .chatbox .dropdown {
1398 | /* status dropdown styles */
1399 | background-color: #FCFDFD; }
1400 | #conversejs .chatbox .dropdown dd {
1401 | margin: 0;
1402 | padding: 0;
1403 | position: relative; }
1404 | #conversejs .chatbox form.sendXMPPMessage {
1405 | -moz-background-clip: padding;
1406 | -webkit-background-clip: padding-box;
1407 | border-bottom-left-radius: 4px;
1408 | border-bottom-right-radius: 4px;
1409 | background-clip: padding-box;
1410 | background: white;
1411 | border-top: 1px solid #BBB;
1412 | border: 0;
1413 | margin: 0;
1414 | padding: 0;
1415 | position: relative;
1416 | height: 95px;
1417 | min-width: 200px; }
1418 | @media screen and (max-height: 450px) {
1419 | #conversejs .chatbox form.sendXMPPMessage {
1420 | width: 100%; } }
1421 | @media screen and (max-width: 480px) {
1422 | #conversejs .chatbox form.sendXMPPMessage {
1423 | width: 100%; } }
1424 | #conversejs .chatbox form.sendXMPPMessage .chat-textarea {
1425 | border-bottom-left-radius: 4px;
1426 | border-bottom-right-radius: 4px;
1427 | border: 0;
1428 | height: 70px;
1429 | padding: 0.5em;
1430 | width: 100%;
1431 | resize: none; }
1432 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar {
1433 | font-size: 14px;
1434 | margin: 0;
1435 | padding: 5px;
1436 | height: 25px;
1437 | display: block;
1438 | background-color: #FFF5EE; }
1439 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar a {
1440 | color: #2A9D8F; }
1441 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .chat-toolbar-text {
1442 | font-size: 12px;
1443 | padding-right: 3px;
1444 | text-shadow: 0 1px 0 white; }
1445 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a,
1446 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted {
1447 | color: #D24E2B; }
1448 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unverified a,
1449 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unverified {
1450 | color: #cf5300; }
1451 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .private a,
1452 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .private {
1453 | color: #4b7003; }
1454 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-occupants,
1455 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-clear,
1456 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr {
1457 | float: right; }
1458 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li {
1459 | display: inline-block;
1460 | list-style: none;
1461 | padding: 0 3px 0 3px;
1462 | cursor: pointer;
1463 | margin-top: 1px; }
1464 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar li:hover {
1465 | cursor: pointer; }
1466 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul {
1467 | background: #fff;
1468 | bottom: 100%;
1469 | box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
1470 | display: none;
1471 | font-size: 12px;
1472 | margin: 0;
1473 | position: absolute;
1474 | right: 0; }
1475 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul li {
1476 | cursor: pointer;
1477 | list-style: none;
1478 | position: relative; }
1479 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul li a:hover {
1480 | color: #8f2831; }
1481 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley {
1482 | color: #2A9D8F;
1483 | padding-left: 5px; }
1484 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li {
1485 | font-size: 14px;
1486 | padding: 5px;
1487 | z-index: 98; }
1488 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li:hover {
1489 | background-color: #DCF9F6; }
1490 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li {
1491 | padding: 7px;
1492 | background-color: white;
1493 | display: block;
1494 | z-index: 99; }
1495 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li a {
1496 | -moz-transition: background-color 0.2s ease-in-out;
1497 | -webkit-transition: background-color 0.2s ease-in-out;
1498 | transition: background-color 0.2s ease-in-out;
1499 | display: block;
1500 | padding: 1px;
1501 | text-decoration: none; }
1502 | #conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li:hover {
1503 | background-color: #DCF9F6; }
1504 | #conversejs .chatbox .dragresize {
1505 | background: transparent;
1506 | border: 0;
1507 | margin: 0;
1508 | position: absolute;
1509 | top: 0;
1510 | z-index: 20; }
1511 | #conversejs .chatbox .dragresize-top {
1512 | cursor: n-resize;
1513 | height: 5px;
1514 | width: 100%; }
1515 | #conversejs .chatbox .dragresize-left {
1516 | cursor: w-resize;
1517 | width: 5px;
1518 | height: 100%;
1519 | left: 0; }
1520 | #conversejs .chatbox .dragresize-topleft {
1521 | cursor: nw-resize;
1522 | width: 15px;
1523 | height: 15px;
1524 | top: 0;
1525 | left: 0; }
1526 |
1527 | #conversejs #controlbox {
1528 | display: none;
1529 | margin-right: 1em; }
1530 | @media screen and (max-width: 480px) {
1531 | #conversejs #controlbox {
1532 | margin: 0; } }
1533 | @media screen and (max-height: 450px) {
1534 | #conversejs #controlbox {
1535 | margin: 0; } }
1536 | #conversejs #controlbox .controlbox-head {
1537 | background-color: #577BDD;
1538 | border-top-left-radius: 4px;
1539 | border-top-right-radius: 4px;
1540 | color: white;
1541 | height: 55px;
1542 | margin: 0;
1543 | padding: 6px 6px 6px 0; }
1544 | @media screen and (max-height: 450px) {
1545 | #conversejs #controlbox .controlbox-head {
1546 | border-top-left-radius: 0;
1547 | border-top-right-radius: 0; } }
1548 | @media screen and (max-width: 480px) {
1549 | #conversejs #controlbox .controlbox-head {
1550 | border-top-left-radius: 0;
1551 | border-top-right-radius: 0; } }
1552 | #conversejs #controlbox form.search-xmpp-contact {
1553 | margin: 0;
1554 | padding-left: 5px;
1555 | padding: 0 0 5px 5px; }
1556 | #conversejs #controlbox form.search-xmpp-contact input {
1557 | width: 8em; }
1558 | #conversejs #controlbox a.subscribe-to-user {
1559 | padding-left: 2em;
1560 | font-weight: bold; }
1561 | #conversejs #controlbox #converse-register {
1562 | background: white; }
1563 | #conversejs #controlbox #converse-register .title {
1564 | font-weight: bold; }
1565 | #conversejs #controlbox #converse-register .info {
1566 | font-style: italic;
1567 | color: green;
1568 | font-size: 85%;
1569 | margin: 5px 0; }
1570 | #conversejs #controlbox #converse-register .form-errors {
1571 | color: red;
1572 | display: none; }
1573 | #conversejs #controlbox #converse-register .provider-title {
1574 | font-size: 22px; }
1575 | #conversejs #controlbox #converse-register .provider-score {
1576 | width: 178px;
1577 | margin-bottom: 8px; }
1578 | #conversejs #controlbox #converse-register .form-help .url {
1579 | font-weight: bold;
1580 | color: #2A9D8F; }
1581 | #conversejs #controlbox #converse-register .input-group {
1582 | display: table;
1583 | margin: auto;
1584 | width: 100%; }
1585 | #conversejs #controlbox #converse-register .input-group span {
1586 | overflow-x: hidden;
1587 | text-overflow: ellipsis;
1588 | max-width: 110px; }
1589 | #conversejs #controlbox #converse-register .input-group span, #conversejs #controlbox #converse-register .input-group input[name=username] {
1590 | display: table-cell;
1591 | text-align: left; }
1592 | #conversejs #controlbox #converse-register .instructions {
1593 | color: gray;
1594 | font-size: 85%; }
1595 | #conversejs #controlbox #converse-register .instructions:hover {
1596 | color: #818479; }
1597 | #conversejs #controlbox #converse-register, #conversejs #controlbox #converse-login {
1598 | margin-top: 2em; }
1599 | #conversejs #controlbox #converse-register .login-anon, #conversejs #controlbox #converse-login .login-anon {
1600 | height: auto;
1601 | white-space: normal; }
1602 | #conversejs #controlbox #converse-register .save-submit, #conversejs #controlbox #converse-login .save-submit {
1603 | color: #436F64; }
1604 | #conversejs #controlbox #converse-register input, #conversejs #controlbox #converse-login input {
1605 | width: 100%;
1606 | margin: 0.5em 0; }
1607 | #conversejs #controlbox #users .add-converse-contact {
1608 | margin: 0 1em 0.75em 1em; }
1609 | #conversejs #controlbox #chatrooms form.add-chatroom input[type=button],
1610 | #conversejs #controlbox #chatrooms form.add-chatroom input[type=submit],
1611 | #conversejs #controlbox #chatrooms form.add-chatroom input[type=text] {
1612 | width: 100%; }
1613 | #conversejs #controlbox #chatrooms #available-chatrooms {
1614 | padding: 0 1em 2em 1em;
1615 | text-align: left; }
1616 | #conversejs #controlbox #chatrooms #available-chatrooms dt {
1617 | border: none;
1618 | color: #818479;
1619 | font-weight: normal;
1620 | padding: 0;
1621 | padding-bottom: 0.5em;
1622 | text-shadow: 0 1px 0 #FAFAFA; }
1623 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom {
1624 | border: none;
1625 | clear: both;
1626 | color: #818479;
1627 | display: block;
1628 | overflow: hidden;
1629 | padding: 0.4em;
1630 | text-shadow: 0 1px 0 #FAFAFA;
1631 | word-wrap: break-word; }
1632 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom:hover {
1633 | background-color: #DCF9F6; }
1634 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom a.room-info {
1635 | display: none;
1636 | clear: right;
1637 | display: block; }
1638 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom a.room-info:before {
1639 | font-size: 15px; }
1640 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom a.open-room {
1641 | float: left;
1642 | width: 85%; }
1643 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom .room-info {
1644 | font-size: 11px;
1645 | font-style: normal;
1646 | font-weight: normal; }
1647 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom li.room-info {
1648 | display: block;
1649 | margin-left: 5px; }
1650 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom p.room-info {
1651 | margin: 0;
1652 | padding: 0;
1653 | display: block;
1654 | white-space: normal; }
1655 | #conversejs #controlbox #chatrooms #available-chatrooms dd.available-chatroom div.room-info {
1656 | clear: left;
1657 | width: 100%; }
1658 | #conversejs #controlbox .dropdown a {
1659 | width: 148px;
1660 | display: inline-block;
1661 | line-height: 25px; }
1662 | #conversejs #controlbox .dropdown li {
1663 | list-style: none;
1664 | padding-left: 0; }
1665 | #conversejs #controlbox .dropdown dd ul {
1666 | padding: 0;
1667 | list-style: none;
1668 | position: absolute;
1669 | left: 0;
1670 | top: 0;
1671 | border: 1px solid #B1BFC4;
1672 | width: 100%;
1673 | z-index: 21;
1674 | background-color: #FCFDFD; }
1675 | #conversejs #controlbox .dropdown dd ul li:hover {
1676 | background-color: #DCF9F6; }
1677 | #conversejs #controlbox .dropdown dd.search-xmpp ul {
1678 | box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); }
1679 | #conversejs #controlbox .dropdown dd.search-xmpp ul li:hover {
1680 | background-color: #FCFDFD; }
1681 | #conversejs #controlbox .dropdown dt a span {
1682 | cursor: pointer;
1683 | display: block;
1684 | padding: 4px 7px 0 5px; }
1685 | #conversejs #controlbox #select-xmpp-status {
1686 | float: right;
1687 | margin-right: 0.5em; }
1688 | #conversejs #controlbox #set-custom-xmpp-status {
1689 | float: left;
1690 | padding: 0; }
1691 | #conversejs #controlbox #set-custom-xmpp-status fieldset {
1692 | padding: 0;
1693 | margin-top: -1px; }
1694 | #conversejs #controlbox #set-custom-xmpp-status input {
1695 | height: 26px;
1696 | width: -webkit-calc(100% - 40px);
1697 | width: calc(100% - 40px);
1698 | padding: 0 0 0 0.5em; }
1699 | #conversejs #controlbox #set-custom-xmpp-status input[type=submit] {
1700 | height: 26px;
1701 | width: 40px;
1702 | padding: 1px;
1703 | float: right; }
1704 | #conversejs #controlbox #controlbox-tabs {
1705 | text-align: center;
1706 | display: inline;
1707 | overflow: hidden;
1708 | font-size: 12px;
1709 | list-style-type: none;
1710 | /* single tab */ }
1711 | #conversejs #controlbox #controlbox-tabs li {
1712 | float: left;
1713 | list-style: none;
1714 | padding-left: 0;
1715 | text-shadow: white 0 1px 0;
1716 | width: 38%; }
1717 | #conversejs #controlbox #controlbox-tabs li a {
1718 | background-color: white;
1719 | border-bottom: 1px solid #CCC;
1720 | border-top-left-radius: 4px;
1721 | border-top-right-radius: 4px;
1722 | box-shadow: inset 2px -2px 20px rgba(0, 0, 0, 0.3);
1723 | color: #818479;
1724 | display: block;
1725 | font-size: 12px;
1726 | height: 54px;
1727 | line-height: 54px;
1728 | margin: 0;
1729 | text-align: center;
1730 | text-decoration: none; }
1731 | #conversejs #controlbox #controlbox-tabs li a:hover {
1732 | color: #818479; }
1733 | #conversejs #controlbox #controlbox-tabs li a.current, #conversejs #controlbox #controlbox-tabs li a.current:hover {
1734 | box-shadow: none;
1735 | border-bottom: 0;
1736 | height: 55px;
1737 | cursor: default;
1738 | color: #818479; }
1739 | #conversejs #controlbox .fancy-dropdown {
1740 | border: 1px solid #B1BFC4;
1741 | height: 25px;
1742 | border-radius: 4px;
1743 | text-align: left;
1744 | padding: 0;
1745 | padding-left: 0.3em; }
1746 | #conversejs #controlbox .fancy-dropdown .choose-xmpp-status {
1747 | width: 155px; }
1748 | #conversejs #controlbox .fancy-dropdown .choose-xmpp-status,
1749 | #conversejs #controlbox .fancy-dropdown .toggle-xmpp-contact-form {
1750 | text-shadow: 0 1px 0 #ffffff;
1751 | overflow: hidden;
1752 | text-overflow: ellipsis;
1753 | white-space: nowrap;
1754 | display: inline; }
1755 | #conversejs #controlbox .fancy-dropdown.no-border {
1756 | border: 0; }
1757 | #conversejs #controlbox #fancy-xmpp-status-select {
1758 | padding-left: 0; }
1759 | #conversejs #controlbox #fancy-xmpp-status-select .xmpp-status {
1760 | margin-left: 0.3em;
1761 | display: inline; }
1762 | #conversejs #controlbox #fancy-xmpp-status-select a.change-xmpp-status-message {
1763 | float: right;
1764 | clear: right;
1765 | width: 12px;
1766 | margin-right: 0.3em;
1767 | color: #2A9D8F; }
1768 | #conversejs #controlbox .controlbox-pane {
1769 | background-color: white;
1770 | border-bottom-left-radius: 4px;
1771 | border-bottom-right-radius: 4px;
1772 | border: 0;
1773 | font-size: 14px;
1774 | position: absolute;
1775 | text-align: center;
1776 | width: 100%;
1777 | height: 289px;
1778 | height: -webkit-calc(100% - 55px);
1779 | height: calc(100% - 55px);
1780 | overflow-y: auto;
1781 | overflow-x: hidden; }
1782 | #conversejs #controlbox .controlbox-pane label {
1783 | font-size: 14px;
1784 | font-weight: bold;
1785 | height: auto;
1786 | margin: 4px; }
1787 | #conversejs #controlbox .controlbox-pane dd {
1788 | margin-left: 0;
1789 | margin-bottom: 0; }
1790 | #conversejs #controlbox .controlbox-pane dd.odd {
1791 | background-color: #DCEAC5; }
1792 | #conversejs #controlbox #users {
1793 | overflow-y: hidden; }
1794 | #conversejs #controlbox .add-xmpp-contact {
1795 | background: none;
1796 | padding: 1em; }
1797 | #conversejs #controlbox .add-xmpp-contact input {
1798 | margin: 0 0 1rem;
1799 | width: 100%; }
1800 | #conversejs #controlbox .add-xmpp-contact button {
1801 | width: 100%; }
1802 | #conversejs #controlbox .xmpp-status-menu {
1803 | text-align: left;
1804 | box-shadow: 1px 4px 10px 1px rgba(0, 0, 0, 0.4); }
1805 | #conversejs #controlbox .xmpp-status-menu li {
1806 | padding: 2px; }
1807 | #conversejs #controlbox .xmpp-status-menu li a {
1808 | width: 100%;
1809 | padding: 0 8px; }
1810 | #conversejs #controlbox .xmpp-status-menu li a.logout,
1811 | #conversejs #controlbox .xmpp-status-menu li a.logout span {
1812 | color: #D24E2B; }
1813 | #conversejs #controlbox .set-xmpp-status {
1814 | background: none;
1815 | margin: 1em 1em 0.5em 1em; }
1816 | #conversejs #controlbox .set-xmpp-status .dropdown dd ul {
1817 | z-index: 22; }
1818 | #conversejs .toggle-controlbox {
1819 | background-color: #2A9D8F;
1820 | border-top-left-radius: 4px;
1821 | border-top-right-radius: 4px;
1822 | color: #0a0a0a;
1823 | float: right;
1824 | height: 100%;
1825 | margin: 0 0.5em;
1826 | padding: 10px 8px 0 8px; }
1827 | #conversejs .toggle-controlbox span {
1828 | color: white; }
1829 |
1830 | #conversejs #converse-roster {
1831 | text-align: left;
1832 | width: 100%;
1833 | position: relative;
1834 | margin: 1em 0 0 0;
1835 | height: 194px;
1836 | height: calc(100% - 50px - 20px);
1837 | overflow: hidden;
1838 | padding: 0;
1839 | padding-bottom: 3em; }
1840 | #conversejs #converse-roster.no-contact-requests {
1841 | height: calc(100% - 25px - 20px); }
1842 | #conversejs #converse-roster .search-xmpp ul li.chat-info {
1843 | padding-left: 10px; }
1844 | #conversejs #converse-roster .roster-filter-group {
1845 | margin: 0 1em;
1846 | width: 100%;
1847 | padding-right: 2em;
1848 | /* (jQ addClass:) if input has value: */
1849 | /* (jQ addClass:) if mouse is over the 'x' input area*/ }
1850 | #conversejs #converse-roster .roster-filter-group .roster-filter {
1851 | float: left;
1852 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAABNSURBVHjaXI7BDcAwCAMvyQjMyQ6dAbZiKfqoUK34g2zJh1dENIC7M8pMAPYdzAVY3d0ajNz9aypS/b5R6o+ZPdqoKgCq6h80KH3xDgBqNR97p8oAGQAAAABJRU5ErkJggg==) no-repeat right -20px center;
1853 | border: 1px solid #999;
1854 | font-size: 14px;
1855 | height: 25px;
1856 | margin: 0;
1857 | padding: 0;
1858 | padding-left: 0.4em;
1859 | width: 53%; }
1860 | #conversejs #converse-roster .roster-filter-group .roster-filter.x {
1861 | background-position: right 3px center; }
1862 | #conversejs #converse-roster .roster-filter-group .roster-filter.onX {
1863 | cursor: pointer; }
1864 | #conversejs #converse-roster .roster-filter-group .state-type {
1865 | float: left;
1866 | border: 1px solid #999;
1867 | font-size: calc(14px - 2px);
1868 | height: 25px;
1869 | margin: 0;
1870 | padding: 0;
1871 | padding-left: 0.4em;
1872 | width: 53%; }
1873 | #conversejs #converse-roster .roster-filter-group .filter-type {
1874 | display: table-cell;
1875 | float: right;
1876 | font-size: calc(14px - 2px);
1877 | height: 25px;
1878 | padding: 0;
1879 | width: 47%;
1880 | border-radius: 0;
1881 | border: 1px solid; }
1882 | #conversejs #converse-roster .roster-contacts {
1883 | margin: 0;
1884 | height: 100%;
1885 | overflow-x: hidden;
1886 | overflow-y: auto; }
1887 | #conversejs #converse-roster .roster-contacts dt.roster-group {
1888 | border: none;
1889 | color: #818479;
1890 | display: none;
1891 | font-weight: normal;
1892 | margin-top: 0.5em;
1893 | padding: 0.5em 1em;
1894 | text-shadow: 0 1px 0 #FAFAFA; }
1895 | #conversejs #converse-roster .roster-contacts dt.roster-group:hover {
1896 | background-color: #DCF9F6; }
1897 | #conversejs #converse-roster .roster-contacts dt.roster-group .group-toggle {
1898 | color: #818479;
1899 | display: block;
1900 | width: 100%; }
1901 | #conversejs #converse-roster .roster-contacts dd {
1902 | border: none;
1903 | clear: both;
1904 | color: #818479;
1905 | background-color: #FCFDFD;
1906 | display: block;
1907 | height: 24px;
1908 | overflow-y: hidden;
1909 | padding: 0.3em 0 0.3em 1em;
1910 | text-shadow: 0 1px 0 #FAFAFA;
1911 | line-height: 14px;
1912 | width: 100%; }
1913 | #conversejs #converse-roster .roster-contacts dd .open-chat {
1914 | max-width: 90%; }
1915 | #conversejs #converse-roster .roster-contacts dd:hover {
1916 | background-color: #DCF9F6; }
1917 | #conversejs #converse-roster .roster-contacts dd:hover .remove-xmpp-contact {
1918 | display: inline-block; }
1919 | #conversejs #converse-roster .roster-contacts dd:hover .open-chat {
1920 | width: 80%; }
1921 | #conversejs #converse-roster .roster-contacts dd.requesting-xmpp-contact.request-actions {
1922 | margin-left: 0.5em;
1923 | margin-bottom: 0.3em;
1924 | float: right; }
1925 | #conversejs #converse-roster .roster-contacts dd.requesting-xmpp-contact .req-contact-name {
1926 | width: 69%;
1927 | padding: 0; }
1928 | #conversejs #converse-roster .roster-contacts dd.current-xmpp-contact span {
1929 | font-size: 16px;
1930 | float: left;
1931 | color: #2A9D8F; }
1932 | #conversejs #converse-roster .roster-contacts dd.odd {
1933 | background-color: #DCEAC5;
1934 | /* Make this difference */ }
1935 | #conversejs #converse-roster .roster-contacts dd a, #conversejs #converse-roster .roster-contacts dd span {
1936 | text-shadow: 0 1px 0 #FAFAFA;
1937 | display: inline-block;
1938 | overflow: hidden;
1939 | white-space: nowrap;
1940 | text-overflow: ellipsis; }
1941 | #conversejs #converse-roster .roster-contacts dd span {
1942 | padding: 0 0.5em 0 0;
1943 | height: 100%; }
1944 | #conversejs #converse-roster .roster-contacts dd a.decline-xmpp-request {
1945 | margin-left: 5px; }
1946 | #conversejs #converse-roster .roster-contacts dd a.remove-xmpp-contact {
1947 | float: right;
1948 | margin-right: 1em;
1949 | display: none;
1950 | color: #818479; }
1951 | #conversejs #converse-roster span.pending-contact-name {
1952 | width: 80%; }
1953 |
1954 | #conversejs .add-chatroom input[type="submit"],
1955 | #conversejs .add-chatroom input[type="button"] {
1956 | margin: 0.3em 0; }
1957 | #conversejs .chat-head-chatroom {
1958 | background-color: #E76F51; }
1959 | #conversejs .chat-head-chatroom .chatroom-topic {
1960 | color: white;
1961 | font-size: 80%;
1962 | font-style: italic;
1963 | height: 1.3em;
1964 | overflow: hidden;
1965 | text-overflow: ellipsis;
1966 | white-space: nowrap;
1967 | margin: 0;
1968 | margin-top: 0.3em; }
1969 | #conversejs .chatroom {
1970 | width: 300px; }
1971 | @media screen and (max-height: 450px) {
1972 | #conversejs .chatroom {
1973 | width: 100%; } }
1974 | @media screen and (max-width: 480px) {
1975 | #conversejs .chatroom {
1976 | width: 100%; } }
1977 | #conversejs .chatroom .box-flyout {
1978 | min-width: 300px;
1979 | width: 300px; }
1980 | @media screen and (max-height: 450px) {
1981 | #conversejs .chatroom .box-flyout {
1982 | height: 400px;
1983 | width: 100%;
1984 | height: 100vh; } }
1985 | @media screen and (max-width: 480px) {
1986 | #conversejs .chatroom .box-flyout {
1987 | height: 400px;
1988 | width: 100%;
1989 | height: 100vh; } }
1990 | #conversejs .chatroom .box-flyout .chatroom-body {
1991 | height: 289px;
1992 | border-bottom-left-radius: 4px;
1993 | border-bottom-right-radius: 4px;
1994 | height: -webkit-calc(100% - 55px);
1995 | height: calc(100% - 55px);
1996 | background-color: white;
1997 | border-top: 0;
1998 | width: 100%; }
1999 | #conversejs .chatroom .box-flyout .chatroom-body .mentioned {
2000 | font-weight: bold; }
2001 | #conversejs .chatroom .box-flyout .chatroom-body .chat-msg-room {
2002 | color: #1A9707; }
2003 | #conversejs .chatroom .box-flyout .chatroom-body .chat-area {
2004 | word-wrap: break-word;
2005 | height: 100%;
2006 | width: 70%;
2007 | float: left;
2008 | min-width: 200px; }
2009 | #conversejs .chatroom .box-flyout .chatroom-body .chat-area .new-msgs-indicator {
2010 | background-color: #E76F51;
2011 | max-width: 70%; }
2012 | #conversejs .chatroom .box-flyout .chatroom-body .chat-area .chat-content {
2013 | padding: 0 0.5em 0 0.5em; }
2014 | #conversejs .chatroom .box-flyout .chatroom-body .chat-area.full {
2015 | min-width: 100%; }
2016 | #conversejs .chatroom .box-flyout .chatroom-body .chat-area.full .new-msgs-indicator {
2017 | min-width: 100%; }
2018 | #conversejs .chatroom .box-flyout .chatroom-body .occupants {
2019 | float: right;
2020 | vertical-align: top;
2021 | background-color: white;
2022 | overflow: hidden;
2023 | border-left: 1px solid #818479;
2024 | border-bottom-right-radius: 4px;
2025 | width: 30%;
2026 | height: 100%; }
2027 | #conversejs .chatroom .box-flyout .chatroom-body .occupants.hidden {
2028 | display: none; }
2029 | #conversejs .chatroom .box-flyout .chatroom-body .occupants .occupants-heading {
2030 | padding: 0.3em;
2031 | font-weight: bold; }
2032 | #conversejs .chatroom .box-flyout .chatroom-body .occupants .occupant-list {
2033 | height: 85%;
2034 | height: calc(100% - 70px);
2035 | overflow-x: hidden;
2036 | overflow-y: auto;
2037 | list-style: none; }
2038 | #conversejs .chatroom .box-flyout .chatroom-body .occupants .occupant-list li {
2039 | cursor: default;
2040 | display: block;
2041 | font-size: 12px;
2042 | overflow: hidden;
2043 | padding: 2px 5px;
2044 | text-overflow: ellipsis;
2045 | white-space: nowrap;
2046 | width: 100px; }
2047 | #conversejs .chatroom .box-flyout .chatroom-body .occupants .occupant-list li.occupant {
2048 | cursor: pointer; }
2049 | #conversejs .chatroom .box-flyout .chatroom-body .occupants .occupant-list li.moderator {
2050 | color: #D24E2B; }
2051 | #conversejs .chatroom .box-flyout .chatroom-body .chatroom-form-container {
2052 | background-color: white;
2053 | border-bottom-left-radius: 4px;
2054 | border-bottom-right-radius: 4px;
2055 | border: 0;
2056 | color: #818479;
2057 | font-size: 14px;
2058 | height: 289px;
2059 | height: -webkit-calc(100% - 55px);
2060 | height: calc(100% - 55px);
2061 | overflow-y: auto;
2062 | position: absolute; }
2063 | #conversejs .chatroom .box-flyout .chatroom-body .chatroom-form-container .validation-message {
2064 | font-size: 90%;
2065 | color: #D24E2B; }
2066 | #conversejs .chatroom .chat-textarea {
2067 | border-bottom-right-radius: 0; }
2068 | #conversejs .chatroom .room-invite {
2069 | margin: 0.3em; }
2070 | #conversejs .chatroom .room-invite .invited-contact {
2071 | margin: -1px 0 0 -1px;
2072 | width: 100%;
2073 | border: 1px solid #999; }
2074 | #conversejs .chatroom .room-invite .invited-contact.tt-input {
2075 | width: 100%;
2076 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkBCjE0uzKkOgAAAidJREFUKM+N0k+IEnEUB/D3cyscdagkWpHV0WGWREXm0AgOGkSJ07kh2UXYU5cOewm6Bp0KXG/tpSCv6hyEFQIhMEaE3yERYfwTOoqKGLQxDAbqYadLgu7J7/XxeY/3ez8EACDLsgljfMfj8ZxUKhXXYDAAnueBoqgyAMipVOovXAuSZdnUaDQeDofDs16vFyUIAjRNUwmCoG02G1AUdZ5IJN7GYrHfm3AvEAjcnUwmX0ajUdRqtV74fL6sruufKYoa6bp+fzabPUMI7ZfL5eImNHk8npNerxc1m80XHMe98fv9H3K5XDkSibxjWfb1arWaYoyPMMbCFqxUKi6CIODw8LDmdDq7oigaAACiKK5omv7KcdylpmlIkiTHFlRVFTRNUxVFqa/ROqIoGoqi5A3DgFartfU4Jp7ngSAI2uVyPZIk6dZmUZKk2w6H4xghBPF4HK7vWLbZbDCdTp+rqvpUkiS0RvV6/bTf7x8wDHMViURqm/AGAMgURZ232+1X1Wr102KxuEwmk3lZlo/7/f7BcrkkSZKs2e12tHXH/x/gHsY4jTE+0jQNGYYBCCFgGOaKJMkfjUaDZximGQ6HXzSbzZ+ZTMbY6oIxFgqFgqPT6YAgCMBxXM1ut6N0Op0fj8chi8XyjWXZ98Fg8DuCHZLNZh+USqWP8/n8idvt/hUKhV7u7QK9Xu8fmqanAJBQVXUfAGY7TQQAKBaLN8fjsdDtdh/run72Dzhf7XLe2UevAAAAAElFTkSuQmCC) no-repeat right 3px center; }
2077 | #conversejs .chatroom .room-invite .invited-contact.tt-input:focus {
2078 | border-color: #E76F51; }
2079 | #conversejs .chatroom .room-invite .invited-contact.tt-hint {
2080 | color: transparent;
2081 | background-color: white; }
2082 | #conversejs .chatroom .room-invite .tt-dropdown-menu {
2083 | width: 96%;
2084 | max-height: 250px;
2085 | background: #E76F51;
2086 | border-bottom-right-radius: 4px;
2087 | border-bottom-left-radius: 4px;
2088 | overflow-y: auto; }
2089 | #conversejs .chatroom .room-invite .tt-dropdown-menu .tt-suggestion p {
2090 | color: white;
2091 | cursor: pointer;
2092 | font-size: 11px;
2093 | text-overflow: ellipsis;
2094 | overflow-x: hidden; }
2095 | #conversejs .chatroom .room-invite .tt-dropdown-menu .tt-suggestion p:hover {
2096 | background-color: #FF977C; }
2097 | #conversejs .chatroom .room-invite .tt-dropdown-menu .tt-suggestion .tt-highlight {
2098 | background-color: #D24E2B; }
2099 |
2100 | #conversejs .chatbox.headlines .chat-head.chat-head-chatbox {
2101 | background-color: #2A9D8F; }
2102 |
2103 | #conversejs #minimized-chats {
2104 | border-top-left-radius: 4px;
2105 | border-top-right-radius: 4px;
2106 | color: white;
2107 | display: none;
2108 | float: right;
2109 | font-weight: bold;
2110 | height: 100%;
2111 | margin: 0 0.5em;
2112 | padding: 0;
2113 | width: 130px; }
2114 | #conversejs #minimized-chats #toggle-minimized-chats {
2115 | border-top-left-radius: 4px;
2116 | border-top-right-radius: 4px;
2117 | background-color: #2A9D8F;
2118 | color: white;
2119 | position: relative;
2120 | padding: 10px 0 0 0;
2121 | display: block;
2122 | width: 100%;
2123 | height: 100%;
2124 | text-align: center; }
2125 | #conversejs #minimized-chats .minimized-chats-flyout {
2126 | height: auto;
2127 | bottom: 35px; }
2128 | #conversejs #minimized-chats .minimized-chats-flyout .chat-head {
2129 | padding: 0.3em;
2130 | border-radius: 4px;
2131 | width: 130px;
2132 | height: 35px;
2133 | margin-bottom: 0.2em;
2134 | box-shadow: 1px 3px 5px 3px rgba(0, 0, 0, 0.4); }
2135 | #conversejs #minimized-chats .minimized-chats-flyout.minimized {
2136 | height: auto; }
2137 | #conversejs #minimized-chats .unread-message-count,
2138 | #conversejs #minimized-chats .chat-head-message-count {
2139 | font-weight: bold;
2140 | background-color: white;
2141 | border: 1px solid;
2142 | text-shadow: 1px 1px 0 #FAFAFA;
2143 | color: #D24E2B;
2144 | border-radius: 5px;
2145 | padding: 2px 4px;
2146 | font-size: 16px;
2147 | text-align: center;
2148 | position: absolute;
2149 | right: 116px;
2150 | bottom: 10px; }
2151 |
2152 | /*# sourceMappingURL=converse.css.map */
2153 |
--------------------------------------------------------------------------------