From 20e15b5623b09772a18cd3b8a084b2e5e99f27ba Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 6 Dec 2014 18:57:15 +0100 Subject: [PATCH] Sphinx changes. * Add buildout config for Sphinx * Add new Sphinx theme * Remove the built html theme files --- .gitignore | 20 +- Makefile | 2 +- bootstrap.py | 260 ++++ buildout.cfg | 22 + converse.js | 2 +- docs/doctrees/index.doctree | Bin 306620 -> 0 bytes docs/html/.buildinfo | 4 - docs/html/_sources/index.txt | 1479 -------------------- docs/html/_static/ajax-loader.gif | Bin 673 -> 0 bytes docs/html/_static/basic.css | 537 ------- docs/html/_static/comment-bright.png | Bin 3500 -> 0 bytes docs/html/_static/comment-close.png | Bin 3578 -> 0 bytes docs/html/_static/comment.png | Bin 3445 -> 0 bytes docs/html/_static/default.css | 256 ---- docs/html/_static/doctools.js | 238 ---- docs/html/_static/down-pressed.png | Bin 368 -> 0 bytes docs/html/_static/down.png | Bin 363 -> 0 bytes docs/html/_static/file.png | Bin 392 -> 0 bytes docs/html/_static/jquery.js | 2 - docs/html/_static/minus.png | Bin 199 -> 0 bytes docs/html/_static/plus.png | Bin 199 -> 0 bytes docs/html/_static/pygments.css | 62 - docs/html/_static/searchtools.js | 622 --------- docs/html/_static/sidebar.js | 159 --- docs/html/_static/stylesheet.css | 55 - docs/html/_static/underscore.js | 31 - docs/html/_static/up-pressed.png | Bin 372 -> 0 bytes docs/html/_static/up.png | Bin 363 -> 0 bytes docs/html/_static/websupport.js | 808 ----------- docs/html/genindex.html | 85 -- docs/html/index.html | 1546 --------------------- docs/html/objects.inv | 7 - docs/html/search.html | 108 -- docs/html/searchindex.js | 1 - docs/source/_static/conversejs_small.png | Bin 0 -> 574 bytes docs/source/_static/favicon.ico | Bin 0 -> 1150 bytes docs/source/_static/style.css | 3 + docs/source/_templates/layout.html | 208 +-- docs/source/conf.py | 81 +- docs/source/index.rst | 45 +- docs/source/theme/static/stylesheet.css_t | 55 - docs/source/theme/theme.conf | 4 - 42 files changed, 397 insertions(+), 6305 deletions(-) create mode 100644 bootstrap.py create mode 100644 buildout.cfg delete mode 100644 docs/doctrees/index.doctree delete mode 100644 docs/html/.buildinfo delete mode 100644 docs/html/_sources/index.txt delete mode 100644 docs/html/_static/ajax-loader.gif delete mode 100644 docs/html/_static/basic.css delete mode 100644 docs/html/_static/comment-bright.png delete mode 100644 docs/html/_static/comment-close.png delete mode 100644 docs/html/_static/comment.png delete mode 100644 docs/html/_static/default.css delete mode 100644 docs/html/_static/doctools.js delete mode 100644 docs/html/_static/down-pressed.png delete mode 100644 docs/html/_static/down.png delete mode 100644 docs/html/_static/file.png delete mode 100644 docs/html/_static/jquery.js delete mode 100644 docs/html/_static/minus.png delete mode 100644 docs/html/_static/plus.png delete mode 100644 docs/html/_static/pygments.css delete mode 100644 docs/html/_static/searchtools.js delete mode 100644 docs/html/_static/sidebar.js delete mode 100644 docs/html/_static/stylesheet.css delete mode 100644 docs/html/_static/underscore.js delete mode 100644 docs/html/_static/up-pressed.png delete mode 100644 docs/html/_static/up.png delete mode 100644 docs/html/_static/websupport.js delete mode 100644 docs/html/genindex.html delete mode 100644 docs/html/index.html delete mode 100644 docs/html/objects.inv delete mode 100644 docs/html/search.html delete mode 100644 docs/html/searchindex.js create mode 100644 docs/source/_static/conversejs_small.png create mode 100644 docs/source/_static/favicon.ico create mode 100644 docs/source/_static/style.css delete mode 100644 docs/source/theme/static/stylesheet.css_t delete mode 100644 docs/source/theme/theme.conf diff --git a/.gitignore b/.gitignore index 464ea67f3..22b4a86c9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,13 +8,27 @@ .svn/ .project .pydevproject + Backbone.Overview -node_modules -components -docs/doctrees/environment.pickle tags stamp-npm stamp-bower +# Sphinx +docs/html +docs/doctrees + +# Bower +components + +# Node.js +node_modules + +# Virtualenv/Buildout +lib +include +bin +develop-eggs + # OSX .DS_Store diff --git a/Makefile b/Makefile index df6777b85..ae5a01c29 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ BOWER ?= node_modules/.bin/bower BUILDDIR = ./docs PAPER = PHANTOMJS ?= node_modules/.bin/phantomjs -SPHINXBUILD = sphinx-build +SPHINXBUILD = ./bin/sphinx-build SPHINXOPTS = POTOJSON ?= node_modules/.bin/po2json diff --git a/bootstrap.py b/bootstrap.py new file mode 100644 index 000000000..5f2cb0835 --- /dev/null +++ b/bootstrap.py @@ -0,0 +1,260 @@ +############################################################################## +# +# Copyright (c) 2006 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""Bootstrap a buildout-based project + +Simply run this script in a directory containing a buildout.cfg. +The script accepts buildout command-line options, so you can +use the -c option to specify an alternate configuration file. +""" + +import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess +from optparse import OptionParser + +if sys.platform == 'win32': + def quote(c): + if ' ' in c: + return '"%s"' % c # work around spawn lamosity on windows + else: + return c +else: + quote = str + +# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. +stdout, stderr = subprocess.Popen( + [sys.executable, '-Sc', + 'try:\n' + ' import ConfigParser\n' + 'except ImportError:\n' + ' print 1\n' + 'else:\n' + ' print 0\n'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() +has_broken_dash_S = bool(int(stdout.strip())) + +# In order to be more robust in the face of system Pythons, we want to +# run without site-packages loaded. This is somewhat tricky, in +# particular because Python 2.6's distutils imports site, so starting +# with the -S flag is not sufficient. However, we'll start with that: +if not has_broken_dash_S and 'site' in sys.modules: + # We will restart with python -S. + args = sys.argv[:] + args[0:0] = [sys.executable, '-S'] + args = map(quote, args) + os.execv(sys.executable, args) +# Now we are running with -S. We'll get the clean sys.path, import site +# because distutils will do it later, and then reset the path and clean +# out any namespace packages from site-packages that might have been +# loaded by .pth files. +clean_path = sys.path[:] +import site +sys.path[:] = clean_path +for k, v in sys.modules.items(): + if k in ('setuptools', 'pkg_resources') or ( + hasattr(v, '__path__') and + len(v.__path__)==1 and + not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))): + # This is a namespace package. Remove it. + sys.modules.pop(k) + +is_jython = sys.platform.startswith('java') + +setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' +distribute_source = 'http://python-distribute.org/distribute_setup.py' + +# parsing arguments +def normalize_to_url(option, opt_str, value, parser): + if value: + if '://' not in value: # It doesn't smell like a URL. + value = 'file://%s' % ( + urllib.pathname2url( + os.path.abspath(os.path.expanduser(value))),) + if opt_str == '--download-base' and not value.endswith('/'): + # Download base needs a trailing slash to make the world happy. + value += '/' + else: + value = None + name = opt_str[2:].replace('-', '_') + setattr(parser.values, name, value) + +usage = '''\ +[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] + +Bootstraps a buildout-based project. + +Simply run this script in a directory containing a buildout.cfg, using the +Python that you want bin/buildout to use. + +Note that by using --setup-source and --download-base to point to +local resources, you can keep this script from going over the network. +''' + +parser = OptionParser(usage=usage) +parser.add_option("-v", "--version", dest="version", + help="use a specific zc.buildout version") +parser.add_option("-d", "--distribute", + action="store_true", dest="use_distribute", default=False, + help="Use Distribute rather than Setuptools.") +parser.add_option("--setup-source", action="callback", dest="setup_source", + callback=normalize_to_url, nargs=1, type="string", + help=("Specify a URL or file location for the setup file. " + "If you use Setuptools, this will default to " + + setuptools_source + "; if you use Distribute, this " + "will default to " + distribute_source +".")) +parser.add_option("--download-base", action="callback", dest="download_base", + callback=normalize_to_url, nargs=1, type="string", + help=("Specify a URL or directory for downloading " + "zc.buildout and either Setuptools or Distribute. " + "Defaults to PyPI.")) +parser.add_option("--eggs", + help=("Specify a directory for storing eggs. Defaults to " + "a temporary directory that is deleted when the " + "bootstrap script completes.")) +parser.add_option("-t", "--accept-buildout-test-releases", + dest='accept_buildout_test_releases', + action="store_true", default=False, + help=("Normally, if you do not specify a --version, the " + "bootstrap script and buildout gets the newest " + "*final* versions of zc.buildout and its recipes and " + "extensions for you. If you use this flag, " + "bootstrap and buildout will get the newest releases " + "even if they are alphas or betas.")) +parser.add_option("-c", None, action="store", dest="config_file", + help=("Specify the path to the buildout configuration " + "file to be used.")) + +options, args = parser.parse_args() + +# if -c was provided, we push it back into args for buildout's main function +if options.config_file is not None: + args += ['-c', options.config_file] + +if options.eggs: + eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) +else: + eggs_dir = tempfile.mkdtemp() + +if options.setup_source is None: + if options.use_distribute: + options.setup_source = distribute_source + else: + options.setup_source = setuptools_source + +if options.accept_buildout_test_releases: + args.append('buildout:accept-buildout-test-releases=true') +args.append('bootstrap') + +try: + import pkg_resources + import setuptools # A flag. Sometimes pkg_resources is installed alone. + if not hasattr(pkg_resources, '_distribute'): + raise ImportError +except ImportError: + ez_code = urllib2.urlopen( + options.setup_source).read().replace('\r\n', '\n') + ez = {} + exec ez_code in ez + setup_args = dict(to_dir=eggs_dir, download_delay=0) + if options.download_base: + setup_args['download_base'] = options.download_base + if options.use_distribute: + setup_args['no_fake'] = True + ez['use_setuptools'](**setup_args) + if 'pkg_resources' in sys.modules: + reload(sys.modules['pkg_resources']) + import pkg_resources + # This does not (always?) update the default working set. We will + # do it. + for path in sys.path: + if path not in pkg_resources.working_set.entries: + pkg_resources.working_set.add_entry(path) + +cmd = [quote(sys.executable), + '-c', + quote('from setuptools.command.easy_install import main; main()'), + '-mqNxd', + quote(eggs_dir)] + +if not has_broken_dash_S: + cmd.insert(1, '-S') + +find_links = options.download_base +if not find_links: + find_links = os.environ.get('bootstrap-testing-find-links') +if find_links: + cmd.extend(['-f', quote(find_links)]) + +if options.use_distribute: + setup_requirement = 'distribute' +else: + setup_requirement = 'setuptools' +ws = pkg_resources.working_set +setup_requirement_path = ws.find( + pkg_resources.Requirement.parse(setup_requirement)).location +env = dict( + os.environ, + PYTHONPATH=setup_requirement_path) + +requirement = 'zc.buildout' +version = options.version +if version is None and not options.accept_buildout_test_releases: + # Figure out the most recent final version of zc.buildout. + import setuptools.package_index + _final_parts = '*final-', '*final' + def _final_version(parsed_version): + for part in parsed_version: + if (part[:1] == '*') and (part not in _final_parts): + return False + return True + index = setuptools.package_index.PackageIndex( + search_path=[setup_requirement_path]) + if find_links: + index.add_find_links((find_links,)) + req = pkg_resources.Requirement.parse(requirement) + if index.obtain(req) is not None: + best = [] + bestv = None + for dist in index[req.project_name]: + distv = dist.parsed_version + if _final_version(distv): + if bestv is None or distv > bestv: + best = [dist] + bestv = distv + elif distv == bestv: + best.append(dist) + if best: + best.sort() + version = best[-1].version +if version: + requirement = '=='.join((requirement, version)) +cmd.append(requirement) + +if is_jython: + import subprocess + exitcode = subprocess.Popen(cmd, env=env).wait() +else: # Windows prefers this, apparently; otherwise we would prefer subprocess + exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) +if exitcode != 0: + sys.stdout.flush() + sys.stderr.flush() + print ("An error occurred when trying to install zc.buildout. " + "Look above this message for any errors that " + "were output by easy_install.") + sys.exit(exitcode) + +ws.add_entry(eggs_dir) +ws.require(requirement) +import zc.buildout.buildout +zc.buildout.buildout.main(args) +if not options.eggs: # clean up temporary egg directory + shutil.rmtree(eggs_dir) diff --git a/buildout.cfg b/buildout.cfg new file mode 100644 index 000000000..c4a512a47 --- /dev/null +++ b/buildout.cfg @@ -0,0 +1,22 @@ +[buildout] +parts = + sphinx + +versions = versions + +[sphinx] +recipe = zc.recipe.egg +eggs = + Sphinx + sphinx-bootstrap-theme + +[versions] +docutils = 0.12 +Jinja2 = 2.7.3 +MarkupSafe = 0.23 +Pygments = 2.0.1 +setuptools = 7.0 +six = 1.8.0 +Sphinx = 1.2.1 +z3c.recipe.egg = 2.0.1 +zc.buildout = 2.2.5 diff --git a/converse.js b/converse.js index 02b173942..0af01c0cd 100644 --- a/converse.js +++ b/converse.js @@ -232,7 +232,7 @@ bosh_service_url: undefined, // The BOSH connection manager URL. cache_otr_key: false, debug: false, - domain_placeholder: " e.g. conversejs.org", // Placeholder text to show in the domain input on the registration form + domain_placeholder: " e.g. conversejs.org", // Placeholder text shown in the domain input on the registration form default_box_height: 400, // The default height, in pixels, for the control box, chat boxes and chatrooms. expose_rid_and_sid: false, forward_messages: false, diff --git a/docs/doctrees/index.doctree b/docs/doctrees/index.doctree deleted file mode 100644 index ea64d1dd9459119848d210f64cef0040ca551519..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 306620 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 z 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

