├── 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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /xmpp/static/images/dark-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /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 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /xmpp/static/images/bgtr.svg: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /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 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------