U=l7XStNUx*}hpBH{fW1kC$4>4&L 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 element of your website via the *script* and *link* -tags: - -:: - - - - -You need to initialize Converse.js with configuration settings according to -your requirements. - -Please refer to the `Configuration variables`_ section further below for info on -all the available configuration settings. - -To configure Converse.js, put the following inline Javascript code at the -bottom of your page (after the closing ** element). - -:: - - require(['converse'], function (converse) { - converse.initialize({ - auto_list_rooms: false, - auto_subscribe: false, - bosh_service_url: 'https://bind.conversejs.org', // Please use this connection manager only for testing purposes - hide_muc_server: false, - i18n: locales.en, // Refer to ./locale/locales.js to see which locales are supported - prebind: false, - show_controlbox_by_default: true, - roster_groups: true - }); - }); - -The `index.html `_ file inside the -Converse.js repository may serve as a nice usable example. - -These minified files provide the same demo-like functionality as is available -on the `conversejs.org `_ website. Useful for testing or demoing. - -You'll most likely want to implement some kind of single persistent session solution for -your website, where users authenticate once in your website and then stay -logged in to their XMPP session upon the next page reload. - -For more info on this, read: `Prebinding and Single Session Support`_. - -You might also want to have more fine-grained control of what gets included in -the minified Javascript file. Read `Configuration`_ and `Minification`_ for more info on how to do -that. - - -============ -Introduction -============ - -Even though you can connect to public XMPP servers on the `conversejs.org`_ -website, *Converse.js* is not really meant to be a "Software-as-a-service" (SaaS) -webchat. - -Instead, its goal is to provide the means for website owners to add a tightly -integrated instant messaging service to their own websites. - -As a website owner, you are expected to host *Converse.js* yourself, and to do some legwork to -properly configure and integrate it into your site. - -The benefit in doing this, is that your users have a much more streamlined and integrated -webchat experience and that you have control over the data. The latter being a -requirement for many sites dealing with sensitive information. - -You'll need to set up your own XMPP server and in order to have -`Session Support`_ (i.e. single-signon functionality whereby users are authenticated once and stay -logged in to XMPP upon page reload) you will likely also have to add some server-side -code. - -The `What you will need`_ section has more information on all these -requirements. - - -======== -Features -======== - -Off-the-record encryption -========================= - -Converse.js supports `Off-the-record (OTR) `_ -encrypted messaging. - -The OTR protocol not only **encrypts your messages**, it provides ways to -**verify the identity** of the person you are talking to, -**plausible deniability** and **perfect forward secrecy** by generating -new encryption keys for each conversation. - -In its current state, Javascript cryptography is fraught with dangers and -challenges that make it impossible to reach the same standard of security that -is available with native "desktop" software. - -This is due to its runtime malleability, the way it is "installed" (e.g. -served) and the browser's lack of cryptographic primitives needed to implement -secure crypto. - -For harsh but fairly valid criticism of Javascript cryptography, read: -`Javascript Cryptography Considered Harmful `_. - -To get an idea on how this applies to OTR support in Converse.js, please read -`my thoughts on it `_. - -For now, suffice to say that although its useful to have OTR support in -Converse.js in order to avoid most eavesdroppers, if you need serious -communications privacy, then you're much better off using native software. - -Sound Notifications -=================== - -From version 0.8.1 Converse.js can play a sound notification when you receive a -message. - -For more info, please see the `play_sounds`_ configuration setting. - -Multilingual Support -==================== - -Converse.js is translated into multiple languages. The default build, -``converse.min.js``, includes all languages. - -Languages increase the size of the Converse.js significantly. - -If you only need one, or a subset of the available languages, it's better to -make a custom build which includes only those languages that you need. - -Chat Rooms -========== - -Commands --------- - -Here are the different commands that may be used in a chat room: - -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| Event Type | When is it triggered? | Example (substitue $nickname with an actual user's nickname) | -+============+==============================================================================================+===============================================================+ -| **ban** | Ban a user from the chat room. They will not be able to join again. | /ban $nickname | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **clear** | Clear the messages shown in the chat room. | /clear | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **deop** | Make a moderator a normal participant. | /deop $nickname [$reason] | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **help** | Show the list of available commands. | /help | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **kick** | Kick a user out of a room. They will be able to join again. | /kick $nickname [$reason] | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **me** | Speak in the 3rd person. | /me $message | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **mute** | Remove a user's ability to post messages to the room. They will still be able to observe. | /mute $nickname [$reason] | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **nick** | Change your nickname. | /nick $nickname | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **op** | Make a normal participant a moderator. | /op $nickname [$reason] | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **topic** | Set the topic of the chat room. | /topic ${topic text} | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ -| **voice** | Allow a muted user to post messages to the room. | /voice $nickname [$reason] | -+------------+----------------------------------------------------------------------------------------------+---------------------------------------------------------------+ - - -================== -What you will need -================== - -An XMPP server -============== - -*Converse.js* implements `XMPP`_ as its messaging protocol, and therefore needs -to connect to an XMPP/Jabber server (Jabber is really just a synonym for XMPP). - -You can connect to public XMPP servers like ``jabber.org`` but if you want to -have `Session Support`_ you'll have to set up your own XMPP server. - -You can find a list of public XMPP servers/providers on `xmpp.net`_ and a list of -servers that you can set up yourself on `xmpp.org`_. - - -A BOSH Connection Manager -========================= - -Your website and *Converse.js* use `HTTP`_ as protocol to communicate with -the webserver. HTTP connections are stateless and usually shortlived. - -`XMPP`_ on the other hand, is the protocol that enables instant messaging, and -its connections are stateful and usually longer. - -To enable a web application like *Converse.js* to communicate with an XMPP -server, we need a proxy in the middle that can act as a bridge between the two -protocols. - -The `index.html `_ file inside the - -This is the job of a connection manager. A connection manager can be either a -standalone application or part of an XMPP server. Popular XMPP servers such as -`ejabberd `_, `prosody `_ and -`openfire `_ all include their own connection managers -(but you usually have to enable them in the configuration). - -Standalone connection managers also exist, see for example `Punjab `_. - -The demo on the `Converse.js homepage`_ uses a connection manager located at https://bind.conversejs.org. -This connection manager is available for testing purposes only, please don't use it in production. - -Overcoming cross-domain request restrictions --------------------------------------------- - -Lets say your domain is *example.org*, but the domain of your connection -manager is *example.com*. - -HTTP requests are made by *Converse.js* to the connection manager via XmlHttpRequests (XHR). -Until recently, it was not possible to make such requests to a different domain -than the one currently being served (to prevent XSS attacks). - -Luckily there is now a standard called `CORS`_ (Cross-origin resource sharing), which enables exactly that. -Modern browsers support CORS, but there are problems with Internet Explorer < -10. - -IE 8 and 9 partially support CORS via a proprietary implementation called -XDomainRequest. There is a `Strophe.js plugin`_ which you can use to enable -support for XDomainRequest when it is present. - -In IE < 8, there is no support for CORS. - -Instead of using CORS, you can add a reverse proxy in -Apache/Nginx which serves the connection manager under the same domain as your -website. This will remove the need for any cross-domain XHR support. - -For example: -~~~~~~~~~~~~ - -Assuming your site is accessible on port ``80`` for the domain ``mysite.com`` -and your connection manager manager is running at ``someothersite.com/http-bind``. - -The *bosh_service_url* value you want to give Converse.js to overcome -the cross-domain restriction is ``mysite.com/http-bind`` and not -``someothersite.com/http-bind``. - -Your ``nginx`` or ``apache`` configuration will look as follows: - -Nginx -~~~~~ -:: - - http { - server { - listen 80 - server_name mysite.com; - location ~ ^/http-bind/ { - proxy_pass http://someothersite.com; - } - } - } - -Apache -~~~~~~ -:: - - - ServerName mysite.com - RewriteEngine On - RewriteRule ^/http-bind(.*) http://someothersite.com/http-bind$1 [P,L] - - - -Server-side authentication -========================== - -.. _`Session Support`: - -Prebinding and Single Session Support -------------------------------------- - -It's possible to enable single-site login, whereby users already -authenticated in your website will also automatically be logged in on the chat server, - -This session should also persist across page loads. In other words, we don't -want the user to have to give their chat credentials every time they reload the -page. - -To do this you will require a `BOSH server `_ -for converse.js to connect to (see the `bosh_service_url`_ under `Configuration variables`_) -as well as a BOSH client on your own server (written for example in Python, Ruby or PHP) that will -do the pre-authentication before the web page loads. - -.. note:: - A BOSH server acts as a bridge between HTTP, the protocol of the web, and - XMPP, the instant messaging protocol. - Converse.js can only communicate via HTTP, but we need to communicate with - an XMPP server in order to chat. So the BOSH server acts as a middle man, - translating our HTTP requests into XMPP stanzas and vice versa. - -Jack Moffitt has a great `blogpost`_ about this and even provides an `example Django application`_ to demonstrate it. - -When you authenticate to the XMPP server on your backend application (for -example via a BOSH client in Django), you'll receive two tokens, RID (request ID) and SID (session ID). - -The **Session ID (SID)** is a unique identifier for the current *session*. This -number stays constant for the entire session. - -The **Request ID (RID)** is a unique identifier for the current *request* (i.e. -page load). Each page load is a new request which requires a new unique RID. -The best way to achieve this is to simply increment the RID with each page -load. - -When you initialize converse.js in your browser, you need to pass it these two -tokens. Converse.js will then use them to attach to the session you just -created. - -You can embed the RID and SID tokens in your HTML markup or you can do an -XMLHttpRequest call to your server and ask it to return them for you. - -Below is one example of how this could work. An Ajax call is made to the -relative URL **/prebind** and it expects to receive JSON data back. - -:: - - $.getJSON('/prebind', function (data) { - converse.initialize({ - prebind: true, - bosh_service_url: data.bosh_service_url, - jid: data.jid, - sid: data.sid, - rid: data.rid - }); - ); - -**Here's what's happening:** - -The JSON data returned from the Ajax call to example.com/prebind contains the user's JID (jabber ID), RID, SID and the URL to the -BOSH server (also called a *connection manager*). - -These values are then passed to converse.js's ``initialize`` method. - -.. note:: - If you want to enable single session support, you need to set **prebind: true** - when calling **converse.initialize** (see ./index.html). - Additionally you need to pass in valid **jid**, **sid**, **rid** and - **bosh_service_url** values. - - -Example code for server-side prebinding ---------------------------------------- - -* PHP: - See `xmpp-prebind-php `_ by - Michael Weibel and the folks from Candy chat. - -* Python: - See this `example Django application`_ by Jack Moffitt. - - -=========== -Development -=========== - -If you want to work with the non-minified Javascript and CSS files you'll soon -notice that there are references to a missing *components* folder. Please -follow the instructions below to create this folder and fetch Converse's -3rd-party dependencies. - -.. note:: - Users have reported that converse.js cannot be built on Windows. Patches to - fix this are welcome. - - -Install the development and front-end dependencies -================================================== - -We use development tools (`Grunt `_ and `Bower `_) -which depend on Node.js and npm (the Node package manager). - -If you don't have Node.js installed, you can download and install the latest -version `here `_. - -Also make sure you have ``git`` installed. `Details `_. - -Once you have *Node.js* and *git* installed, run the following command inside the Converse.js -directory: - -:: - - make dev - -Or alternatively, if you don't have GNU Make: - -:: - - npm install - bower update - -This will first install the Node.js development tools (like Grunt and Bower) -and then use Bower to install all of Converse.js's front-end dependencies. - -The front-end dependencies are those javascript files on which -Converse.js directly depends and which will be loaded in the browser. - -If you are curious to know what the different dependencies are: - -* Development dependencies: - Take a look at whats under the *devDependencies* key in - `package.json `_. - -* Front-end dependencies: - See *dependencies* in - `bower.json `_. - -.. note:: - After running ```make dev```, you should now have a new directory *components*, - which contains all the front-end dependencies of Converse.js. - If this directory does NOT exist, something must have gone wrong. - Double-check the output of ```make dev``` to see if there are any errors - listed. For support, you can write to the mailing list: conversejs@librelist.com - - -With AMD and require.js (recommended) -===================================== - -Converse.js uses `require.js `_ to asynchronously load dependencies. - -If you want to develop or customize converse.js, you'll want to load the -non-minified javascript files. - -Add the following two lines to the ** section of your webpage: - -:: - - - - -require.js will then let the main.js file be parsed (because of the *data-main* -attribute on the *script* tag), which will in turn cause converse.js to be -parsed. - -Without AMD and require.js -========================== - -Converse.js can also be used without require.js. If you for some reason prefer -to use it this way, please refer to -`non_amd.html `_ -for an example of how and in what order all the Javascript files that converse.js -depends on need to be loaded. - - -Before submitting a pull request -================================ - -Add tests for your bugfix or feature ------------------------------------- - -Add a test for any bug fixed or feature added. We use Jasmine -for testing. - -Take a look at ``tests.html`` and ``spec/MainSpec.js`` to see how -the tests are implemented. - -If you are unsure how to write tests, please -`contact me `_ and I'll be happy to help. - -Check that the tests pass -------------------------- - -Check that the Jasmine tests complete sucessfully. Open -`tests.html `_ -in your browser, and the tests will run automatically. - -On the command line you can run: - -:: - - grunt test - -Check your code for errors or bad habits by running JSHint ----------------------------------------------------------- - -`JSHint `_ will do a static analysis of your code and hightlight potential errors -and/or bad habits. - -:: - - grunt jshint - - -You can run both the tests and jshint in one go by calling: - -:: - - grunt check - - -Developer API -============= - -.. note:: The API documented here is available in Converse.js 0.8.4 and higher. - Earlier versions of Converse.js might have different API methods or none at all. - -In the Converse.js API, you traverse towards a logical grouping, from -which you can then call certain standardised accessors and mutators, like:: - - .get - .set - .add - .all - .remove - -This is done to increase readability and to allow intuitive method chaining. - -For example, to get a contact, you would do the following:: - - converse.contacts.get('jid@example.com'); - -To get multiple contacts, just pass in an array of jids:: - - converse.contacts.get(['jid1@example.com', 'jid2@example.com']); - - -**Here follows now a breakdown of all API groupings and methods**: - - -initialize ----------- - -.. note:: This method is the one exception of a method which is not logically grouped - as explained above. - -Initializes converse.js. This method must always be called when using -converse.js. - -The `initialize` method takes a map (also called a hash or dictionary) of -`configuration variables`_. - -Example:: - - converse.initialize({ - allow_otr: true, - auto_list_rooms: false, - auto_subscribe: false, - bosh_service_url: 'https://bind.example.com', - hide_muc_server: false, - i18n: locales['en'], - keepalive: true, - play_sounds: true, - prebind: false, - show_controlbox_by_default: true, - debug: false, - roster_groups: true - }); - - -"contacts" grouping -------------------- - -get -~~~ - -Returns a map of attributes for a given buddy (i.e. roster contact), specified -by JID (Jabber ID). - -Example:: - - converse.contacts.get('buddy@example.com') - -The map of attributes: - -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| Attribute | | -+================+======================================================================================================================================+ -| ask | If ask === 'subscribe', then we have asked this person to be our chat buddy. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| fullname | The person's full name. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| jid | The person's Jabber/XMPP username. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| requesting | If true, then this person is asking to be our chat buddy. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| subscription | The subscription state between the current user and this chat buddy. Can be `none`, `to`, `from` or `both`. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| id | A unique id, same as the jid. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| chat_status | The person's chat status. Can be `online`, `offline`, `busy`, `xa` (extended away) or `away`. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| user_id | The user id part of the JID (the part before the `@`). | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| resources | The known resources for this chat buddy. Each resource denotes a separate and connected chat client. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| groups | The roster groups in which this chat buddy was placed. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| status | Their human readable custom status message. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| image_type | The image's file type. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| image | The Base64 encoded image data. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| url | The buddy's website URL, as specified in their VCard data. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ -| vcard_updated | When last the buddy's VCard was updated. | -+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ - -"chats" grouping ----------------- - -get -~~~ - -Returns an object/map representing a chat box (without opening or affecting that chat box). - -Example:: - - converse.chats.get('buddy@example.com') - -*The returned chat box contains the following methods:* - -+-------------+------------------------------------------+ -| Method | Description | -+=============+==========================================+ -| endOTR | End an OTR (Off-the-record) session. | -+-------------+------------------------------------------+ -| get | Get an attribute (i.e. accessor). | -+-------------+------------------------------------------+ -| initiateOTR | Start an OTR (off-the-record) session. | -+-------------+------------------------------------------+ -| maximize | Minimize the chat box. | -+-------------+------------------------------------------+ -| minimize | Maximize the chat box. | -+-------------+------------------------------------------+ -| set | Set an attribute (i.e. mutator). | -+-------------+------------------------------------------+ - -*The get and set methods can be used to retrieve and change the following attributes:* - -+-------------+-----------------------------------------------------+ -| Attribute | Description | -+=============+=====================================================+ -| height | The height of the chat box. | -+-------------+-----------------------------------------------------+ -| url | The URL of the chat box heading. | -+-------------+-----------------------------------------------------+ - -"tokens" grouping ------------------ - -get -~~~ - -Returns a token, either the RID or SID token depending on what's asked for. - -Example:: - - converse.tokens.get('rid') - -"listen" grouping ------------------ - -Converse.js emits events to which you can subscribe from your own Javascript. - -Concerning events, the following methods are available under the "listen" -grouping: - -* **on(eventName, callback)**: - - Calling the ``on`` method allows you to subscribe to an event. - Every time the event fires, the callback method specified by ``callback`` will be - called. - - Parameters: - - * ``eventName`` is the event name as a string. - * ``callback`` is the callback method to be called when the event is emitted. - - For example:: - - converse.listen.on('message', function (messageXML) { ... }); - -* **once(eventName, callback)**: - - Calling the ``once`` method allows you to listen to an event - exactly once. - - Parameters: - - * ``eventName`` is the event name as a string. - * ``callback`` is the callback method to be called when the event is emitted. - - For example:: - - converse.listen.once('message', function (messageXML) { ... }); - -* **not(eventName, callback)** - - To stop listening to an event, you can use the ``not`` method. - - Parameters: - - * ``eventName`` is the event name as a string. - * ``callback`` refers to the function that is to be no longer executed. - - For example:: - - converse.listen.not('message', function (messageXML) { ... }); - -Events -====== - -.. note:: see also the `"listen" grouping`_ API section above. - -Event Types ------------ - -Here are the different events that are emitted: - -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| Event Type | When is it triggered? | Example | -+================================+===================================================================================================+=========================================================================================+ -| **initialized** | Once converse.js has been initialized. | ``converse.on('initialized', function () { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **ready** | After connection has been established and converse.js has got all its ducks in a row. | ``converse.on('ready', function () { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **reconnect** | After the connection has dropped. Converse.js will attempt to reconnect when not in prebind mode. | ``converse.on('reconnect', function () { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **message** | When a message is received. | ``converse.on('message', function (messageXML) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **messageSend** | When a message will be sent out. | ``converse.on('messageSend', function (messageText) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **noResumeableSession** | When keepalive=true but there aren't any stored prebind tokens. | ``converse.on('noResumeableSession', function () { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **roster** | When the roster is updated. | ``converse.on('roster', function (items) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **callButtonClicked** | When a call button (i.e. with class .toggle-call) on a chat box has been clicked. | ``converse.on('callButtonClicked', function (connection, model) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **chatBoxOpened** | When a chat box has been opened. | ``converse.on('chatBoxOpened', function (chatbox) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **chatRoomOpened** | When a chat room has been opened. | ``converse.on('chatRoomOpened', function (chatbox) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **chatBoxClosed** | When a chat box has been closed. | ``converse.on('chatBoxClosed', function (chatbox) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **chatBoxFocused** | When the focus has been moved to a chat box. | ``converse.on('chatBoxFocused', function (chatbox) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **chatBoxToggled** | When a chat box has been minimized or maximized. | ``converse.on('chatBoxToggled', function (chatbox) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **roomInviteSent** | After the user has sent out a direct invitation, to a roster contact, asking them to join a room. | ``converse.on('roomInvite', function (roomview, invitee_jid, reason) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **roomInviteReceived** | After the user has sent out a direct invitation, to a roster contact, asking them to join a room. | ``converse.on('roomInvite', function (roomview, invitee_jid, reason) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **statusChanged** | When own chat status has changed. | ``converse.on('statusChanged', function (status) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **statusMessageChanged** | When own custom status message has changed. | ``converse.on('statusMessageChanged', function (message) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **buddyStatusChanged** | When a chat buddy's chat status has changed. | ``converse.on('buddyStatusChanged', function (buddy, status) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **buddyStatusMessageChanged** | When a chat buddy's custom status message has changed. | ``converse.on('buddyStatusMessageChanged', function (buddy, messageText) { ... });`` | -+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ - - -Minification -============ - -Minifying Javascript and CSS ----------------------------- - -Please make sure to read the section `Development`_ and that you have installed -all development dependencies (long story short, you can run ``npm install`` -and then ``grunt fetch``). - -We use `require.js`_ to keep track of *Converse.js* and its dependencies and to -to bundle them together in a single minified file fit for deployment to a -production site. - -To minify the Javascript and CSS, run the following command: - -:: - - grunt minify - -Javascript will be bundled and minified with `require.js`_'s optimization tool, -using `almond `_. - -You can `read more about require.js's optimizer here`_. - -CSS is minified via `cssmin `_. - -Translations -============ - -.. note:: - Translations take up a lot of space and will bloat your minified file. - At the time of writing, all the translations add about 50KB of extra data to - the minified javascript file. Therefore, make sure to only - include those languages that you intend to support and remove from - ./locale/locales.js those which you don't need. Remember to rebuild the - minified file afterwards. - -The gettext POT file located in ./locale/converse.pot is the template -containing all translations and from which for each language an individual PO -file is generated. - -The POT file contains all translateable strings extracted from converse.js. - -To make a user facing string translateable, wrap it in the double underscore helper -function like so: - -:: - - __('This string will be translated at runtime'); - -After adding the string, you'll need to regenerate the POT file, like so: - -:: - - make pot - -To create a new PO file for a language in which converse.js is not yet -translated into, do the following - -.. note:: In this example we use Polish (pl), you need to substitute 'pl' to your own language's code. - -:: - - mkdir -p ./locale/pl/LC_MESSAGES - msginit -i ./locale/converse.pot -o ./locale/pl/LC_MESSAGES/converse.po -l pl - -You can then create or update the PO file for a specific language by doing the following: - -.. note:: In this example we use German (de), you need to substitute 'de' to your own language's code. - -:: - - msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U - -To do this for ALL languages, run: - -:: - - make po - -The resulting PO file is then what gets translated. - -If you've created a new PO file, please make sure to add the following -attributes at the top of the file (under *Content-Transfer-Encoding*). They are -required as configuration settings for Jed, the Javascript translations library -that we're using. - -:: - - "domain: converse\n" - "lang: de\n" - "plural_forms: nplurals=2; plural=(n != 1);\n" - - -Unfortunately `Jed `_ cannot use the PO files directly. We have to generate from it -a file in JSON format and then put that in a .js file for the specific -language. - -To generate JSON from a PO file, you'll need po2json for node.js. Run the -following command to install it (npm being the node.js package manager): - -:: - - npm install po2json - -You can then convert the translations into JSON format: - -:: - - po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json - -Now from converse.json paste the data as a value for the "locale_data" key in the -object in the language's .js file. - -So, if you are for example translating into German (language code 'de'), you'll -create or update the file ./locale/LC_MESSAGES/de.js with the following code: - -:: - - (function (root, factory) { - define("de", ['jed'], function () { - return factory(new Jed({ - "domain": "converse", - "locale_data": { - // Paste the JSON data from converse.json here - } - }) - } - }(this, function (i18n) { - return i18n; - })); - -making sure to also paste the JSON data as value to the "locale_data" key. - -.. note:: - If you are adding translations for a new language that is not already supported, - you'll have to add the language path in main.js and make one more edit in ./locale/locales.js - to make sure the language is loaded by require.js. - -Congratulations, you've now succesfully added your translations. Sorry for all -those hoops you had to jump through. - - - -=============== -Troubleshooting -=============== - -Conflicts with other Javascript libraries -========================================= - -Problem: ---------- - -You are using other Javascript libraries (like JQuery plugins), and -get errors like these in your browser console:: - - Uncaught TypeError: Object [object Object] has no method 'xxx' from example.js - -Solution: ---------- - -First, find out which object is referred to by ``Object [object Object]``. - -It will probably be the jQuery object ``$`` or perhaps the underscore.js object ``_``. - -For the purpose of demonstration, I'm going to assume its ``$``, but the same -rules apply if its something else. - -The bundled and minified default build of converse.js, ``converse.min.js`` -includes within it all of converse.js's dependencies, which include for example *jQuery*. - -If you are having conflicts where attributes or methods aren't available -on the jQuery object, you are probably loading ``converse.min.js`` (which -includes jQuery) as well as your own jQuery version separately. - -What then happens is that there are two ``$`` objects (one from -converse.js and one from the jQuery version you included manually) -and only one of them has been extended to have the methods or attributes you require. - -Which jQuery object you get depends on the order in which you load the libraries. - -There are multiple ways to solve this issue. - -Firstly, make sure whether you really need to include a separate version of -jQuery. Chances are that you don't. If you can remove the separate -version, your problem should be solved, as long as your libraries are loaded in -the right order. - -Either case, whether you need to keep two versions or not, the solution depends -on whether you'll use require.js to manage your libraries or whether you'll -load them manually. - -With require.js -~~~~~~~~~~~~~~~ - -Instead of using ``converse.min.js``, manage all the libraries in your project -(i.e. converse.js and its dependencies plus all other libraries you use) as one -require.js project, making sure everything is loaded in the correct order. - -Then, before deployment, you make your own custom minified build that bundles everything -you need. - -With - - - - - - -

-
-

Converse.js

-

Documentation

-
-
- - -
- -
- -
-
-
- - -

Index

- -
- -
- - -
-
-
-
- -
- -
- - - \ No newline at end of file diff --git a/docs/html/index.html b/docs/html/index.html deleted file mode 100644 index 0836815da..000000000 --- a/docs/html/index.html +++ /dev/null @@ -1,1546 +0,0 @@ - - - - - - - - Quickstart (to get a demo up and running) — Converse.js 0.8.3 documentation - - - - - - - - - - - -
-
-

Converse.js

-

Documentation

-
-
- - -
- -
- -
-
-
- -
-
    -
-
-
-

Table of Contents

- -
-
-

Quickstart (to get a demo up and running)

-

When you download a specific release of Converse.js there will be two minified files inside the zip file.

-
    -
  • builds/converse.min.js
  • -
  • css/converse.min.css
  • -
-

You can include these two files inside the <head> element of your website via the script and link -tags:

-
<link rel="stylesheet" type="text/css" media="screen" href="css/converse.min.css">
-<script src="builds/converse.min.js"></script>
-
-
-

You need to initialize Converse.js with configuration settings according to -your requirements.

-

Please refer to the Configuration variables section further below for info on -all the available configuration settings.

-

To configure Converse.js, put the following inline Javascript code at the -bottom of your page (after the closing </body> element).

-
require(['converse'], function (converse) {
-    converse.initialize({
-        auto_list_rooms: false,
-        auto_subscribe: false,
-        bosh_service_url: 'https://bind.conversejs.org', // Please use this connection manager only for testing purposes
-        hide_muc_server: false,
-        i18n: locales.en, // Refer to ./locale/locales.js to see which locales are supported
-        prebind: false,
-        show_controlbox_by_default: true,
-        roster_groups: true
-    });
-});
-
-
-

The index.html file inside the -Converse.js repository may serve as a nice usable example.

-

These minified files provide the same demo-like functionality as is available -on the conversejs.org website. Useful for testing or demoing.

-

You’ll most likely want to implement some kind of single persistent session solution for -your website, where users authenticate once in your website and then stay -logged in to their XMPP session upon the next page reload.

-

For more info on this, read: Prebinding and Single Session Support.

-

You might also want to have more fine-grained control of what gets included in -the minified Javascript file. Read Configuration and Minification for more info on how to do -that.

-
-
-

Introduction

-

Even though you can connect to public XMPP servers on the conversejs.org -website, Converse.js is not really meant to be a “Software-as-a-service” (SaaS) -webchat.

-

Instead, its goal is to provide the means for website owners to add a tightly -integrated instant messaging service to their own websites.

-

As a website owner, you are expected to host Converse.js yourself, and to do some legwork to -properly configure and integrate it into your site.

-

The benefit in doing this, is that your users have a much more streamlined and integrated -webchat experience and that you have control over the data. The latter being a -requirement for many sites dealing with sensitive information.

-

You’ll need to set up your own XMPP server and in order to have -Session Support (i.e. single-signon functionality whereby users are authenticated once and stay -logged in to XMPP upon page reload) you will likely also have to add some server-side -code.

-

The What you will need section has more information on all these -requirements.

-
-
-

Features

-
-

Off-the-record encryption

-

Converse.js supports Off-the-record (OTR) -encrypted messaging.

-

The OTR protocol not only encrypts your messages, it provides ways to -verify the identity of the person you are talking to, -plausible deniability and perfect forward secrecy by generating -new encryption keys for each conversation.

-

In its current state, Javascript cryptography is fraught with dangers and -challenges that make it impossible to reach the same standard of security that -is available with native “desktop” software.

-

This is due to its runtime malleability, the way it is “installed” (e.g. -served) and the browser’s lack of cryptographic primitives needed to implement -secure crypto.

-

For harsh but fairly valid criticism of Javascript cryptography, read: -Javascript Cryptography Considered Harmful.

-

To get an idea on how this applies to OTR support in Converse.js, please read -my thoughts on it.

-

For now, suffice to say that although its useful to have OTR support in -Converse.js in order to avoid most eavesdroppers, if you need serious -communications privacy, then you’re much better off using native software.

-
-
-

Sound Notifications

-

From version 0.8.1 Converse.js can play a sound notification when you receive a -message.

-

For more info, please see the play_sounds configuration setting.

-
-
-

Multilingual Support

-

Converse.js is translated into multiple languages. The default build, -converse.min.js, includes all languages.

-

Languages increase the size of the Converse.js significantly.

-

If you only need one, or a subset of the available languages, it’s better to -make a custom build which includes only those languages that you need.

-
-
-

Chat Rooms

-
-

Commands

-

Here are the different commands that may be used in a chat room:

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event TypeWhen is it triggered?Example (substitue $nickname with an actual user’s nickname)
banBan a user from the chat room. They will not be able to join again./ban $nickname
clearClear the messages shown in the chat room./clear
deopMake a moderator a normal participant./deop $nickname [$reason]
helpShow the list of available commands./help
kickKick a user out of a room. They will be able to join again./kick $nickname [$reason]
meSpeak in the 3rd person./me $message
muteRemove a user’s ability to post messages to the room. They will still be able to observe./mute $nickname [$reason]
nickChange your nickname./nick $nickname
opMake a normal participant a moderator./op $nickname [$reason]
topicSet the topic of the chat room./topic ${topic text}
voiceAllow a muted user to post messages to the room./voice $nickname [$reason]
-
-
-
-
-

What you will need

-
-

An XMPP server

-

Converse.js implements XMPP as its messaging protocol, and therefore needs -to connect to an XMPP/Jabber server (Jabber is really just a synonym for XMPP).

-

You can connect to public XMPP servers like jabber.org but if you want to -have Session Support you’ll have to set up your own XMPP server.

-

You can find a list of public XMPP servers/providers on xmpp.net and a list of -servers that you can set up yourself on xmpp.org.

-
-
-

A BOSH Connection Manager

-

Your website and Converse.js use HTTP as protocol to communicate with -the webserver. HTTP connections are stateless and usually shortlived.

-

XMPP on the other hand, is the protocol that enables instant messaging, and -its connections are stateful and usually longer.

-

To enable a web application like Converse.js to communicate with an XMPP -server, we need a proxy in the middle that can act as a bridge between the two -protocols.

-

The index.html file inside the

-

This is the job of a connection manager. A connection manager can be either a -standalone application or part of an XMPP server. Popular XMPP servers such as -ejabberd, prosody and -openfire all include their own connection managers -(but you usually have to enable them in the configuration).

-

Standalone connection managers also exist, see for example Punjab.

-

The demo on the Converse.js homepage uses a connection manager located at https://bind.conversejs.org. -This connection manager is available for testing purposes only, please don’t use it in production.

-
-

Overcoming cross-domain request restrictions

-

Lets say your domain is example.org, but the domain of your connection -manager is example.com.

-

HTTP requests are made by Converse.js to the connection manager via XmlHttpRequests (XHR). -Until recently, it was not possible to make such requests to a different domain -than the one currently being served (to prevent XSS attacks).

-

Luckily there is now a standard called CORS (Cross-origin resource sharing), which enables exactly that. -Modern browsers support CORS, but there are problems with Internet Explorer < -10.

-

IE 8 and 9 partially support CORS via a proprietary implementation called -XDomainRequest. There is a Strophe.js plugin which you can use to enable -support for XDomainRequest when it is present.

-

In IE < 8, there is no support for CORS.

-

Instead of using CORS, you can add a reverse proxy in -Apache/Nginx which serves the connection manager under the same domain as your -website. This will remove the need for any cross-domain XHR support.

-
-

For example:

-

Assuming your site is accessible on port 80 for the domain mysite.com -and your connection manager manager is running at someothersite.com/http-bind.

-

The bosh_service_url value you want to give Converse.js to overcome -the cross-domain restriction is mysite.com/http-bind and not -someothersite.com/http-bind.

-

Your nginx or apache configuration will look as follows:

-
-
-

Nginx

-
http {
-    server {
-        listen       80
-        server_name  mysite.com;
-        location ~ ^/http-bind/ {
-            proxy_pass http://someothersite.com;
-        }
-    }
-}
-
-
-
-
-

Apache

-
<VirtualHost *:80>
-    ServerName mysite.com
-    RewriteEngine On
-    RewriteRule ^/http-bind(.*) http://someothersite.com/http-bind$1 [P,L]
-</VirtualHost>
-
-
-
-
-
-
-

Server-side authentication

-
-

Prebinding and Single Session Support

-

It’s possible to enable single-site login, whereby users already -authenticated in your website will also automatically be logged in on the chat server,

-

This session should also persist across page loads. In other words, we don’t -want the user to have to give their chat credentials every time they reload the -page.

-

To do this you will require a BOSH server -for converse.js to connect to (see the bosh_service_url under Configuration variables) -as well as a BOSH client on your own server (written for example in Python, Ruby or PHP) that will -do the pre-authentication before the web page loads.

-
-

Note

-

A BOSH server acts as a bridge between HTTP, the protocol of the web, and -XMPP, the instant messaging protocol. -Converse.js can only communicate via HTTP, but we need to communicate with -an XMPP server in order to chat. So the BOSH server acts as a middle man, -translating our HTTP requests into XMPP stanzas and vice versa.

-
-

Jack Moffitt has a great blogpost about this and even provides an example Django application to demonstrate it.

-

When you authenticate to the XMPP server on your backend application (for -example via a BOSH client in Django), you’ll receive two tokens, RID (request ID) and SID (session ID).

-

The Session ID (SID) is a unique identifier for the current session. This -number stays constant for the entire session.

-

The Request ID (RID) is a unique identifier for the current request (i.e. -page load). Each page load is a new request which requires a new unique RID. -The best way to achieve this is to simply increment the RID with each page -load.

-

When you initialize converse.js in your browser, you need to pass it these two -tokens. Converse.js will then use them to attach to the session you just -created.

-

You can embed the RID and SID tokens in your HTML markup or you can do an -XMLHttpRequest call to your server and ask it to return them for you.

-

Below is one example of how this could work. An Ajax call is made to the -relative URL /prebind and it expects to receive JSON data back.

-
$.getJSON('/prebind', function (data) {
-    converse.initialize({
-        prebind: true,
-        bosh_service_url: data.bosh_service_url,
-        jid: data.jid,
-        sid: data.sid,
-        rid: data.rid
-    });
-);
-
-
-

Here’s what’s happening:

-

The JSON data returned from the Ajax call to example.com/prebind contains the user’s JID (jabber ID), RID, SID and the URL to the -BOSH server (also called a connection manager).

-

These values are then passed to converse.js’s initialize method.

-
-

Note

-

If you want to enable single session support, you need to set prebind: true -when calling converse.initialize (see ./index.html). -Additionally you need to pass in valid jid, sid, rid and -bosh_service_url values.

-
-
-
-

Example code for server-side prebinding

- -
-
-
-
-

Development

-

If you want to work with the non-minified Javascript and CSS files you’ll soon -notice that there are references to a missing components folder. Please -follow the instructions below to create this folder and fetch Converse’s -3rd-party dependencies.

-
-

Note

-

Users have reported that converse.js cannot be built on Windows. Patches to -fix this are welcome.

-
-
-

Install the development and front-end dependencies

-

We use development tools (Grunt and Bower) -which depend on Node.js and npm (the Node package manager).

-

If you don’t have Node.js installed, you can download and install the latest -version here.

-

Also make sure you have git installed. Details.

-

Once you have Node.js and git installed, run the following command inside the Converse.js -directory:

-
make dev
-
-
-

Or alternatively, if you don’t have GNU Make:

-
npm install
-bower update
-
-
-

This will first install the Node.js development tools (like Grunt and Bower) -and then use Bower to install all of Converse.js’s front-end dependencies.

-

The front-end dependencies are those javascript files on which -Converse.js directly depends and which will be loaded in the browser.

-

If you are curious to know what the different dependencies are:

-
    -
  • -
    Development dependencies:
    -

    Take a look at whats under the devDependencies key in -package.json.

    -
    -
    -
  • -
  • -
    Front-end dependencies:
    -

    See dependencies in -bower.json.

    -
    -
    -
  • -
-
-

Note

-

After running `make dev`, you should now have a new directory components, -which contains all the front-end dependencies of Converse.js. -If this directory does NOT exist, something must have gone wrong. -Double-check the output of `make dev` to see if there are any errors -listed. For support, you can write to the mailing list: conversejs@librelist.com

-
-
- -
-

Without AMD and require.js

-

Converse.js can also be used without require.js. If you for some reason prefer -to use it this way, please refer to -non_amd.html -for an example of how and in what order all the Javascript files that converse.js -depends on need to be loaded.

-
-
-

Before submitting a pull request

-
-

Add tests for your bugfix or feature

-

Add a test for any bug fixed or feature added. We use Jasmine -for testing.

-

Take a look at tests.html and spec/MainSpec.js to see how -the tests are implemented.

-

If you are unsure how to write tests, please -contact me and I’ll be happy to help.

-
-
-

Check that the tests pass

-

Check that the Jasmine tests complete sucessfully. Open -tests.html -in your browser, and the tests will run automatically.

-

On the command line you can run:

-
grunt test
-
-
-
-
-

Check your code for errors or bad habits by running JSHint

-

JSHint will do a static analysis of your code and hightlight potential errors -and/or bad habits.

-
grunt jshint
-
-
-

You can run both the tests and jshint in one go by calling:

-
grunt check
-
-
-
-
-
-

Developer API

-
-

Note

-

The API documented here is available in Converse.js 0.8.4 and higher. -Earlier versions of Converse.js might have different API methods or none at all.

-
-

In the Converse.js API, you traverse towards a logical grouping, from -which you can then call certain standardised accessors and mutators, like:

-
.get
-.set
-.add
-.all
-.remove
-
-
-

This is done to increase readability and to allow intuitive method chaining.

-

For example, to get a contact, you would do the following:

-
converse.contacts.get('jid@example.com');
-
-
-

To get multiple contacts, just pass in an array of jids:

-
converse.contacts.get(['jid1@example.com', 'jid2@example.com']);
-
-
-

Here follows now a breakdown of all API groupings and methods:

-
-

initialize

-
-

Note

-

This method is the one exception of a method which is not logically grouped -as explained above.

-
-

Initializes converse.js. This method must always be called when using -converse.js.

-

The initialize method takes a map (also called a hash or dictionary) of -configuration variables.

-

Example:

-
converse.initialize({
-        allow_otr: true,
-        auto_list_rooms: false,
-        auto_subscribe: false,
-        bosh_service_url: 'https://bind.example.com',
-        hide_muc_server: false,
-        i18n: locales['en'],
-        keepalive: true,
-        play_sounds: true,
-        prebind: false,
-        show_controlbox_by_default: true,
-        debug: false,
-        roster_groups: true
-    });
-
-
-
-
-

“contacts” grouping

-
-

get

-

Returns a map of attributes for a given buddy (i.e. roster contact), specified -by JID (Jabber ID).

-

Example:

-
converse.contacts.get('buddy@example.com')
-
-
-

The map of attributes:

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attribute 
askIf ask === ‘subscribe’, then we have asked this person to be our chat buddy.
fullnameThe person’s full name.
jidThe person’s Jabber/XMPP username.
requestingIf true, then this person is asking to be our chat buddy.
subscriptionThe subscription state between the current user and this chat buddy. Can be none, to, from or both.
idA unique id, same as the jid.
chat_statusThe person’s chat status. Can be online, offline, busy, xa (extended away) or away.
user_idThe user id part of the JID (the part before the @).
resourcesThe known resources for this chat buddy. Each resource denotes a separate and connected chat client.
groupsThe roster groups in which this chat buddy was placed.
statusTheir human readable custom status message.
image_typeThe image’s file type.
imageThe Base64 encoded image data.
urlThe buddy’s website URL, as specified in their VCard data.
vcard_updatedWhen last the buddy’s VCard was updated.
-
-
-
-

“chats” grouping

-
-

get

-

Returns an object/map representing a chat box (without opening or affecting that chat box).

-

Example:

-
converse.chats.get('buddy@example.com')
-
-
-

The returned chat box contains the following methods:

- ---- - - - - - - - - - - - - - - - - - - - - - - - - - -
MethodDescription
endOTREnd an OTR (Off-the-record) session.
getGet an attribute (i.e. accessor).
initiateOTRStart an OTR (off-the-record) session.
maximizeMinimize the chat box.
minimizeMaximize the chat box.
setSet an attribute (i.e. mutator).
-

The get and set methods can be used to retrieve and change the following attributes:

- ---- - - - - - - - - - - - - - -
AttributeDescription
heightThe height of the chat box.
urlThe URL of the chat box heading.
-
-
-
-

“tokens” grouping

-
-

get

-

Returns a token, either the RID or SID token depending on what’s asked for.

-

Example:

-
converse.tokens.get('rid')
-
-
-
-
-
-

“listen” grouping

-

Converse.js emits events to which you can subscribe from your own Javascript.

-

Concerning events, the following methods are available under the “listen” -grouping:

-
    -
  • on(eventName, callback):

    -
    -

    Calling the on method allows you to subscribe to an event. -Every time the event fires, the callback method specified by callback will be -called.

    -

    Parameters:

    -
      -
    • eventName is the event name as a string.
    • -
    • callback is the callback method to be called when the event is emitted.
    • -
    -

    For example:

    -
    converse.listen.on('message', function (messageXML) { ... });
    -
    -
    -
    -
  • -
  • once(eventName, callback):

    -
    -

    Calling the once method allows you to listen to an event -exactly once.

    -

    Parameters:

    -
      -
    • eventName is the event name as a string.
    • -
    • callback is the callback method to be called when the event is emitted.
    • -
    -

    For example:

    -
    converse.listen.once('message', function (messageXML) { ... });
    -
    -
    -
    -
  • -
  • not(eventName, callback)

    -
    -

    To stop listening to an event, you can use the not method.

    -

    Parameters:

    -
      -
    • eventName is the event name as a string.
    • -
    • callback refers to the function that is to be no longer executed.
    • -
    -

    For example:

    -
    converse.listen.not('message', function (messageXML) { ... });
    -
    -
    -
    -
  • -
-
-
-
-

Events

-
-

Note

-

see also the “listen” grouping API section above.

-
-
-

Event Types

-

Here are the different events that are emitted:

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event TypeWhen is it triggered?Example
initializedOnce converse.js has been initialized.converse.on('initialized', function () { ... });
readyAfter connection has been established and converse.js has got all its ducks in a row.converse.on('ready', function () { ... });
reconnectAfter the connection has dropped. Converse.js will attempt to reconnect when not in prebind mode.converse.on('reconnect', function () { ... });
messageWhen a message is received.converse.on('message', function (messageXML) { ... });
messageSendWhen a message will be sent out.converse.on('messageSend', function (messageText) { ... });
noResumeableSessionWhen keepalive=true but there aren’t any stored prebind tokens.converse.on('noResumeableSession', function () { ... });
rosterWhen the roster is updated.converse.on('roster', function (items) { ... });
callButtonClickedWhen a call button (i.e. with class .toggle-call) on a chat box has been clicked.converse.on('callButtonClicked', function (connection, model) { ... });
chatBoxOpenedWhen a chat box has been opened.converse.on('chatBoxOpened', function (chatbox) { ... });
chatRoomOpenedWhen a chat room has been opened.converse.on('chatRoomOpened', function (chatbox) { ... });
chatBoxClosedWhen a chat box has been closed.converse.on('chatBoxClosed', function (chatbox) { ... });
chatBoxFocusedWhen the focus has been moved to a chat box.converse.on('chatBoxFocused', function (chatbox) { ... });
chatBoxToggledWhen a chat box has been minimized or maximized.converse.on('chatBoxToggled', function (chatbox) { ... });
roomInviteSentAfter the user has sent out a direct invitation, to a roster contact, asking them to join a room.converse.on('roomInvite', function (roomview, invitee_jid, reason) { ... });
roomInviteReceivedAfter the user has sent out a direct invitation, to a roster contact, asking them to join a room.converse.on('roomInvite', function (roomview, invitee_jid, reason) { ... });
statusChangedWhen own chat status has changed.converse.on('statusChanged', function (status) { ... });
statusMessageChangedWhen own custom status message has changed.converse.on('statusMessageChanged', function (message) { ... });
buddyStatusChangedWhen a chat buddy’s chat status has changed.converse.on('buddyStatusChanged', function (buddy, status) { ... });
buddyStatusMessageChangedWhen a chat buddy’s custom status message has changed.converse.on('buddyStatusMessageChanged', function (buddy, messageText) { ... });
-
-
-
-

Minification

-
-

Minifying Javascript and CSS

-

Please make sure to read the section Development and that you have installed -all development dependencies (long story short, you can run npm install -and then grunt fetch).

-

We use require.js to keep track of Converse.js and its dependencies and to -to bundle them together in a single minified file fit for deployment to a -production site.

-

To minify the Javascript and CSS, run the following command:

-
grunt minify
-
-
-

Javascript will be bundled and minified with require.js‘s optimization tool, -using almond.

-

You can read more about require.js’s optimizer here.

-

CSS is minified via cssmin.

-
-
-
-

Translations

-
-

Note

-

Translations take up a lot of space and will bloat your minified file. -At the time of writing, all the translations add about 50KB of extra data to -the minified javascript file. Therefore, make sure to only -include those languages that you intend to support and remove from -./locale/locales.js those which you don’t need. Remember to rebuild the -minified file afterwards.

-
-

The gettext POT file located in ./locale/converse.pot is the template -containing all translations and from which for each language an individual PO -file is generated.

-

The POT file contains all translateable strings extracted from converse.js.

-

To make a user facing string translateable, wrap it in the double underscore helper -function like so:

-
__('This string will be translated at runtime');
-
-
-

After adding the string, you’ll need to regenerate the POT file, like so:

-
make pot
-
-
-

To create a new PO file for a language in which converse.js is not yet -translated into, do the following

-
-

Note

-

In this example we use Polish (pl), you need to substitute ‘pl’ to your own language’s code.

-
-
mkdir -p ./locale/pl/LC_MESSAGES
-msginit -i ./locale/converse.pot -o ./locale/pl/LC_MESSAGES/converse.po -l pl
-
-
-

You can then create or update the PO file for a specific language by doing the following:

-
-

Note

-

In this example we use German (de), you need to substitute ‘de’ to your own language’s code.

-
-
msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U
-
-
-

To do this for ALL languages, run:

-
make po
-
-
-

The resulting PO file is then what gets translated.

-

If you’ve created a new PO file, please make sure to add the following -attributes at the top of the file (under Content-Transfer-Encoding). They are -required as configuration settings for Jed, the Javascript translations library -that we’re using.

-
"domain: converse\n"
-"lang: de\n"
-"plural_forms: nplurals=2; plural=(n != 1);\n"
-
-
-

Unfortunately Jed cannot use the PO files directly. We have to generate from it -a file in JSON format and then put that in a .js file for the specific -language.

-

To generate JSON from a PO file, you’ll need po2json for node.js. Run the -following command to install it (npm being the node.js package manager):

-
npm install po2json
-
-
-

You can then convert the translations into JSON format:

-
po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json
-
-
-

Now from converse.json paste the data as a value for the “locale_data” key in the -object in the language’s .js file.

-

So, if you are for example translating into German (language code ‘de’), you’ll -create or update the file ./locale/LC_MESSAGES/de.js with the following code:

-
(function (root, factory) {
-    define("de", ['jed'], function () {
-        return factory(new Jed({
-            "domain": "converse",
-            "locale_data": {
-                // Paste the JSON data from converse.json here
-            }
-        })
-    }
-}(this, function (i18n) {
-    return i18n;
-}));
-
-
-

making sure to also paste the JSON data as value to the “locale_data” key.

-
-

Note

-

If you are adding translations for a new language that is not already supported, -you’ll have to add the language path in main.js and make one more edit in ./locale/locales.js -to make sure the language is loaded by require.js.

-
-

Congratulations, you’ve now succesfully added your translations. Sorry for all -those hoops you had to jump through.

-
-
-
-

Troubleshooting

-
-

Conflicts with other Javascript libraries

-
-

Problem:

-

You are using other Javascript libraries (like JQuery plugins), and -get errors like these in your browser console:

-
Uncaught TypeError: Object [object Object] has no method 'xxx' from example.js
-
-
-
-
-

Solution:

-

First, find out which object is referred to by Object [object Object].

-

It will probably be the jQuery object $ or perhaps the underscore.js object _.

-

For the purpose of demonstration, I’m going to assume its $, but the same -rules apply if its something else.

-

The bundled and minified default build of converse.js, converse.min.js -includes within it all of converse.js’s dependencies, which include for example jQuery.

-

If you are having conflicts where attributes or methods aren’t available -on the jQuery object, you are probably loading converse.min.js (which -includes jQuery) as well as your own jQuery version separately.

-

What then happens is that there are two $ objects (one from -converse.js and one from the jQuery version you included manually) -and only one of them has been extended to have the methods or attributes you require.

-

Which jQuery object you get depends on the order in which you load the libraries.

-

There are multiple ways to solve this issue.

-

Firstly, make sure whether you really need to include a separate version of -jQuery. Chances are that you don’t. If you can remove the separate -version, your problem should be solved, as long as your libraries are loaded in -the right order.

-

Either case, whether you need to keep two versions or not, the solution depends -on whether you’ll use require.js to manage your libraries or whether you’ll -load them manually.

-
-

With require.js

-

Instead of using converse.min.js, manage all the libraries in your project -(i.e. converse.js and its dependencies plus all other libraries you use) as one -require.js project, making sure everything is loaded in the correct order.

-

Then, before deployment, you make your own custom minified build that bundles everything -you need.

-
-
-

With <script> tags

-

Take a look at non_amd.html -in the converse.js repo.

-

It shows in which order the libraries must be loaded via <script> tags. Add -your own libraries, making sure that they are loaded in the correct order (e.g. -jQuery plugins must load after jQuery).

-
-
-
-
-
-

Configuration

-

The included minified JS and CSS files can be used for demoing or testing, but -you’ll want to configure Converse.js to suit your needs before you deploy it -on your website.

-

Converse.js is passed its configuration settings when you call its -initialize method.

-

You’ll most likely want to call the initialize method in your HTML page. For -an example of how this is done, please see the bottom of the ./index.html page.

-

Please refer to the Configuration variables section below for info on -all the available configuration settings.

-

After you have configured Converse.js, you’ll have to regenerate the minified -JS file so that it will include the new settings. Please refer to the -Minification section for more info on how to do this.

-
-

Configuration variables

-
-

allow_contact_requests

-

Default: true

-

Allow users to add one another as contacts. If this is set to false, the -Add a contact widget, Contact Requests and Pending Contacts roster -sections will all not appear. Additionally, all incoming contact requests will be -ignored.

-
-
-

allow_muc

-

Default: true

-

Allow multi-user chat (muc) in chatrooms. Setting this to false will remove -the Chatrooms tab from the control box.

-
-
-

allow_otr

-

Default: true

-

Allow Off-the-record encryption of single-user chat messages.

-
-
-

animate

-

Default: true

-

Show animations, for example when opening and closing chat boxes.

-
-
-

auto_list_rooms

-

Default: false

-

If true, and the XMPP server on which the current user is logged in supports -multi-user chat, then a list of rooms on that server will be fetched.

-

Not recommended for servers with lots of chat rooms.

-

For each room on the server a query is made to fetch further details (e.g. -features, number of occupants etc.), so on servers with many rooms this -option will create lots of extra connection traffic.

-
-
-

auto_reconnect

-

Default: true

-

Automatically reconnect to the XMPP server if the connection drops -unexpectedly.

-
-
-

auto_subscribe

-

Default: false

-

If true, the user will automatically subscribe back to any contact requests.

-
-
-

bosh_service_url

-

Connections to an XMPP server depend on a BOSH connection manager which acts as -a middle man between HTTP and XMPP.

-

See here for more information.

-
-
-

cache_otr_key

-

Default: false

-

Let the OTR (Off-the-record encryption) private -key be cached in your browser’s session storage.

-

The browser’s session storage persists across page loads but is deleted once -the tab or window is closed.

-

If this option is set to false, a new OTR private key will be generated -for each page load. While more inconvenient, this is a much more secure option.

-

This setting can only be used together with allow_otr = true.

-
-

Note

-

A browser window’s session storage is accessible by all javascript that -is served from the same domain. So if there is malicious javascript served by -the same server (or somehow injected via an attacker), then they will be able -to retrieve your private key and read your all the chat messages in your -current session. Previous sessions however cannot be decrypted.

-
-
-
-

debug

-

Default: false

-

If set to true, debugging output will be logged to the browser console.

-
-
-

keepalive

-

Default: true

-

Determines whether Converse.js will maintain the chat session across page -loads.

-

See also:

- -
-
-

message_carbons

-

Default: false

-

Support for XEP-0280: Message Carbons

-

In order to keep all IM clients for a user engaged in a conversation, -outbound messages are carbon-copied to all interested resources.

-

This is especially important in webchat, like converse.js, where each browser -tab serves as a separate IM client.

-

Both message_carbons and forward_messages try to solve the same problem -(showing sent messages in all connected chat clients aka resources), but go about it -in two different ways.

-

Message carbons is the XEP (Jabber protocol extension) specifically drafted to -solve this problem, while `forwarded_messages`_ uses -stanza forwarding

-
-
-

expose_rid_and_sid

-

Default: false

-

Allow the prebind tokens, RID (request ID) and SID (session ID), to be exposed -globally via the API. This allows other scripts served on the same page to use -these values.

-

Beware: a malicious script could use these tokens to assume your identity -and inject fake chat messages.

-
-
-

forward_messages

-

Default: false

-

If set to true, sent messages will also be forwarded to the sending user’s -bare JID (their Jabber ID independent of any chat clients aka resources).

-

This means that sent messages are visible from all the user’s chat clients, -and not just the one from which it was actually sent.

-

This is especially important for web chat, such as converse.js, where each -browser tab functions as a separate chat client, with its own resource.

-

This feature uses Stanza forwarding, see also XEP 0297: Stanza Forwarding

-

For an alternative approach, see also `message carbons`_.

-
-
-

fullname

-

If you are using prebinding, can specify the fullname of the currently -logged in user, otherwise the user’s vCard will be fetched.

-
-
-

hide_muc_server

-

Default: false

-

Hide the server input field of the form inside the Room panel of the -controlbox. Useful if you want to restrict users to a specific XMPP server of -your choosing.

-
-
-

i18n

-

Specify the locale/language. The language must be in the locales object. Refer to -./locale/locales.js to see which locales are supported.

-
-
-

play_sounds

-

Default: false

-

Plays a notification sound when you receive a personal message or when your -nickname is mentioned in a chat room.

-

Inside the ./sounds directory of the Converse.js repo, you’ll see MP3 and Ogg -formatted sound files. We need both, because neither format is supported by all browsers.

-

For now, sound files are looked up by convention, not configuration. So to have -a sound play when a message is received, make sure that your webserver serves -it in both formats as http://yoursite.com/sounds/msg_received.mp3 and -http://yoursite.com/sounds/msg_received.ogg.

-

http://yoursite.com should of course be your site’s URL.

-
-
-

prebind

-

Default: false

-

See also: Prebinding and Single Session Support

-

Use this option when you want to attach to an existing XMPP connection that was -already authenticated (usually on the backend before page load).

-

This is useful when you don’t want to render the login form on the chat control -box with each page load.

-

For prebinding to work, you must set up a pre-authenticated BOSH session, -for which you will receive a JID (jabber ID), SID (session ID) and RID -(Request ID).

-

These values (rid, sid and jid) need to be passed into -converse.initialize (with the exception of keepalive, see below).

-

Additionally, you also have to specify a bosh_service_url.

-
-

Using prebind in connection with keepalive

-

The prebind and keepalive options can be used together.

-

The keepalive option caches the rid, sid and jid values -(henceforth referred to as session tokens) one receives from a prebinded -BOSH session, in order to re-use them when the page reloads.

-

However, if besides setting keepalive to true, you also set prebind -to true, and you pass in valid session tokens to converse.initialize, -then those passed in session tokens will be used instead of any tokens cached by -keepalive.

-

If you set prebind to true and don’t pass in the session tokens to -converse.initialize, then converse.js will look for tokens cached by -keepalive.

-

If you’ve set keepalive and prebind to true, don’t pass in session -tokens and converse.js doesn’t find any cached session tokens, then -converse.js will emit an event noResumeableSession and exit.

-

This allows you to start a prebinded session with valid tokens, and then fall -back to keepalive for maintaining that session across page reloads. When -for some reason keepalive doesn’t have cached session tokens anymore, you -can listen for the noResumeableSession event and take that as a cue that -you should again prebind in order to get valid session tokens.

-

Here is a code example:

-
converse.on('noResumeableSession', function () {
-    $.getJSON('/prebind', function (data) {
-        converse.initialize({
-            prebind: true,
-            keepalive: true,
-            bosh_service_url: 'https://bind.example.com',
-            jid: data.jid,
-            sid: data.sid,
-            rid: data.rid
-        });
-    });
-});
-converse.initialize({
-    prebind: true,
-    keepalive: true,
-    bosh_service_url: 'https://bind.example.com'
-}));
-
-
-
-
-
-

roster_groups

-

Default: false

-

If set to true, converse.js will show any roster groups you might have -configured.

-
-

Note

-

It’s currently not possible to use converse.js to assign contacts to groups. -Converse.js can only show users and groups that were previously configured -elsewhere.

-
-
-
-

show_controlbox_by_default

-

Default: false

-

The “controlbox” refers to the special chatbox containing your contacts roster, -status widget, chatrooms and other controls.

-

By default this box is hidden and can be toggled by clicking on any element in -the page with class toggle-controlbox.

-

If this options is set to true, the controlbox will by default be shown upon -page load.

-
-
-

show_only_online_users

-

Default: false

-

If set to true, only online users will be shown in the contacts roster. -Users with any other status (e.g. away, busy etc.) will not be shown.

-
-
-

storage

-

Default: session

-

Valid options: session, local.

-

This option determines the type of storage -(localStorage or sessionStorage) used by converse.js to cache user data.

-

Originally converse.js used only localStorage, however sessionStorage is from a -privacy perspective a better choice.

-

The main difference between the two is that sessionStorage only persists while -the current tab or window containing a converse.js instance is open. As soon as -it’s closed, the data is cleared.

-

Data in localStorage on the other hand is kept indefinitely.

-
-

Note

-

Since version 0.8.0, the use of local storage is not recommended. The -statuses (online, away, busy etc.) of your roster contacts are cached in -the browser storage. If you use local storage, these values are stored for -multiple sessions, and they will likely become out of sync with your contacts’ -actual statuses. The session storage doesn’t have this problem, because -roster contact statuses will not become out of sync in a single session, -only across more than one session.

-
-
-
-

use_otr_by_default

-

Default: false

-

If set to true, Converse.js will automatically try to initiate an OTR (off-the-record) -encrypted chat session every time you open a chat box.

-
-
-

use_vcards

-

Default: true

-

Determines whether the XMPP server will be queried for roster contacts’ VCards -or not. VCards contain extra personal information such as your fullname and -avatar image.

-
-
-

visible_toolbar_buttons

-

Default:

-
{
-    call: false,
-    clear: true,
-    emoticons: true,
-    toggle_participants: true
-}
-
-
-

Allows you to show or hide buttons on the chat boxes’ toolbars.

-
    -
  • -
    call:
    -

    Provides a button with a picture of a telephone on it. -When the call button is pressed, it will emit an event that can be used by a third-party library to initiate a call.:

    -
    converse.on('callButtonClicked', function(event, data) {
    -    console.log('Strophe connection is', data.connection);
    -    console.log('Bare buddy JID is', data.model.get('jid'));
    -    // ... Third-party library code ...
    -});
    -
    -
    -
    -
    -
  • -
  • -
    clear:
    -

    Provides a button for clearing messages from a chat box.

    -
    -
    -
  • -
  • -
    emoticons:
    -

    Enables rendering of emoticons and provides a toolbar button for choosing them.

    -
    -
    -
  • -
  • -
    toggle_participants:
    -

    Shows a button for toggling (i.e. showing/hiding) the list of participants in a chat room.

    -
    -
    -
  • -
-
-
-

xhr_custom_status

-

Default: false

-
-

Note

-

XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).

-
-

This option will let converse.js make an AJAX POST with your changed custom chat status to a -remote server.

-
-
-

xhr_custom_status_url

-
-

Note

-

XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).

-
-

Default: Empty string

-

Used only in conjunction with xhr_custom_status.

-

This is the URL to which the AJAX POST request to set the user’s custom status -message will be made.

-

The message itself is sent in the request under the key msg.

-
- -
-

xhr_user_search_url

-
-

Note

-

XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).

-
-

Default: Empty string

-

Used only in conjunction with xhr_user_search.

-

This is the URL to which an AJAX GET request will be made to fetch user data from your remote server. -The query string will be included in the request with q as its key.

-

The calendar can be configured through a data-pat-calendar attribute. -The available options are:

-
-
-
- - -
-
-
-
- -
- -
- - - \ No newline at end of file diff --git a/docs/html/objects.inv b/docs/html/objects.inv deleted file mode 100644 index e11d61944..000000000 --- a/docs/html/objects.inv +++ /dev/null @@ -1,7 +0,0 @@ -# Sphinx inventory version 2 -# Project: Converse.js -# Version: 0.8.3 -# The remainder of this file is compressed using zlib. -xm - {"]; ->]4,n -ܠ|Lum)^q=<ґjcP!W_L`v: ARrmmups{p`z5}xT+ \ No newline at end of file diff --git a/docs/html/search.html b/docs/html/search.html deleted file mode 100644 index 357b04825..000000000 --- a/docs/html/search.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - Search — Converse.js 0.8.3 documentation - - - - - - - - - - - - - - - - - -
-
-

Converse.js

-

Documentation

-
-
- - -
- -
- -
-
-
- -

Search

-
- -

- Please activate JavaScript to enable the search - functionality. -

-
-

- From here you can search these documents. Enter your search - words into the box below and click "search". Note that the search - function will automatically search for all of the words. Pages - containing fewer words won't appear in the result list. -

-
- - - -
- -
- -
- -
-
-
-
- -
- -
- - - \ No newline at end of file diff --git a/docs/html/searchindex.js b/docs/html/searchindex.js deleted file mode 100644 index 175a13182..000000000 --- a/docs/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({envversion:42,terms:{all:0,partial:0,edg:[],chain:0,queri:0,lack:0,standardis:0,webchat:0,mp3:0,abil:0,follow:0,row:0,privat:0,typeerror:0,sensit:0,punjab:0,base64:0,readabl:0,allow_otr:[],send:0,vcard:0,buddi:0,under:0,sens:0,spec:0,sent:0,file:0,global:0,everi:0,string:0,fals:0,voic:0,offlin:0,mechan:0,jack:0,fall:0,veri:[],affect:0,tri:[],button:0,messagetext:0,list:0,virtualhost:0,correct:0,"try":0,item:0,sane:[],pleas:0,prevent:0,almond:0,prosodi:0,focu:0,jump:0,second:0,jid2:0,jid1:0,download:0,further:0,port:0,folk:0,even:0,index:0,hide:0,appear:0,section:0,abl:0,current:0,delet:0,version:0,"new":0,net:0,"public":0,widget:0,full:0,themselv:[],messagexml:0,join:0,gener:0,here:0,bodi:0,middl:0,let:0,path:0,becom:0,modifi:[],sinc:0,valu:0,box:0,great:0,convers:0,mysit:0,anymor:0,reason:0,fetch:0,implement:0,sorri:0,chanc:0,via:0,although:0,danger:0,primit:0,prefer:0,ask:0,href:0,fake:0,sessionstorag:0,establish:0,from:0,zip:0,commun:0,deop:0,doubl:0,two:0,next:0,websit:0,few:[],stylesheet:0,call:0,msg:0,until:0,tightli:0,more:0,emoticon:0,peopl:[],line:0,notic:0,particular:[],known:0,cach:0,must:0,none:0,word:0,room:[],work:0,uniqu:0,dev:0,xhr:0,can:0,lc_messag:0,purpos:0,root:0,blogpost:0,control:0,getsess:[],give:0,challeng:0,share:0,templat:0,topic:0,critic:0,movim:[],proprietari:0,explor:0,onlin:0,callbuttonclick:0,occup:0,alwai:0,cours:0,multipl:0,goal:0,turn:0,anoth:0,deniabl:0,write:0,how:0,bosh_serv:[],sid:0,verifi:0,perspect:0,updat:0,npm:0,map:0,product:0,resourc:0,earlier:0,usabl:0,shortliv:0,wrong:0,mai:0,pat:0,underscor:0,data:0,demonstr:0,man:0,repo:0,"short":0,attempt:0,practic:[],third:0,nativ:0,seriou:0,secur:0,credenti:0,correspond:0,element:0,caus:0,inform:0,maintain:0,allow:0,parti:0,order:0,talk:0,feedback:[],chatbox:0,chatroomopen:0,over:0,move:0,becaus:0,chatboxopen:0,increas:0,telephon:0,through:0,reconnect:0,still:0,paramet:[],streamlin:0,jid:0,"8147a27e4a7f9b55ffc85c2683f9529a":[],render:0,fit:0,fix:0,better:0,whether:0,window:0,pend:0,persist:0,mail:0,hidden:0,main:0,might:0,hoop:0,them:0,lastnam:0,"return":0,thei:0,python:0,toggle_particip:0,initi:[],rewriterul:0,mention:0,instead:0,aka:0,now:0,choic:0,name:0,edit:0,drop:0,crypto:0,separ:0,achiev:0,ejabberd:0,each:0,complet:0,mean:0,subset:0,status:0,harm:0,chatboxfocus:0,regener:0,experiment:[],michael:0,individu:0,idea:0,librelist:0,"static":0,expect:0,our:0,happen:0,extract:0,special:0,out:0,shown:0,"3rd":0,space:0,open:0,proxy_pass:0,rel:0,internet:0,got:0,plural:0,factori:0,po2json:0,model:0,after:0,proxi:0,insid:0,state:0,given:0,standard:0,standalon:0,ajax:0,dictionari:0,put:0,succesfulli:0,afterward:0,roominvites:0,unhandl:[],could:0,keep:0,thing:[],perhap:0,place:0,nicknam:0,imposs:0,token:[],first:0,origin:0,softwar:0,directli:0,malici:0,onc:0,arrai:0,independ:0,number:0,yourself:0,instruct:0,alreadi:0,done:0,owner:0,custom:0,miss:0,suffic:0,size:0,differ:0,convent:0,top:0,mkdir:0,attack:0,messag:0,attach:0,stori:0,draft:0,jed:0,privaci:0,forwarded_messag:0,store:0,listen:[],luckili:0,assign:0,consol:0,option:0,especi:0,tool:0,copi:0,specifi:0,direct:0,maxim:0,part:0,pars:0,moder:0,ogg:0,exactli:0,than:0,serv:0,past:0,kind:0,bloat:0,provid:0,remov:0,jqueri:0,bridg:0,bind:0,toward:0,someothersit:0,browser:0,pre:0,analysi:0,sai:0,saa:0,session_kei:[],ani:0,packag:0,properli:0,increment:0,moffitt:0,django:0,normal:0,issu:0,outbound:0,built:0,callback:0,latter:0,yoursit:0,thorough:[],click:0,note:[],also:0,contact:[],take:0,which:0,therefor:0,sure:0,roster:0,unsur:0,previou:0,reach:0,most:0,plai:0,eavesdropp:0,homepag:0,"class":0,msginit:0,don:0,bug:0,url:0,clear:0,doe:0,noresumeablesess:0,runtim:0,statuschang:0,bower:0,latest:0,xdomainrequest:0,devdepend:0,show:0,german:0,text:0,buddystatuschang:0,server_nam:0,identifi:0,fine:0,find:0,help:0,xml:0,henceforth:0,onli:0,grunt:0,locat:0,execut:0,explain:0,mute:0,releas:0,stanza:0,chat_statu:0,haven:[],busi:0,roominvitereceiv:0,folder:0,local:0,meant:0,wide:[],stop:0,account:[],soon:0,opkod:[],initiateotr:0,cannot:0,cryptographi:0,report:0,subscript:0,enabl:0,emb:0,approach:0,mainspec:0,multi:0,patch:0,remot:0,deploy:0,contain:0,ban:0,where:0,wiki:[],chatboxclos:0,stroph:0,see:0,bare:0,result:0,close:0,calendar:0,eventnam:0,best:0,concern:0,awar:[],statu:0,said:[],kei:0,inconveni:0,someth:0,particip:0,written:0,muc:0,between:0,"import":0,neither:0,experi:0,jasmin:0,across:0,attribut:0,altern:0,perfect:0,accord:0,appreci:[],extend:0,screen:0,were:0,conjunct:0,extens:0,job:0,entir:0,otherwis:0,"5e64a30272af065bd72258c565a03f2f":[],group:[],both:0,cor:0,instant:0,plugin:0,howev:0,avatar:0,etc:0,instanc:0,grain:0,logic:0,mani:0,login:0,com:0,load:0,simpli:0,pot:0,height:0,sync:0,solv:0,non:0,deploi:0,carbon:0,constant:0,assum:0,malleabl:0,backend:0,quit:[],user_id:0,sucessfulli:0,addition:0,rebuild:0,due:0,been:0,accessor:0,compon:0,json:0,much:0,besid:0,toolbar:0,interest:0,subscrib:0,modern:0,fire:0,imag:0,xxx:0,rubi:0,convert:0,togeth:0,input:0,last:0,otr:0,plausibl:0,present:0,"case":0,myself:[],ident:0,look:0,gnu:0,servic:0,invit:0,messagesend:0,defin:0,"while":0,kick:0,abov:0,observ:0,hightlight:0,engag:0,helper:0,readi:0,site:0,itself:0,incom:0,rid:0,mutat:0,welcom:0,minim:0,receiv:0,media:0,make:0,format:0,same:0,webpag:0,onconnectfacebook:[],html:0,unexpectedli:0,chatroom:0,document:0,medit:[],higher:0,breakdown:0,signon:0,http:0,webserv:0,denot:0,optim:0,roomview:0,upon:0,someon:[],hand:0,fairli:0,"50kb":0,user:0,roominvit:0,uncaught:0,php:0,cssmin:0,recent:0,weibel:0,stateless:0,travers:0,kept:0,bewar:0,firstli:0,markup:0,min:0,well:0,thought:0,person:0,client:0,command:[],wherebi:0,thi:0,choos:0,everyth:0,usual:0,plural_form:0,protocol:0,just:0,when:0,xep:0,human:0,polish:0,yet:0,languag:0,previous:0,web:0,fraught:0,xmlhttprequest:0,expos:0,nick:0,extra:0,had:0,except:0,desktop:0,cue:0,non_amd:0,versa:0,appli:0,els:0,match:0,build:0,applic:0,secreci:0,read:0,intuit:0,traffic:0,know:0,press:0,xss:0,like:0,specif:0,should:0,reload:0,manual:0,benefit:0,api:[],either:0,have:0,popular:0,output:0,mode:0,page:0,candi:0,indefinit:0,facebookconnect:[],revers:0,chatboxtoggl:0,who:[],deal:0,visibl:0,some:0,substitu:0,certain:0,endotr:0,openfir:0,bottom:0,avoid:0,though:0,rewriteengin:0,usernam:0,substitut:0,exit:0,inject:0,speak:0,localhost:[],refer:0,somehow:0,plu:0,object:0,msg_receiv:0,host:0,repositori:0,post:0,panel:0,src:0,about:0,actual:0,would:0,invitee_jid:0,firstnam:0,controlbox:0,unfortun:0,stand:0,act:0,own:0,curiou:0,inlin:0,within:0,encod:0,automat:0,right:0,empti:0,wrap:0,chang:0,merg:[],git:0,log:0,wai:0,pictur:0,aren:0,transfer:0,"long":0,happi:0,avail:0,start:0,trigger:0,localstorag:0,includ:0,lot:0,suit:0,forward:0,"function":0,project:0,head:0,nplural:0,form:0,bundl:0,back:0,link:0,buddystatusmessagechang:0,synonym:0,cryptograph:0,realli:0,"true":0,awai:0,congratul:0,requirej:0,info:0,made:0,dirti:[],tab:0,possibl:0,"default":0,access:0,asynchron:0,below:0,those:0,toggl:0,legwork:0,emit:0,significantli:0,gone:0,hash:0,creat:0,retriev:0,decrypt:0,doesn:0,repres:0,msgmerg:0,exist:0,chat:[],face:0,probabl:0,again:0,image_typ:0,want:0,tip:[],detail:0,gettext:0,statusmessagechang:0,field:0,valid:0,rememb:0,varieti:[],servernam:0,nice:0,node:0,intend:0,determin:0,duck:0,harsh:0,org:0,vcard_upd:0,elsewher:0,track:0,consid:0,conversej:0,stai:0,lang:0,longer:0,vice:0,directori:0,descript:[],getjson:0,rule:0,ignor:0,locale_data:0,potenti:0,time:0},objtypes:{},objnames:{},filenames:["index"],titles:["Quickstart (to get a demo up and running)"],objects:{},titleterms:{demo:0,roster_group:0,multilingu:0,code:0,xmpp:0,session:0,jshint:0,paramet:[],group:0,singl:0,configur:0,apach:0,add:0,anim:0,get:0,end:0,amd:0,initi:0,nginx:0,facebook:[],front:0,requir:0,introduct:0,troubleshoot:0,authent:0,server:0,play_sound:0,bad:0,integr:[],debug:0,side:0,domain:0,set:[],habit:0,xhr_user_search_url:0,connect:0,pass:0,fullnam:0,event:0,librari:0,variabl:0,what:0,storag:0,xhr_custom_statu:0,content:0,show_only_online_us:0,allow_otr:0,use_otr_by_default:0,overcom:0,method:[],run:0,hide_muc_serv:0,javascript:0,visible_toolbar_button:0,bosh:0,depend:0,xhr_custom_status_url:0,cache_otr_kei:0,manag:0,solut:0,restrict:0,api:0,auto_list_room:0,instal:0,jabber:[],your:0,script:0,support:0,submit:0,getsid:[],recommend:0,type:0,listen:0,show_controlbox_by_default:0,notif:0,minifi:0,translat:0,i18n:0,getrid:[],sound:0,pull:0,room:0,bugfix:0,exampl:0,record:0,error:0,auto_reconnect:0,problem:0,featur:0,quickstart:0,forward_messag:0,descript:[],auto_subscrib:0,argument:[],tag:0,chat:0,tabl:0,need:0,check:0,bosh_service_url:0,prebind:0,develop:0,message_carbon:0,getbuddi:[],cross:0,other:0,test:0,expose_rid_and_sid:0,you:0,css:0,keepal:0,befor:0,allow_contact_request:0,encrypt:0,minif:0,xhr_user_search:0,off:0,use_vcard:0,request:0,without:0,allow_muc:0,contact:0,command:0,token:0,conflict:0}}) \ No newline at end of file diff --git a/docs/source/_static/conversejs_small.png b/docs/source/_static/conversejs_small.png new file mode 100644 index 0000000000000000000000000000000000000000..3c86868bc7a18da137b1777fb6d89234c4dcdeb4 GIT binary patch literal 574 zcmV-E0>S->P)z<9I#fyr|t)@Gx^acBCd&@}SWRm)n!k+Dllf3uLoo!Gn?rPK0Mi zHjs&mbY9K{vOL0hlDvHX=arbe;|(G`Sg~g=r$)LZ5Qp$7CrBU93b*eI_?WtUTM@{x zoNt8gTgw~xUqEVojJG3@rfe-P-=__NyeMAXx>(P6(5>SUj@eE27yn#J-oh(bV*mgE M07*qoM6N<$f;gJ|KL7v# literal 0 HcmV?d00001 diff --git a/docs/source/_static/favicon.ico b/docs/source/_static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f2c3de77eef720525705ba6ee7e41faa4e06537f GIT binary patch literal 1150 zcmc(Z!3uyd3_~OM0Xup2=%@MrcbOR)kP^Xe2P@rUS<(tj{7M1O75fY<05&!yDwj?G zd^1(49qh*6yWZ9FFUpG98On*-eDkX^*_O%pqqk@0bB6L6j^^7g&G@p{d7b8F$tTJa a@6sdX6ZIbN(jA@GX)gPwDL+WY`|AWy$SX4d literal 0 HcmV?d00001 diff --git a/docs/source/_static/style.css b/docs/source/_static/style.css new file mode 100644 index 000000000..6f7474995 --- /dev/null +++ b/docs/source/_static/style.css @@ -0,0 +1,3 @@ +.navbar-brand { + padding-top: 7px; +} diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html index 385713149..efce3f8d0 100644 --- a/docs/source/_templates/layout.html +++ b/docs/source/_templates/layout.html @@ -1,205 +1,5 @@ -{%- block doctype -%} - -{%- endblock %} -{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} -{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} -{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and - (sidebars != []) %} -{%- set url_root = pathto('', 1) %} -{# XXX necessary? #} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} -{%- if not embedded and docstitle %} - {%- set titlesuffix = " — "|safe + docstitle|e %} -{%- else %} - {%- set titlesuffix = "" %} -{%- endif %} +{# Import the theme's layout. #} +{% extends "!layout.html" %} -{%- macro relbar() %} - -{%- endmacro %} - -{%- macro sidebar() %} - {%- if render_sidebar %} -
-
- {%- block sidebarlogo %} - {%- if logo %} - - {%- endif %} - {%- endblock %} - {%- if sidebars != None %} - {#- new style sidebar: explicitly include/exclude templates #} - {%- for sidebartemplate in sidebars %} - {%- include sidebartemplate %} - {%- endfor %} - {%- else %} - {#- old style sidebars: using blocks -- should be deprecated #} - {%- block sidebartoc %} - {%- include "localtoc.html" %} - {%- endblock %} - {%- block sidebarrel %} - {%- include "relations.html" %} - {%- endblock %} - {%- block sidebarsourcelink %} - {%- include "sourcelink.html" %} - {%- endblock %} - {%- if customsidebar %} - {%- include customsidebar %} - {%- endif %} - {%- block sidebarsearch %} - {%- include "searchbox.html" %} - {%- endblock %} - {%- endif %} -
-
- {%- endif %} -{%- endmacro %} - -{%- macro script() %} - - {%- for scriptfile in script_files %} - - {%- endfor %} -{%- endmacro %} - -{%- macro css() %} - - - {%- for cssfile in css_files %} - - {%- endfor %} -{%- endmacro %} - - - - - {{ metatags }} - {%- block htmltitle %} - {{ title|striptags|e }}{{ titlesuffix }} - {%- endblock %} - {{ css() }} - {%- if not embedded %} - {{ script() }} - {%- if use_opensearch %} - - {%- endif %} - {%- if favicon %} - - {%- endif %} - {%- endif %} -{%- block linktags %} - {%- if hasdoc('about') %} - - {%- endif %} - {%- if hasdoc('genindex') %} - - {%- endif %} - {%- if hasdoc('search') %} - - {%- endif %} - {%- if hasdoc('copyright') %} - - {%- endif %} - - {%- if parents %} - - {%- endif %} - {%- if next %} - - {%- endif %} - {%- if prev %} - - {%- endif %} -{%- endblock %} -{%- block extrahead %} {% endblock %} - - -{%- block header %} -
-
-

Converse.js

-

Documentation

-
-
-{% endblock %} - -
-{%- block relbar1 %}{{ relbar() }}{% endblock %} -
- -{%- block content %} - {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %} - -
- {%- block document %} -
- {%- if render_sidebar %} -
- {%- endif %} -
- {% block body %} {% endblock %} -
- {%- if render_sidebar %} -
- {%- endif %} -
- {%- endblock %} - - {%- block sidebar2 %}{{ sidebar() }}{% endblock %} -
-
-{%- endblock %} - -
-{%- block relbar2 %}{{ relbar() }}{% endblock %} -
- -{%- block footer %} - -{%- endblock %} - - +{# Custom CSS overrides #} +{% set bootswatch_css_custom = ['_static/style.css'] %} diff --git a/docs/source/conf.py b/docs/source/conf.py index 06088331e..c4991e247 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -91,18 +91,72 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'theme' +import sphinx_bootstrap_theme +html_theme = 'bootstrap' +html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# (Optional) Logo. Should be small enough to fit the navbar (ideally 24x24). +# Path should be relative to the ``_static`` files directory. +html_logo = "_static/conversejs_small.png" + +# Theme options are theme-specific and customize the look and feel of a +# theme further. html_theme_options = { - 'nosidebar': True + # Navigation bar title. (Default: ``project`` value) + 'navbar_title': "Converse.js", + # Tab name for entire site. (Default: "Site") + 'navbar_site_name': "Converse.js Documentation", + # A list of tuples containing pages or urls to link to. + # Valid tuples should be in the following forms: + # (name, page) # a link to a page + # (name, "/aa/bb", 1) # a link to an arbitrary relative url + # (name, "http://example.com", True) # arbitrary absolute url + # Note the "1" or "True" value above as the third argument to indicate + # an arbitrary url. + 'navbar_links': [ + ("Main Site", "https://conversejs.org", True), + ("Download", "https://github.com/jcbrand/converse.js/releases", True), + ], + # Render the next and previous page links in navbar. (Default: true) + 'navbar_sidebarrel': True, + # Render the current pages TOC in the navbar. (Default: true) + 'navbar_pagenav': True, + # Tab name for the current pages TOC. (Default: "Page") + 'navbar_pagenav_name': "Page", + # Global TOC depth for "site" navbar tab. (Default: 1) + # Switching to -1 shows all levels. + 'globaltoc_depth': 2, + # Include hidden TOCs in Site navbar? + # + # Note: If this is "false", you cannot have mixed ``:hidden:`` and + # non-hidden ``toctree`` directives in the same page, or else the build + # will break. + # + # Values: "true" (default) or "false" + 'globaltoc_includehidden': "true", + # HTML navbar class (Default: "navbar") to attach to
element. + # For black navbar, do "navbar navbar-inverse" + 'navbar_class': "navbar", + # Fix navigation bar to top of page? + # Values: "true" (default) or "false" + 'navbar_fixed_top': "true", + # Location of link to source. + # Options are "nav" (default), "footer" or anything else to exclude. + 'source_link_position': "nav", + # Bootswatch (http://bootswatch.com/) theme. + # Options are nothing (default) or the name of a valid theme + # such as "amelia" or "cosmo". + # 'bootswatch_theme': "yeti", + # Choose Bootstrap version. + # Values: "3" (default) or "2" (in quotes) + 'bootstrap_version': "3", } -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['.'] - # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None @@ -110,19 +164,10 @@ html_theme_path = ['.'] # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_favicon = "_static/favicon.ico" # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff --git a/docs/source/index.rst b/docs/source/index.rst index 6d610386f..d9953eb85 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -23,7 +23,7 @@ When you download a specific release of *Converse.js* there will be two minified You can include these two files inside the ** element of your website via the *script* and *link* tags: -:: +.. code-block:: html @@ -37,7 +37,7 @@ all the available configuration settings. To configure Converse.js, put the following inline Javascript code at the bottom of your page (after the closing ** element). -:: +.. code-block:: javascript require(['converse'], function (converse) { converse.initialize({ @@ -264,7 +264,8 @@ Your ``nginx`` or ``apache`` configuration will look as follows: Nginx ~~~~~ -:: + +.. code-block:: nginx http { server { @@ -278,7 +279,8 @@ Nginx Apache ~~~~~~ -:: + +.. code-block:: apache ServerName mysite.com @@ -314,7 +316,9 @@ do the pre-authentication before the web page loads. an XMPP server in order to chat. So the BOSH server acts as a middle man, translating our HTTP requests into XMPP stanzas and vice versa. -Jack Moffitt has a great `blogpost`_ about this and even provides an `example Django application`_ to demonstrate it. +Jack Moffitt has a great `blogpost`_ about this and even provides an +`example Django application `_ +to demonstrate it. When you authenticate to the XMPP server on your backend application (for example via a BOSH client in Django), you'll receive two tokens, RID (request ID) and SID (session ID). @@ -337,7 +341,7 @@ XMLHttpRequest call to your server and ask it to return them for you. Below is one example of how this could work. An Ajax call is made to the relative URL **/prebind** and it expects to receive JSON data back. -:: +.. code-block:: javascript $.getJSON('/prebind', function (data) { converse.initialize({ @@ -447,7 +451,7 @@ non-minified javascript files. Add the following two lines to the ** section of your webpage: -:: +.. code-block:: html @@ -553,7 +557,9 @@ converse.js. The `initialize` method takes a map (also called a hash or dictionary) of `configuration variables`_. -Example:: +Example: + +.. code-block:: javascript converse.initialize({ allow_otr: true, @@ -769,9 +775,9 @@ Here are the different events that are emitted: +--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ | **statusMessageChanged** | When own custom status message has changed. | ``converse.on('statusMessageChanged', function (message) { ... });`` | +--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **contactStatusChanged** | When a chat buddy's chat status has changed. | ``converse.on('contactStatusChanged', function (buddy, status) { ... });`` | +| **contactStatusChanged** | When a chat buddy's chat status has changed. | ``converse.on('contactStatusChanged', function (buddy, status) { ... });`` | +--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ -| **contactStatusMessageChanged** | When a chat buddy's custom status message has changed. | ``converse.on('contactStatusMessageChanged', function (buddy, messageText) { ... });`` | +| **contactStatusMessageChanged**| When a chat buddy's custom status message has changed. | ``converse.on('contactStatusMessageChanged', function (buddy, messageText) { ... });`` | +--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ @@ -822,7 +828,7 @@ The POT file contains all translateable strings extracted from converse.js. To make a user facing string translateable, wrap it in the double underscore helper function like so: -:: +.. code-block:: javascript __('This string will be translated at runtime'); @@ -863,7 +869,7 @@ attributes at the top of the file (under *Content-Transfer-Encoding*). They are required as configuration settings for Jed, the Javascript translations library that we're using. -:: +.. code-block:: po "domain: converse\n" "lang: de\n" @@ -893,7 +899,7 @@ object in the language's .js file. So, if you are for example translating into German (language code 'de'), you'll create or update the file ./locale/LC_MESSAGES/de.js with the following code: -:: +.. code-block:: javascript (function (root, factory) { define("de", ['jed'], function () { @@ -1084,7 +1090,7 @@ bosh_service_url Connections to an XMPP server depend on a BOSH connection manager which acts as a middle man between HTTP and XMPP. -See `here `_ for more information. +For more information, read this blog post: `Which BOSH server do you need? `_ cache_otr_key ------------- @@ -1154,7 +1160,7 @@ Both message_carbons and `forward_messages`_ try to solve the same problem in two different ways. Message carbons is the XEP (Jabber protocol extension) specifically drafted to -solve this problem, while `forwarded_messages`_ uses +solve this problem, while `forward_messages`_ uses `stanza forwarding `_ expose_rid_and_sid @@ -1185,7 +1191,7 @@ browser tab functions as a separate chat client, with its own resource. This feature uses Stanza forwarding, see also `XEP 0297: Stanza Forwarding `_ -For an alternative approach, see also `message carbons`_. +For an alternative approach, see also `message_carbons`_. fullname -------- @@ -1283,7 +1289,9 @@ for some reason ``keepalive`` doesn't have cached session tokens anymore, you can listen for the ``noResumeableSession`` event and take that as a cue that you should again prebind in order to get valid session tokens. -Here is a code example:: +Here is a code example: + +.. code-block:: javascript converse.on('noResumeableSession', function () { $.getJSON('/prebind', function (data) { @@ -1399,7 +1407,7 @@ visible_toolbar_buttons Default: -:: +.. code-block:: javascript { call: false, @@ -1499,4 +1507,3 @@ The available options are: .. _`xmpp.org`: http://xmpp.org/xmpp-software/servers/ .. _`ejabberd`: http://www.ejabberd.im .. _`blogpost`: http://metajack.im/2008/10/03/getting-attached-to-strophe -.. _`example Django application`: https://github.com/metajack/strophejs/tree/master/examples/attach diff --git a/docs/source/theme/static/stylesheet.css_t b/docs/source/theme/static/stylesheet.css_t deleted file mode 100644 index 0d2b94165..000000000 --- a/docs/source/theme/static/stylesheet.css_t +++ /dev/null @@ -1,55 +0,0 @@ -@import url("default.css"); -@import url(pygment_trac.css); - -body { - margin: 1em; -} - -body, -header, -div.body, -div.document { - background-color: white; -} - -header { - margin: 1em; -} - -header h1#project_title { - color: black; - font-size: 44px; -} - -header h1#project_title a { - color: black; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - background-color: transparent; - border-bottom: 0; -} - -h1#project_title a { - color: white; -} - -h1 a { - color: #0069ba; -} - -ul { - margin-bottom: 5px; -} - -tt.literal { - color: #222; - background-color: #fff; - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; - font-size: 14px; -} diff --git a/docs/source/theme/theme.conf b/docs/source/theme/theme.conf deleted file mode 100644 index ca5ced5a9..000000000 --- a/docs/source/theme/theme.conf +++ /dev/null @@ -1,4 +0,0 @@ -[theme] -inherit = default -stylesheet = stylesheet.css -pygments_style = sphinx