Merge branch 'master' into converse-omemo
This commit is contained in:
commit
6785eff4a7
9
.babelrc
9
.babelrc
@ -1,9 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
"targets": {
|
||||
"browsers": ["last 2 versions", "safari >= 10", "IE >= 11"]
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
"extends": ["eslint:recommended", "plugin:lodash/canonical"],
|
||||
"globals": {
|
||||
"Promise": true,
|
||||
"converse": true,
|
||||
"define": true,
|
||||
"require": true,
|
||||
"sinon": true,
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,6 +13,8 @@
|
||||
.su?
|
||||
builds/*
|
||||
3rdparty/libsignal-protocol-javascript/
|
||||
*.map
|
||||
dist/converse-no-dependencies-es2015.js
|
||||
|
||||
analytics.js
|
||||
inverse-analytics.js
|
||||
|
@ -7,7 +7,11 @@
|
||||
- #161 XEP-0363: HTTP File Upload
|
||||
- #194 Include entity capabilities in outgoing presence stanzas
|
||||
- #337 API call to update a VCard
|
||||
- #968 Use nickname from VCard when joining a room
|
||||
- #1091 There's now only one CSS file for all view modes.
|
||||
- #1094 Show room members who aren't currently online
|
||||
- #1106 Support for Roster Versioning
|
||||
- #1081 Allow for shift-enter to insert newlines
|
||||
- It's now also possible to edit your VCard via the UI
|
||||
- Automatically grow/shrink input as text is entered/removed
|
||||
- MP4 and MP3 files when sent as XEP-0066 Out of Band Data, are now playable directly in chat
|
||||
@ -16,6 +20,8 @@
|
||||
- Add a checkbox to indicate whether a trusted device is being used or not.
|
||||
If the device is not trusted, sessionStorage is used and all user data is deleted from the browser cache upon logout.
|
||||
If the device is trusted, localStorage is used and user data is cached indefinitely.
|
||||
- Initial support for XEP-0357 Push Notifications, specifically registering an "App Server".
|
||||
- Add support for logging in via OAuth (see the [oauth_providers](https://conversejs.org/docs/html/configurations.html#oauth-providers) setting)
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
72
Makefile
72
Makefile
@ -8,15 +8,16 @@ CHROMIUM ?= ./node_modules/.bin/run-headless-chromium
|
||||
CLEANCSS ?= ./node_modules/clean-css-cli/bin/cleancss --skip-rebase
|
||||
ESLINT ?= ./node_modules/.bin/eslint
|
||||
HTTPSERVE ?= ./node_modules/.bin/http-server
|
||||
HTTPSERVE_PORT ?= 8000
|
||||
INKSCAPE ?= inkscape
|
||||
HTTPSERVE_PORT ?= 8000
|
||||
INKSCAPE ?= inkscape
|
||||
JSDOC ?= ./node_modules/.bin/jsdoc
|
||||
OXIPNG ?= oxipng
|
||||
OXIPNG ?= oxipng
|
||||
PAPER =
|
||||
PO2JSON ?= ./node_modules/.bin/po2json
|
||||
RJS ?= ./node_modules/.bin/r.js
|
||||
RJS ?= ./node_modules/.bin/r.js
|
||||
WEBPACK ?= ./node_modules/.bin/npx
|
||||
SASS ?= ./.bundle/bin/sass
|
||||
SED ?= sed
|
||||
SED ?= sed
|
||||
SPHINXBUILD ?= ./bin/sphinx-build
|
||||
SPHINXOPTS =
|
||||
UGLIFYJS ?= node_modules/.bin/uglifyjs
|
||||
@ -73,7 +74,7 @@ serve_bg: dev
|
||||
GETTEXT = xgettext --language="JavaScript" --keyword=__ --keyword=___ --from-code=UTF-8 --output=locale/converse.pot dist/converse-no-dependencies.js --package-name=Converse.js --copyright-holder="Jan-Carel Brand" --package-version=3.3.4 -c
|
||||
|
||||
.PHONY: pot
|
||||
pot: dist/converse-no-dependencies.js
|
||||
pot: dist/converse-no-dependencies-es2015.js
|
||||
$(GETTEXT) 2>&1 > /dev/null; exit $$?;
|
||||
|
||||
.PHONY: po
|
||||
@ -121,7 +122,7 @@ stamp-bundler: Gemfile
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf node_modules .bundle stamp-npm
|
||||
rm -rf node_modules .bundle stamp-npm stamp-bundler
|
||||
rm dist/*.min.js
|
||||
rm css/website.min.css
|
||||
rm css/converse.min.css
|
||||
@ -134,10 +135,7 @@ dev: stamp-bundler stamp-npm
|
||||
## Builds
|
||||
|
||||
.PHONY: css
|
||||
css: dev sass/*.scss css/converse.css css/converse.min.css css/website.css css/website.min.css css/inverse.css css/inverse.min.css css/fonts.css
|
||||
|
||||
css/inverse.css:: dev sass sass
|
||||
$(SASS) -I $(BOURBON) -I $(BOOTSTRAP) sass/inverse.scss css/inverse.css
|
||||
css: dev sass/*.scss css/converse.css css/converse.min.css css/website.css css/website.min.css css/fonts.css
|
||||
|
||||
css/converse.css:: dev sass
|
||||
$(SASS) -I $(BOURBON) -I $(BOOTSTRAP) sass/converse.scss css/converse.css
|
||||
@ -158,12 +156,7 @@ watch: dev
|
||||
|
||||
.PHONY: watchjs
|
||||
watchjs: dev
|
||||
$(BABEL) --source-maps --watch=./src --out-dir=./builds
|
||||
|
||||
transpile: dev src
|
||||
$(BABEL) --source-maps --out-dir=./builds ./src
|
||||
$(BABEL) --source-maps --out-dir=./builds ./node_modules/backbone.vdomview/backbone.vdomview.js
|
||||
touch transpile
|
||||
./node_modules/.bin/npx webpack --mode=development --watch
|
||||
|
||||
.PHONY: logo
|
||||
logo: logo/conversejs-transparent16.png \
|
||||
@ -186,37 +179,34 @@ logo/conversejs-filled%.png:: logo/conversejs-filled.svg
|
||||
$(OXIPNG) $@
|
||||
|
||||
BUILDS = dist/converse.js \
|
||||
dist/converse.min.js \
|
||||
dist/converse-headless.js \
|
||||
dist/converse-headless.min.js \
|
||||
dist/converse-no-dependencies.min.js \
|
||||
dist/converse-no-dependencies.js
|
||||
dist/converse.min.js \
|
||||
dist/converse-headless.js \
|
||||
dist/converse-headless.min.js \
|
||||
dist/converse-no-dependencies.min.js \
|
||||
dist/converse-no-dependencies.js \
|
||||
dist/converse-no-dependencies-es2015.js
|
||||
|
||||
# dist/converse-esnext.js \
|
||||
# dist/converse-esnext.min.js \
|
||||
dist/converse.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=development
|
||||
dist/converse.min.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=production
|
||||
dist/converse-headless.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=development --type=headless
|
||||
dist/converse-headless.min.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=production --type=headless
|
||||
dist/converse-no-dependencies.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=development --type=nodeps
|
||||
dist/converse-no-dependencies.min.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=production --type=nodeps
|
||||
dist/converse-no-dependencies-es2015.js: src webpack.config.js stamp-npm
|
||||
./node_modules/.bin/npx webpack --mode=development --type=nodeps --lang=es2015
|
||||
|
||||
dist/converse.js: transpile src stamp-npm
|
||||
$(RJS) -o src/build.js include=converse out=dist/converse.js optimize=none
|
||||
dist/converse.min.js: transpile src stamp-npm
|
||||
$(RJS) -o src/build.js include=converse out=dist/converse.min.js
|
||||
dist/converse-headless.js: transpile src stamp-npm
|
||||
$(RJS) -o src/build.js paths.converse=src/headless include=converse out=dist/converse-headless.js optimize=none
|
||||
dist/converse-headless.min.js: transpile src stamp-npm
|
||||
$(RJS) -o src/build.js paths.converse=src/headless include=converse out=dist/converse-headless.min.js
|
||||
dist/converse-esnext.js: src stamp-npm
|
||||
$(RJS) -o src/build-esnext.js include=converse out=dist/converse-esnext.js optimize=none
|
||||
dist/converse-esnext.min.js: src stamp-npm
|
||||
$(RJS) -o src/build-esnext.js include=converse out=dist/converse-esnext.min.js
|
||||
dist/converse-no-dependencies.js: transpile src stamp-npm
|
||||
$(RJS) -o src/build-no-dependencies.js optimize=none out=dist/converse-no-dependencies.js
|
||||
dist/converse-no-dependencies.min.js: transpile src stamp-npm
|
||||
$(RJS) -o src/build-no-dependencies.js out=dist/converse-no-dependencies.min.js
|
||||
|
||||
.PHONY: dist
|
||||
dist:: build
|
||||
|
||||
.PHONY: build
|
||||
build:: dev css transpile $(BUILDS)
|
||||
build:: dev css $(BUILDS)
|
||||
|
||||
########################################################################
|
||||
## Tests
|
||||
|
210
bootstrap.py
210
bootstrap.py
@ -1,210 +0,0 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
__version__ = '2015-07-01'
|
||||
# See zc.buildout's changelog if this version is up to date.
|
||||
|
||||
tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
|
||||
|
||||
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 --find-links to point to local resources, you can keep
|
||||
this script from going over the network.
|
||||
'''
|
||||
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("--version",
|
||||
action="store_true", default=False,
|
||||
help=("Return bootstrap.py version."))
|
||||
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", "--config-file",
|
||||
help=("Specify the path to the buildout configuration "
|
||||
"file to be used."))
|
||||
parser.add_option("-f", "--find-links",
|
||||
help=("Specify a URL to search for buildout releases"))
|
||||
parser.add_option("--allow-site-packages",
|
||||
action="store_true", default=False,
|
||||
help=("Let bootstrap.py use existing site packages"))
|
||||
parser.add_option("--buildout-version",
|
||||
help="Use a specific zc.buildout version")
|
||||
parser.add_option("--setuptools-version",
|
||||
help="Use a specific setuptools version")
|
||||
parser.add_option("--setuptools-to-dir",
|
||||
help=("Allow for re-use of existing directory of "
|
||||
"setuptools versions"))
|
||||
|
||||
options, args = parser.parse_args()
|
||||
if options.version:
|
||||
print("bootstrap.py version %s" % __version__)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
######################################################################
|
||||
# load/install setuptools
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
|
||||
ez = {}
|
||||
if os.path.exists('ez_setup.py'):
|
||||
exec(open('ez_setup.py').read(), ez)
|
||||
else:
|
||||
exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
|
||||
|
||||
if not options.allow_site_packages:
|
||||
# ez_setup imports site, which adds site packages
|
||||
# this will remove them from the path to ensure that incompatible versions
|
||||
# of setuptools are not in the path
|
||||
import site
|
||||
# inside a virtualenv, there is no 'getsitepackages'.
|
||||
# We can't remove these reliably
|
||||
if hasattr(site, 'getsitepackages'):
|
||||
for sitepackage_path in site.getsitepackages():
|
||||
# Strip all site-packages directories from sys.path that
|
||||
# are not sys.prefix; this is because on Windows
|
||||
# sys.prefix is a site-package directory.
|
||||
if sitepackage_path != sys.prefix:
|
||||
sys.path[:] = [x for x in sys.path
|
||||
if sitepackage_path not in x]
|
||||
|
||||
setup_args = dict(to_dir=tmpeggs, download_delay=0)
|
||||
|
||||
if options.setuptools_version is not None:
|
||||
setup_args['version'] = options.setuptools_version
|
||||
if options.setuptools_to_dir is not None:
|
||||
setup_args['to_dir'] = options.setuptools_to_dir
|
||||
|
||||
ez['use_setuptools'](**setup_args)
|
||||
import setuptools
|
||||
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)
|
||||
|
||||
######################################################################
|
||||
# Install buildout
|
||||
|
||||
ws = pkg_resources.working_set
|
||||
|
||||
setuptools_path = ws.find(
|
||||
pkg_resources.Requirement.parse('setuptools')).location
|
||||
|
||||
# Fix sys.path here as easy_install.pth added before PYTHONPATH
|
||||
cmd = [sys.executable, '-c',
|
||||
'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
|
||||
'from setuptools.command.easy_install import main; main()',
|
||||
'-mZqNxd', tmpeggs]
|
||||
|
||||
find_links = os.environ.get(
|
||||
'bootstrap-testing-find-links',
|
||||
options.find_links or
|
||||
('http://downloads.buildout.org/'
|
||||
if options.accept_buildout_test_releases else None)
|
||||
)
|
||||
if find_links:
|
||||
cmd.extend(['-f', find_links])
|
||||
|
||||
requirement = 'zc.buildout'
|
||||
version = options.buildout_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):
|
||||
try:
|
||||
return not parsed_version.is_prerelease
|
||||
except AttributeError:
|
||||
# Older setuptools
|
||||
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=[setuptools_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)
|
||||
|
||||
import subprocess
|
||||
if subprocess.call(cmd) != 0:
|
||||
raise Exception(
|
||||
"Failed to execute command:\n%s" % repr(cmd)[1:-1])
|
||||
|
||||
######################################################################
|
||||
# Import and run buildout
|
||||
|
||||
ws.add_entry(tmpeggs)
|
||||
ws.require(requirement)
|
||||
import zc.buildout.buildout
|
||||
|
||||
if not [a for a in args if '=' not in a]:
|
||||
args.append('bootstrap')
|
||||
|
||||
# if -c was provided, we push it back into args for buildout' main function
|
||||
if options.config_file is not None:
|
||||
args[0:0] = ['-c', options.config_file]
|
||||
|
||||
zc.buildout.buildout.main(args)
|
||||
shutil.rmtree(tmpeggs)
|
10
buildout.cfg
10
buildout.cfg
@ -11,12 +11,4 @@ eggs =
|
||||
sphinx-bootstrap-theme
|
||||
|
||||
[versions]
|
||||
docutils = 0.13.1
|
||||
Jinja2 = 2.9.5
|
||||
MarkupSafe = 0.23
|
||||
Pygments = 2.2.0
|
||||
six = 1.10.0
|
||||
setuptools = 28.6.1
|
||||
Sphinx = 1.5.2
|
||||
z3c.recipe.egg = 2.0.3
|
||||
zc.buildout = 2.5.3
|
||||
Sphinx = 1.7.5
|
||||
|
@ -1,3 +0,0 @@
|
||||
This directory exists as a location for intermediate files generated by the
|
||||
Babel compiler, before they're bundled into distribution bundles in the
|
||||
`./dist/` directory.
|
672
css/converse.css
672
css/converse.css
File diff suppressed because it is too large
Load Diff
26
css/fullpage.css
Normal file
26
css/fullpage.css
Normal file
@ -0,0 +1,26 @@
|
||||
body {
|
||||
font-family: "Lora", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #ffffff;
|
||||
background-color: #578EA9;
|
||||
}
|
||||
.brand-heading {
|
||||
font-size: 600%;
|
||||
margin-left: -10%;
|
||||
}
|
||||
.icon-conversejs {
|
||||
font-size: 88%;
|
||||
}
|
||||
.brand-heading div.content {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: fixed;
|
||||
background-color: #578EA9;
|
||||
}
|
||||
.brand-heading div.content .inner-content {
|
||||
text-align: center;
|
||||
padding: 7%;
|
||||
}
|
||||
p.no-chats {
|
||||
padding-right: 10%;
|
||||
font-size: 120%;
|
||||
}
|
8908
css/inverse.css
8908
css/inverse.css
File diff suppressed because it is too large
Load Diff
@ -117,6 +117,14 @@ a:hover, a:focus {
|
||||
.outro {
|
||||
background: url("images/bgtr.svg") top right no-repeat, url("images/bgbl.svg") bottom left no-repeat, url("images/overlay.png"), linear-gradient(45deg, #384955, #655361, #85505f); }
|
||||
|
||||
section h2 {
|
||||
color: #E7A151; }
|
||||
section h3 {
|
||||
color: #89B7CD; }
|
||||
section h4 {
|
||||
color: #5CBC86;
|
||||
font-size: 1.5em; }
|
||||
|
||||
.brand-heading {
|
||||
font-family: Futura,Helvetica,Trebuchet MS,Arial,sans-serif;
|
||||
font-weight: normal;
|
||||
@ -181,7 +189,17 @@ a:hover, a:focus {
|
||||
-moz-animation-timing-function: linear; }
|
||||
|
||||
.content-section {
|
||||
padding-top: 100px; }
|
||||
padding-top: 100px;
|
||||
padding-top: 100px;
|
||||
min-height: 100vh; }
|
||||
.content-section .privacy-policy {
|
||||
padding-top: 2em; }
|
||||
.content-section .privacy-policy h4 {
|
||||
padding-top: 1.5em; }
|
||||
.content-section .privacy-policy p {
|
||||
font-size: 1.2em;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 1em; }
|
||||
|
||||
.donate-section {
|
||||
width: 100%;
|
||||
@ -194,7 +212,6 @@ a:hover, a:focus {
|
||||
|
||||
@media (min-width: 767px) {
|
||||
.content-section {
|
||||
padding-top: 150px;
|
||||
padding-bottom: 50px; }
|
||||
|
||||
.donate-section {
|
||||
@ -304,6 +321,8 @@ ul.features {
|
||||
clear: both;
|
||||
font-size: 1.4em;
|
||||
padding: 2em 0 6em 0; }
|
||||
.sponsors ul {
|
||||
padding: 0; }
|
||||
|
||||
.sponsors h2 {
|
||||
text-align: center; }
|
||||
|
46
dev.html
46
dev.html
@ -9,35 +9,33 @@
|
||||
<meta name="author" content="JC Brand" />
|
||||
<meta name="keywords" content="xmpp chat webchat converse.js" />
|
||||
<link rel="shortcut icon" type="image/ico" href="css/images/favicon.ico"/>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/inverse.css" />
|
||||
<script src="node_modules/requirejs/require.js"></script>
|
||||
<script src="src/config.js"></script>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/fullpage.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/converse.css" />
|
||||
<script src="dist/converse.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="reset">
|
||||
|
||||
<script>
|
||||
require(['converse', 'converse-omemo'], function (converse) {
|
||||
converse.initialize({
|
||||
auto_away: 300,
|
||||
i18n: 'en',
|
||||
// auto_join_rooms: [
|
||||
// 'discuss@conference.conversejs.org',
|
||||
// 'prosody@conference.prosody.im',
|
||||
// 'jdev@conference.jabber.org'
|
||||
// ],
|
||||
// websocket_url: 'ws://chat.example.org:5280/xmpp-websocket',
|
||||
view_mode: 'fullscreen',
|
||||
archived_messages_page_size: '500',
|
||||
allow_public_bookmarks: true,
|
||||
notify_all_room_messages: [
|
||||
'discuss@conference.conversejs.org'
|
||||
],
|
||||
// bosh_service_url: 'http://chat.example.org:5280/http-bind/',
|
||||
bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
|
||||
message_archiving: 'always',
|
||||
debug: true
|
||||
});
|
||||
converse.initialize({
|
||||
auto_away: 300,
|
||||
i18n: 'en',
|
||||
// auto_join_rooms: [
|
||||
// 'discuss@conference.conversejs.org',
|
||||
// 'prosody@conference.prosody.im',
|
||||
// 'jdev@conference.jabber.org'
|
||||
// ],
|
||||
// websocket_url: 'ws://chat.example.org:5280/xmpp-websocket',
|
||||
view_mode: 'fullscreen',
|
||||
archived_messages_page_size: '500',
|
||||
allow_public_bookmarks: true,
|
||||
notify_all_room_messages: [
|
||||
'discuss@conference.conversejs.org'
|
||||
],
|
||||
// bosh_service_url: 'http://chat.example.org:5280/http-bind/',
|
||||
bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
|
||||
message_archiving: 'always',
|
||||
debug: true
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
73071
dist/converse-no-dependencies.js
vendored
73071
dist/converse-no-dependencies.js
vendored
File diff suppressed because one or more lines are too long
103805
dist/converse.js
vendored
103805
dist/converse.js
vendored
File diff suppressed because one or more lines are too long
@ -7,10 +7,10 @@ Configuration
|
||||
=============
|
||||
|
||||
The included minified JavaScript 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
|
||||
you'll want to configure *Converse* to suit your needs before you deploy it
|
||||
on your website.
|
||||
|
||||
*Converse.js* is passed its configuration settings when you call its *initialize* method.
|
||||
*Converse* 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.
|
||||
@ -18,7 +18,7 @@ an example of how this is done, please see the bottom of the *./index.html* page
|
||||
Please refer to the `Configuration settings`_ section below for info on
|
||||
all the available configuration settings.
|
||||
|
||||
After you have configured *Converse.js*, you'll have to regenerate the minified
|
||||
After you have configured *Converse*, you'll have to regenerate the minified
|
||||
JavaScript file so that it will include the new settings. Please refer to the
|
||||
:ref:`minification` section for more info on how to do this.
|
||||
|
||||
@ -83,7 +83,7 @@ requiring them to log in manually.
|
||||
When a BOSH session is initially created, you'll receive three tokens.
|
||||
A JID (jabber ID), SID (session ID) and RID (Request ID).
|
||||
|
||||
Converse.js needs these tokens in order to attach to that same session.
|
||||
Converse needs these tokens in order to attach to that same session.
|
||||
|
||||
There are two complementary configuration settings to ``prebind``.
|
||||
They are :ref:`keepalive` and `prebind_url`_.
|
||||
@ -200,7 +200,7 @@ allow_public_bookmarks
|
||||
Some XMPP servers don't support private PEP/PubSub nodes, as required for
|
||||
private bookmarks and outlined in `XEP-0223 <https://xmpp.org/extensions/xep-0223.html>`_.
|
||||
|
||||
Even though Converse.js asks for the bookmarks to be kept private (via the
|
||||
Even though Converse asks for the bookmarks to be kept private (via the
|
||||
`<publish-options>` XML node), the server simply ignores the privacy settings
|
||||
and publishes the node contents under the default privacy setting, which makes
|
||||
the information available to all roster contacts.
|
||||
@ -376,13 +376,13 @@ For example::
|
||||
blacklisted_plugins
|
||||
-------------------
|
||||
|
||||
* Default: ``[]`` (``['converse-minimize', 'converse-dragresize']`` for inVerse)
|
||||
* Default: ``[]``
|
||||
|
||||
A list of plugin names that are blacklisted and will therefore not be
|
||||
initialized once ``converse.initialize`` is called, even if the same plugin is
|
||||
whitelisted.
|
||||
|
||||
From Converse.js 3.0 onwards most of the API is available only to plugins and
|
||||
From Converse 3.0 onwards most of the API is available only to plugins and
|
||||
all plugins need to be whitelisted first.
|
||||
|
||||
The usecase for blacklisting is generally to disable removed core plugins
|
||||
@ -495,7 +495,7 @@ connection_options
|
||||
* Default: ``{}``
|
||||
* Type: Object
|
||||
|
||||
Converse.js relies on `Strophe.js <http://strophe.im>`_ to establish and
|
||||
Converse relies on `Strophe.js <http://strophe.im>`_ to establish and
|
||||
maintain a connection to the XMPP server.
|
||||
|
||||
This option allows you to pass a map of configuration options to be passed into
|
||||
@ -672,7 +672,7 @@ geouri_regex
|
||||
Regular expression used to extract geo coordinates from links to openstreetmap.
|
||||
|
||||
geouri_replacement
|
||||
----------------
|
||||
------------------
|
||||
|
||||
* Default: ``'https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2'``
|
||||
|
||||
@ -698,7 +698,7 @@ If set to ``true``, then don't show offline users.
|
||||
hide_open_bookmarks
|
||||
-------------------
|
||||
|
||||
* Default: ``false`` (``true`` for inVerse).
|
||||
* Default: ``false`` (``true`` when the ``view_mode`` is set to ``fullscreen``).
|
||||
|
||||
This setting applies to the ``converse-bookmarks`` plugin and specfically the
|
||||
list of bookmarks shown in the ``Rooms`` tab of the control box.
|
||||
@ -711,48 +711,6 @@ Makes sense to set this to ``true`` when also using the non-core
|
||||
``converse-roomslist`` plugin, which shows a list of currently open (i.e.
|
||||
"joined") rooms.
|
||||
|
||||
include_offline_state
|
||||
---------------------
|
||||
|
||||
* Default: `false`
|
||||
|
||||
Originally, converse.js included an `offline` state which the user could
|
||||
choose (along with `online`, `busy` and `away`).
|
||||
|
||||
Eventually it was however decided to remove this state, since the `offline`
|
||||
state doesn't propagate across tabs like the others do.
|
||||
|
||||
What's meant by "propagate across tabs", is that when you set the state to
|
||||
`offline` in one tab, and you have instances of converse.js open in other tabs
|
||||
in your browser, then those instances will not have their states changed to
|
||||
`offline` as well. For the other statees the change is however propagated.
|
||||
|
||||
The reason for this is that according to the XMPP spec, there is no `offline`
|
||||
state. The only defined states are:
|
||||
|
||||
* away -- The entity or resource is temporarily away.
|
||||
* chat -- The entity or resource is actively interested in chattiIng.
|
||||
* dnd -- The entity or resource is busy (dnd = "Do Not Disturb").
|
||||
* xa -- The entity or resource is away for an extended period (xa = "eXtended Away").
|
||||
|
||||
Read the `relevant section in the XMPP spec <https://xmpp.org/rfcs/rfc6121.html#presence-syntax-children-show>`_
|
||||
for more info.
|
||||
|
||||
What used to happen in converse.js when the `offline` state was chosen, is
|
||||
that a presence stanza with a `type` of `unavailable` was sent out.
|
||||
|
||||
This is actually exactly what happens when you log out of converse.js as well,
|
||||
with the notable exception that in the `offline` state, the connection is not
|
||||
terminated. So you can at any time change your state to something else and
|
||||
start chatting again.
|
||||
|
||||
This might be useful to people, however the fact that the `offline` state
|
||||
doesn't propagate across tabs means that the user experience is inconsistent,
|
||||
confusing and appears "broken".
|
||||
|
||||
If you are however aware of this issue and still want to allow the `offline`
|
||||
state, then you can set this option to `true` to enable it.
|
||||
|
||||
.. _`i18n`:
|
||||
|
||||
i18n
|
||||
@ -767,7 +725,7 @@ The translations for that locale must be available in JSON format at the
|
||||
|
||||
If an explicit locale is specified via the ``i18n`` setting and the
|
||||
translations for that locale are not found at the `locales_url``, then
|
||||
then Converse.js will fall back to trying to determine the browser's language
|
||||
then Converse will fall back to trying to determine the browser's language
|
||||
and fetching those translations, or if that fails the default English texts
|
||||
will be used.
|
||||
|
||||
@ -789,7 +747,7 @@ keepalive
|
||||
|
||||
* Default: ``true``
|
||||
|
||||
Determines whether Converse.js will maintain the chat session across page
|
||||
Determines whether Converse will maintain the chat session across page
|
||||
loads.
|
||||
|
||||
This setting should also be used in conjunction with ``authentication`` set to `prebind`_.
|
||||
@ -827,7 +785,7 @@ locales
|
||||
'ru', 'uk', 'zh'
|
||||
]
|
||||
|
||||
This setting restricts the locales that are supported by Converse.js and
|
||||
This setting restricts the locales that are supported by Converse and
|
||||
therefore what may be given as value for the :ref:`i18n` option.
|
||||
|
||||
Any other locales will be ignored.
|
||||
@ -842,7 +800,7 @@ locales_url
|
||||
|
||||
* Default: ``/locale/{{{locale}}}/LC_MESSAGES/converse.json``,
|
||||
|
||||
The URL from where Converse.js should fetch translation JSON.
|
||||
The URL from where Converse should fetch translation JSON.
|
||||
|
||||
The three curly braces ``{{{ }}}`` are
|
||||
`Mustache <https://github.com/janl/mustache.js#readme>`_-style
|
||||
@ -854,7 +812,7 @@ The variable being interpolated via the curly braces is ``locale``, which is
|
||||
the value passed in to the `i18n`_ setting, or the browser's locale or the
|
||||
default local or `en` (resolved in that order).
|
||||
|
||||
From version 3.3.0, Converse.js no longer bundles all translations into its
|
||||
From version 3.3.0, Converse no longer bundles all translations into its
|
||||
final build file. Instead, only the relevant translations are fetched at
|
||||
runtime.
|
||||
|
||||
@ -995,7 +953,7 @@ muc_show_join_leave
|
||||
|
||||
* Default; ``true``
|
||||
|
||||
Determines whether Converse.js will show info messages inside a chatroom
|
||||
Determines whether Converse will show info messages inside a chatroom
|
||||
whenever a user joins or leaves it.
|
||||
|
||||
nickname
|
||||
@ -1028,6 +986,39 @@ This option specifies which icon is shown in HTML5 notifications, as provided
|
||||
by the ``src/converse-notification.js`` plugin.
|
||||
|
||||
|
||||
oauth_providers
|
||||
---------------
|
||||
|
||||
* Default: ``[]``
|
||||
|
||||
Allows you to specify a list of OAuth providers that the user may use to log in
|
||||
with.
|
||||
|
||||
.. note::
|
||||
Your XMPP server will have to support Oauth logins
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
converse.initialize({
|
||||
oauth_providers: {
|
||||
'github': {
|
||||
'client_id': '1338d9f7ff52b1309b29',
|
||||
'host': 'chat.example.org',
|
||||
'class': 'fa-github-alt',
|
||||
'id': 'github',
|
||||
'name': 'Github'
|
||||
},
|
||||
'twitter': {
|
||||
'client_id': '0332d98cff83b1999b22',
|
||||
'host': 'chat.example.org',
|
||||
'class': 'fa-twitter',
|
||||
'id': 'twitter',
|
||||
'name': 'Twitter'
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
ping_interval
|
||||
-------------
|
||||
|
||||
@ -1049,7 +1040,7 @@ play_sounds
|
||||
Plays a notification sound when you receive a personal message or when your
|
||||
nickname is mentioned in a chatroom.
|
||||
|
||||
Inside the ``./sounds`` directory of the Converse.js repo you'll see MP3 and Ogg
|
||||
Inside the ``./sounds`` directory of the Converse repo you'll see MP3 and Ogg
|
||||
formatted sound files. We need both, because neither format is supported by all browsers.
|
||||
|
||||
You can set the URL where the sound files are hosted with the `sounds_path`_
|
||||
@ -1089,12 +1080,12 @@ priority
|
||||
* Type: Number
|
||||
|
||||
Determines the priority used for presence stanzas sent out from this resource
|
||||
(i.e. this instance of Converse.js).
|
||||
(i.e. this instance of Converse).
|
||||
|
||||
The priority of a given XMPP chat client determines the importance of its presence
|
||||
stanzas in relation to stanzas received from other clients of the same user.
|
||||
|
||||
In Converse.js, the indicated chat status of a roster contact will be taken from the
|
||||
In Converse, the indicated chat status of a roster contact will be taken from the
|
||||
presence stanza (and associated resource) with the highest priority.
|
||||
|
||||
If multiple resources have the same top priority, then the chat status will be
|
||||
@ -1110,6 +1101,39 @@ providers_link
|
||||
The hyperlink on the registration form which points to a directory of public
|
||||
XMPP servers.
|
||||
|
||||
push_app_servers
|
||||
----------------
|
||||
|
||||
* Default: ``[]``
|
||||
|
||||
This option lets you enable or disable so-called push notification "App Servers"
|
||||
(as per `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
|
||||
|
||||
For each "App Server" an object needs to be passed in. When enabling, you need
|
||||
to specify ``jid`` and ``node`` values. You can also provide a
|
||||
``secret``, if required by your App Server.
|
||||
|
||||
When disabling, you need to specify at least a ``jid`` and set ``disabled`` to
|
||||
``true``. This will disable notifications to all pubsub nodes on that "App
|
||||
Server". If you want to disable only a particular node, then specify a ``node``
|
||||
value as well.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
converse.initialize({
|
||||
'push_app_servers': [{
|
||||
'jid': 'push-4@client.example',
|
||||
'node': 'yxs32uqsflafdk3iuqo',
|
||||
'disable': true
|
||||
}, {
|
||||
'jid': 'push-5@client.example',
|
||||
'node': 'yxs32uqsflafdk3iuqo',
|
||||
}]
|
||||
});
|
||||
|
||||
root
|
||||
----
|
||||
|
||||
@ -1150,7 +1174,7 @@ 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
|
||||
Converse can only show users and groups that were previously configured
|
||||
elsewhere.
|
||||
|
||||
show_chatstate_notifications
|
||||
@ -1163,7 +1187,7 @@ Specifies whether chat state (online, dnd, away) HTML5 desktop notifications sho
|
||||
show_controlbox_by_default
|
||||
--------------------------
|
||||
|
||||
* Default: ``false`` (``true`` for inVerse)
|
||||
* Default: ``false`` (``true`` when the ``view_mode`` is set to ``fullscreen``)
|
||||
|
||||
The "controlbox" refers to the special chatbox containing your contacts roster,
|
||||
status widget, chatrooms and other controls.
|
||||
@ -1280,7 +1304,7 @@ See also `trusted`_.
|
||||
sticky_controlbox
|
||||
-----------------
|
||||
|
||||
* Default: ``false`` (``true`` for inVerse).
|
||||
* Default: ``false`` (``true`` when the ``view_mode`` is set to ``fullscreen``).
|
||||
|
||||
If set to ``true``, the control box (which includes the login, registration,
|
||||
contacts and rooms tabs) will not be closeable. It won't have a close button at
|
||||
@ -1304,10 +1328,10 @@ loaded), then an error will be raised.
|
||||
|
||||
Otherwise a message will simply be logged and the override instruction ignored.
|
||||
|
||||
The Converse.js plugins architecture can have an :ref:`dependencies`
|
||||
The Converse plugins architecture can have an :ref:`dependencies`
|
||||
plugin attribute. This enables you to specify an array of other plugins which
|
||||
this one depends on.
|
||||
Converse.js (more specifically, `pluggable.js <https://jcbrand.github.io/pluggable.js/>`_)
|
||||
Converse (more specifically, `pluggable.js <https://jcbrand.github.io/pluggable.js/>`_)
|
||||
will first load these dependencies before executing the plugin's overrides and
|
||||
calling its ``initialize`` method.
|
||||
|
||||
@ -1344,7 +1368,7 @@ This setting determines whether the default value of the "This is a trusted devi
|
||||
When the current device is not trusted, then localStorage and sessionStorage
|
||||
will be cleared when the user logs out, thereby removing all cached data.
|
||||
|
||||
Clearing the cache in this way makes Converse.js much slower when the user logs
|
||||
Clearing the cache in this way makes Converse much slower when the user logs
|
||||
in again, because all data needs to be fetch anew.
|
||||
|
||||
See also `storage`_.
|
||||
@ -1365,7 +1389,7 @@ use_otr_by_default
|
||||
|
||||
* Default: ``false``
|
||||
|
||||
If set to ``true``, Converse.js will automatically try to initiate an OTR (off-the-record)
|
||||
If set to ``true``, Converse will automatically try to initiate an OTR (off-the-record)
|
||||
encrypted chat session every time you open a chatbox.
|
||||
|
||||
visible_toolbar_buttons
|
||||
@ -1424,7 +1448,7 @@ support.
|
||||
configuration setting).
|
||||
|
||||
.. note::
|
||||
Converse.js does not yet support "keepalive" with websockets.
|
||||
Converse does not yet support "keepalive" with websockets.
|
||||
|
||||
.. _`view_mode`:
|
||||
|
||||
@ -1468,6 +1492,9 @@ Since version 3.3.0, the ``inverse.js`` and ``converse-mobile.js`` builds no
|
||||
longer exist. Instead the standard ``converse.js`` build is used, together with
|
||||
the appropriate ``view_mode`` value.
|
||||
|
||||
Since verseion 4.0.0, there is now also only one CSS file to be used for all
|
||||
the different view modes, ``converse.css``.
|
||||
|
||||
The ``converse-muc-embedded.js`` build is still kept, because it's smaller than
|
||||
``converse.js`` due to unused code being removed. It doesn't however contain
|
||||
any new code, so the full ``converse.js`` build could be used instead, as long
|
||||
@ -1476,19 +1503,6 @@ as ``view_mode`` is set to ``embedded``.
|
||||
Furthermore, it's no longer necessary to whitelist or blacklist any plugins
|
||||
when switching view modes.
|
||||
|
||||
.. note::
|
||||
Although the ``view_mode`` setting has removed the need for different
|
||||
JavaScript builds, you'll still need to use different CSS files depending
|
||||
on the view mode.
|
||||
|
||||
* For ``embedded`` you need to use ``./css/converse-muc-embedded.css``
|
||||
* For ``fullscreen`` you need ``./css/inverse.css``
|
||||
* For ``mobile`` you need to use both ``./css/converse.css`` and ``./css/mobile.css``
|
||||
* For ``overlayed`` this is ``./css/converse.css``
|
||||
|
||||
Hopefully in a future release the CSS files will be combined and you'll
|
||||
only need ``converse.css``
|
||||
|
||||
|
||||
.. _`whitelisted_plugins`:
|
||||
|
||||
@ -1500,7 +1514,7 @@ whitelisted_plugins
|
||||
A list of plugin names that are whitelisted and will therefore be
|
||||
initialized once ``converse.initialize`` is called.
|
||||
|
||||
From Converse.js 3.0 onwards most of the API is available only to plugins and
|
||||
From Converse 3.0 onwards most of the API is available only to plugins and
|
||||
all plugins need to be whitelisted first.
|
||||
|
||||
This is done to prevent malicious scripts from using the API to trick users or
|
||||
|
@ -7,7 +7,7 @@
|
||||
Events and promises
|
||||
===================
|
||||
|
||||
Converse.js and its plugins emit various events which you can listen to via the
|
||||
Converse and its plugins emit various events which you can listen to via the
|
||||
:ref:`listen-grouping`.
|
||||
|
||||
Some of these events are also available as `ES2015 Promises <http://es6-features.org/#PromiseUsage>`_,
|
||||
@ -294,24 +294,6 @@ Also available as an `ES2015 Promise <http://es6-features.org/#PromiseUsage>`_:
|
||||
// Your code here...
|
||||
});
|
||||
|
||||
reconnecting
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Fired once converse.js has determined that it will attempt to reconnect (and
|
||||
each subsequent time, if it attempts repeatedly).
|
||||
|
||||
reconnected
|
||||
~~~~~~~~~~~
|
||||
|
||||
After the connection has dropped and converse.js has reconnected.
|
||||
Any Strophe stanza handlers (as registered via `converse.listen.stanza`) will
|
||||
have to be registered anew.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
_converse.api.listen.on('reconnected', function () { ... });
|
||||
|
||||
|
||||
privateChatsAutoJoined
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -330,6 +312,33 @@ Also available as an `ES2015 Promise <http://es6-features.org/#PromiseUsage>`_.
|
||||
// Your code here...
|
||||
});
|
||||
|
||||
|
||||
reconnecting
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Fired once converse.js has determined that it will attempt to reconnect (and
|
||||
each subsequent time, if it attempts repeatedly).
|
||||
|
||||
reconnected
|
||||
~~~~~~~~~~~
|
||||
|
||||
After the connection has dropped and converse.js has reconnected.
|
||||
Any Strophe stanza handlers (as registered via `converse.listen.stanza`) will
|
||||
have to be registered anew.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
_converse.api.listen.on('reconnected', function () { ... });
|
||||
|
||||
registeredGlobalEventHandlers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called once Converse has registered its global event handlers (for events such
|
||||
as window resize or unload).
|
||||
|
||||
Plugins can listen to this event as cue to register their own global event
|
||||
handlers.
|
||||
|
||||
roomsAutoJoined
|
||||
---------------
|
||||
|
||||
@ -466,6 +475,14 @@ Similar to `rosterInitialized`, but instead pertaining to reconnection. This
|
||||
event indicates that the Backbone collections representing the roster and its
|
||||
groups are now again available after converse.js has reconnected.
|
||||
|
||||
serviceDiscovered
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
When converse.js has learned of a service provided by the XMPP server. See XEP-0030.
|
||||
|
||||
``_converse.api.listen.on('serviceDiscovered', function (service) { ... });``
|
||||
|
||||
|
||||
.. _`statusInitialized`:
|
||||
|
||||
statusInitialized
|
||||
@ -497,12 +514,12 @@ When own custom status message has changed.
|
||||
|
||||
``_converse.api.listen.on('statusMessageChanged', function (message) { ... });``
|
||||
|
||||
serviceDiscovered
|
||||
~~~~~~~~~~~~~~~~~
|
||||
streamFeaturesAdded
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When converse.js has learned of a service provided by the XMPP server. See XEP-0030.
|
||||
|
||||
``_converse.api.listen.on('serviceDiscovered', function (service) { ... });``
|
||||
Emitted as soon as Converse has processed the stream features as advertised by
|
||||
the server. If you want to check whether a stream feature is supported before
|
||||
proceeding, then you'll first want to wait for this event.
|
||||
|
||||
windowStateChanged
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
@ -19,7 +19,7 @@ and a private chat with a URL fragment such as
|
||||
Off-the-record encryption
|
||||
=========================
|
||||
|
||||
Converse.js supports `Off-the-record (OTR) <https://otr.cypherpunks.ca/>`_
|
||||
Converse supports `Off-the-record (OTR) <https://otr.cypherpunks.ca/>`_
|
||||
encrypted messaging.
|
||||
|
||||
The OTR protocol not only **encrypts your messages**, it provides ways to
|
||||
@ -38,17 +38,17 @@ secure crypto.
|
||||
For harsh but fairly valid criticism of JavaScript cryptography, read:
|
||||
`JavaScript Cryptography Considered Harmful <http://www.matasano.com/articles/javascript-cryptography/>`_.
|
||||
|
||||
To get an idea on how this applies to OTR support in Converse.js, please read
|
||||
To get an idea on how this applies to OTR support in Converse, please read
|
||||
`my thoughts on it <https://opkode.com/media/blog/2013/11/11/conversejs-otr-support>`_.
|
||||
|
||||
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
|
||||
Converse in order to avoid most eavesdroppers, if you need serious
|
||||
communications privacy, then you're much better off using native software.
|
||||
|
||||
Notifications
|
||||
=============
|
||||
|
||||
From version 0.8.1 Converse.js can play a sound notification when you receive a
|
||||
From version 0.8.1 Converse can play a sound notification when you receive a
|
||||
message.
|
||||
|
||||
For more info, refer to the :ref:`play-sounds` configuration setting.
|
||||
@ -61,13 +61,10 @@ For more info, refer to the :ref:`show-desktop-notifications` configuration sett
|
||||
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.
|
||||
Converse is translated into multiple languages. Translations are supplied in
|
||||
JSON format and are loaded on demand. Converse will expect to find the
|
||||
translations in the ``/locales`` path of your site. This can be changed via the
|
||||
:ref:`locales-url` configuration setting.
|
||||
|
||||
Moderating chatrooms
|
||||
====================
|
||||
@ -103,7 +100,7 @@ Here are the different commands that may be used to moderate a chatroom:
|
||||
Passwordless login with client certificates
|
||||
===========================================
|
||||
|
||||
Converse.js supports the SASL-EXTERNAL authentication mechanism, which can be
|
||||
Converse supports the SASL-EXTERNAL authentication mechanism, which can be
|
||||
used together with x509 client certificates to enable passwordless login or
|
||||
even 2-factor authentication.
|
||||
|
||||
|
@ -34,8 +34,6 @@ via the *script* and *link* tags:
|
||||
<script src="https://cdn.conversejs.org/dist/converse.min.js" charset="utf-8"></script>
|
||||
|
||||
|
||||
.. note:: For the fullscreen :ref:`view_mode` version of converse.js, replace ``converse.min.css`` with ``inverse.min.css``.
|
||||
|
||||
.. note:: Instead of always loading the latest version of Converse.js via the
|
||||
CDN, it's generally better to load a specific version (preferably the
|
||||
latest one), to avoid breakage when new backwards-incompatible versions are
|
||||
@ -111,19 +109,13 @@ split up into two parts, with the UI part dropped for this build.
|
||||
Fullscreen version
|
||||
------------------
|
||||
|
||||
Converse.js also comes in a fullscreen version (often referred to as Inverse).
|
||||
Converse.js also comes in a fullscreen version.
|
||||
A hosted version is available online at `inverse.chat <https://inverse.chat>`_.
|
||||
|
||||
Originally this version was available as a separate build file, but
|
||||
as of version 4.0.0 and higher, the difference between the "overlay" and the
|
||||
"fullscreen" versions of converse.js is simply a matter of configuring the
|
||||
:ref:`view_mode` and including the right CSS file.
|
||||
|
||||
For the default "overlay" version, ``converse.css`` is used, and for the
|
||||
"fullscreen" version ``inverse.css`` is used.
|
||||
|
||||
We'd like to eventually not require two different CSS files, and to allow you
|
||||
to seamlessly switch between the different view modes.
|
||||
:ref:`view_mode`.
|
||||
|
||||
To generate the headless build, run ``make dist/converse-headless.js`` and/or
|
||||
``make dist/converse-headless.min.js``.
|
||||
|
@ -3,11 +3,12 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>inVerse</title>
|
||||
<title>Converse</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="css/images/favicon.ico"/>
|
||||
<script type="text/javascript" src="inverse-analytics.js"></script>
|
||||
<noscript><p><img src="//stats.opkode.com/piwik.php?idsite=5" style="border:0;" alt="" /></p></noscript>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/inverse.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/converse.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/fullpage.css" />
|
||||
<script src="dist/converse.js"></script>
|
||||
</head>
|
||||
<body class="reset">
|
||||
|
113
index.html
113
index.html
@ -5,7 +5,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="Converse.js: An XMPP chat client which can be integrated into any website" />
|
||||
<meta name="description" content="Converse: An XMPP chat client which can be integrated into any website" />
|
||||
<meta name="author" content="JC Brand" />
|
||||
<meta name="keywords" content="xmpp chat webchat converse.js" />
|
||||
|
||||
@ -56,8 +56,8 @@
|
||||
<li class="page-scroll">
|
||||
<a href="#sponsors">Sponsor</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/docs/html/manual.html">User Manual</a>
|
||||
<li class="page-scroll">
|
||||
<a href="#hosting">Hosting</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/docs/html/index.html">Documentation</a>
|
||||
@ -107,7 +107,7 @@
|
||||
<div class="col-lg-8 col-lg-offset-2">
|
||||
<h2>Converse is written in JavaScript and runs in your browser.</h2>
|
||||
<p>You can start using it here immediately, or you can <a href="/docs/html/index.html">integrate it into your own website</a>.</p>
|
||||
<p>Take a look at the <a href="/demo">demo page</a> for other examples of how Converse.js can be configured and used.</a>
|
||||
<p>Take a look at the <a href="/demo">demo page</a> for other examples of how Converse can be configured and used.</a>
|
||||
|
||||
<p>
|
||||
You can connect to any publically accessible <a href="http://xmpp.org" target="_blank" rel="noopener">XMPP/Jabber</a> server,
|
||||
@ -193,7 +193,7 @@
|
||||
or <a href="https://mastodon.xyz/@jcbrand" target="_blank" rel="noopener">Mastodon</a>
|
||||
<li>Chat with me via XMPP at <a href="xmpp:jc@opkode.com" class="xmpp JSnocheck" title="XMPP/Jabber">jc@opkode.com</a></li>
|
||||
<li>For technical support, you can ask on <a href="http://stackoverflow.com/questions/tagged/converse.js">Stack Overflow</a>
|
||||
<li>The Converse.js XMPP chatroom: <a href="xmpp:discuss@conference.conversejs.org" class="xmpp JSnocheck" title="Converse.js chat room">discuss@conference.conversejs.org</a>.</li>
|
||||
<li>The Converse XMPP chatroom: <a href="xmpp:discuss@conference.conversejs.org" class="xmpp JSnocheck" title="Converse chat room">discuss@conference.conversejs.org</a>.</li>
|
||||
<li>Please file bugs and feature requests on <a target="_blank" rel="noopener" href="https://github.com/jcbrand/converse.js/issues">Github</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -217,17 +217,19 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2" style="margin-top: 3em">
|
||||
<div class="sponsors">
|
||||
<h2>Converse.js is supported by:</h2>
|
||||
<h2>Converse is supported by:</h2>
|
||||
<ul>
|
||||
<li><a href="https://www.keycdn.com/" target="_blank" rel="noopener"><img style="height: 3em" src="/logo/keycdn.svg" alt="KeyCDN"></a></li>
|
||||
<li><a href="https://wikisuite.org" target="_blank" rel="noopener"><img style="height: 4em" src="/logo/wikisuite-white.png" alt="WikiSuite"></a></li>
|
||||
<li><a href="https://www.keycdn.com/?utm_source=conversejs" target="_blank" rel="noopener"><img style="height: 3em" src="/logo/keycdn.svg" alt="KeyCDN"></a></li>
|
||||
<li><a href="https://wikisuite.org/?utm_source=conversejs" target="_blank" rel="noopener"><img style="height: 4em" src="/logo/wikisuite-white.png" alt="WikiSuite"></a></li>
|
||||
<li><a href="https://hostpresto.com/?utm_source=conversejs" target="_blank" rel="noopener"><img style="height: 3em" src="/logo/hostpresto.png" alt="HostPresto"></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p class="sponsors-text">Converse.js is a software commons; available at no cost to you or anyone else.
|
||||
Sponsorships allow us to fund further development and improvements and are greatly appreciated.
|
||||
If you'd like to sponsor this project, please visit <a href="https://www.patreon.com/jcbrand" target="_blank" rel="noopener">Patreon</a>
|
||||
or <a href="https://liberapay.com/jcbrand" target="_blank" rel="noopener">Liberapay</a>.
|
||||
<p class="sponsors-text">Converse is a software commons, available at no cost to you or anyone else.
|
||||
Sponsorships allow us to fund further development and improvements.
|
||||
If you'd like to sponsor this project, please visit <a href="https://www.patreon.com/jcbrand" target="_blank" rel="noopener">Patreon</a>,
|
||||
<a href="https://liberapay.com/jcbrand" target="_blank" rel="noopener">Liberapay</a> or
|
||||
<a href="http://opkode.com/contact" target="_blank" rel="noopener">contact us</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -235,6 +237,93 @@
|
||||
</section>
|
||||
</body>
|
||||
|
||||
<section class="outro content-section text-center" id="hosting">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2" style="margin-top: 3em">
|
||||
<h2>XMPP Account Hosting</h2>
|
||||
<p>
|
||||
We provide free XMPP accounts under the domain <strong>conversejs.org</strong>.
|
||||
You can create an account directly through the app on
|
||||
this website or on <a href="https://inverse.chat" target="_blank" rel="noopener">inverse.chat</a>.
|
||||
</p>
|
||||
<p>
|
||||
If you're interested in professional XMPP hosting under your
|
||||
own domain name, please <a href="http://opkode.com/contact" target="_blank" rel="noopener">contact us</a>.
|
||||
</p>
|
||||
|
||||
<div class="privacy-policy">
|
||||
<h3>Privacy policy and GDPR compliance</h3>
|
||||
<p>
|
||||
This service is provided on a pro bono basis. An email
|
||||
address is not needed to sign up and we don't sell or
|
||||
monetize any of your data.
|
||||
</p>
|
||||
<h4>Sharing of data with 3rd parties</h4>
|
||||
<p>
|
||||
We don't share any of your data with 3rd parties,
|
||||
except when necessary to run the service. For example,
|
||||
when you send a message to a user on a differerent XMPP
|
||||
server.
|
||||
Your presence information (whether you're online or
|
||||
not) is shared with contacts that you've added from
|
||||
other servers.
|
||||
</p>
|
||||
<p>
|
||||
Users on other XMPP servers
|
||||
can request access to your (optionally filled-in) VCard data.
|
||||
You can remove your VCard data through an XMPP client.
|
||||
The latest version of Converse supports this, and you can
|
||||
<a href="https://conversejs.org/4.0.0-alpha/fullscreen.html" target="_blank" rel="noopener">use it here</a>.
|
||||
</p>
|
||||
<h4>Data storage</h4>
|
||||
<p>
|
||||
Our XMPP server runs in a Hetzner data centre in
|
||||
Strasbourg, France.
|
||||
</p>
|
||||
<p>
|
||||
Your chat messages are archived for a period of 1
|
||||
month, after which they are deleted.
|
||||
</p>
|
||||
<p>
|
||||
Currently the <strong>conversejs.org</strong> XMPP
|
||||
server does not support HTTP-file upload, which means
|
||||
that we don't host any uploaded files of users.
|
||||
</p>
|
||||
<p>
|
||||
During normal operations we don't log or process IP
|
||||
addresses, although it might be necessary in certain
|
||||
cases where a problem needs to be debugged (hasn't
|
||||
happened yet). Logs older than 6 months are deleted.
|
||||
</p>
|
||||
<h4>Data portability</h4>
|
||||
<p>
|
||||
Currently there is no standardized way to move a
|
||||
user account from one XMPP server to another.
|
||||
</p>
|
||||
<p>
|
||||
If you'd like to have a copy of your data for
|
||||
transferal to another account, please <a href="http://opkode.com/contact" target="_blank" rel="noopener">contact us</a>.
|
||||
</p>
|
||||
<h4>Account deletion</h4>
|
||||
<p>
|
||||
Currently it's not possible to automatically delete
|
||||
your account via Converse, although you might be
|
||||
able to do so via other XMPP clients that support
|
||||
account deletion via
|
||||
<a href="https://xmpp.org/extensions/xep-0077.html" target="_blank" rel="noopener">XEP-0077</a>.
|
||||
</p>
|
||||
<p>
|
||||
You can always <a href="http://opkode.com/contact" target="_blank" rel="noopener">contact us</a>
|
||||
and we'll delete your account manually.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
/*
|
||||
@licstart
|
||||
|
1511
locale/converse.pot
1511
locale/converse.pot
File diff suppressed because it is too large
Load Diff
BIN
logo/hostpresto.png
Normal file
BIN
logo/hostpresto.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Converse.js Mockups</title>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../node_modules/font-awesome/css/font-awesome.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../css/inverse.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../css/converse.css" />
|
||||
</head>
|
||||
|
||||
<body class="reset">
|
||||
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Chatroom Fullscreen</title>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../node_modules/font-awesome/css/font-awesome.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../css/inverse.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../css/converse.css" />
|
||||
</head>
|
||||
|
||||
<body class="reset">
|
||||
@ -23,12 +23,11 @@
|
||||
<div class="chatbox chatroom" id="chatroom">
|
||||
<div class="flyout box-flyout">
|
||||
<div class="chat-head chat-head-chatroom row no-gutters">
|
||||
<div class="col col-9">
|
||||
<div class="chatbox-title">
|
||||
<div class="chat-title">Capulet's orchard</div>
|
||||
<p class="chatroom-description">Two households, both alike in dignity, In fair Verona, where we lay our scene.</p>
|
||||
</div>
|
||||
<div class="chatbox-buttons row no-gutters">
|
||||
<a class="chatbox-btn fa fa-minus"></a>
|
||||
<a class="chatbox-btn fa fa-close"></a>
|
||||
<a class="chatbox-btn fa fa-wrench"></a>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<title>Login Fullscreen</title>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../node_modules/bootstrap/dist/css/bootstrap.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../node_modules/font-awesome/css/font-awesome.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../css/inverse.css" />
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="../../css/converse.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
10423
package-lock.json
generated
10423
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "converse.js",
|
||||
"version": "3.3.4",
|
||||
"description": "Browser based XMPP instant messaging client",
|
||||
"main": "main.js",
|
||||
"description": "Browser based XMPP chat client",
|
||||
"main": "dist/converse.js",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"locale": "locale",
|
||||
@ -20,20 +20,24 @@
|
||||
"chatrooms",
|
||||
"webchat"
|
||||
],
|
||||
"author": "JC Brand",
|
||||
"author": {
|
||||
"name": "JC Brand",
|
||||
"email": "jc@opkode.com"
|
||||
},
|
||||
"license": "MPL-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jcbrand/converse.js/issues"
|
||||
"url": "https://github.com/conversejs/converse.js/issues"
|
||||
},
|
||||
"engines": {
|
||||
"browser": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0-beta.35",
|
||||
"@babel/core": "^7.0.0-beta.35",
|
||||
"@babel/preset-env": "^7.0.0-beta.35",
|
||||
"almond": "~0.3.3",
|
||||
"@babel/cli": "^7.0.0-beta.48",
|
||||
"@babel/core": "^7.0.0-beta.48",
|
||||
"@babel/preset-env": "^7.0.0-beta.48",
|
||||
"@babel/preset-es2015": "^7.0.0-beta.49",
|
||||
"awesomplete-avoid-xss": "^1.1.2",
|
||||
"babel-loader": "^8.0.0-beta.3",
|
||||
"backbone": "1.3.3",
|
||||
"backbone.browserStorage": "0.0.3",
|
||||
"backbone.nativeview": "^0.3.3",
|
||||
@ -48,9 +52,12 @@
|
||||
"es6-promise": "^4.1.0",
|
||||
"eslint": "4.19.1",
|
||||
"eslint-plugin-lodash": "^2.3.3",
|
||||
"exports-loader": "^0.7.0",
|
||||
"filesize": "^3.6.1",
|
||||
"font-awesome": "^4.7.0",
|
||||
"hellojs": "^1.16.1",
|
||||
"http-server": "^0.10.0",
|
||||
"imports-loader": "^0.8.0",
|
||||
"install": "^0.9.5",
|
||||
"jasmine-core": "2.6.4",
|
||||
"jed": "1.1.1",
|
||||
@ -60,7 +67,10 @@
|
||||
"lodash": "4.17.4",
|
||||
"lodash-template-loader": "^2.0.0",
|
||||
"long": "^3.1.0",
|
||||
"lodash-template-webpack-loader": "jcbrand/lodash-template-webpack-loader",
|
||||
"minimist": "^1.2.0",
|
||||
"moment": "~> 2.19.3 ",
|
||||
"npm": "^5.7.1",
|
||||
"otr": "0.2.16",
|
||||
"pluggable.js": "2.0.0",
|
||||
"po2json": "^0.4.4",
|
||||
@ -70,17 +80,15 @@
|
||||
"sinon": "^2.1.0",
|
||||
"sizzle": "^2.3.3",
|
||||
"snabbdom": "0.7.1",
|
||||
"strophe.js": "1.2.14",
|
||||
"strophe.js": "1.2.15",
|
||||
"strophejs-plugin-ping": "0.0.1",
|
||||
"strophejs-plugin-register": "0.0.1",
|
||||
"strophejs-plugin-rsm": "0.0.1",
|
||||
"text": "requirejs/text#2.0.15",
|
||||
"uglify-es": "^3.0.24",
|
||||
"urijs": "^1.19.1",
|
||||
"wait-until-promise": "^1.0.0",
|
||||
"webpack": "^4.0.1",
|
||||
"webpack-cli": "^2.1.4",
|
||||
"xss": "^0.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"npm": "^5.7.1"
|
||||
}
|
||||
}
|
||||
|
18
redirect.html
Normal file
18
redirect.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Converse</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="css/images/favicon.ico"/>
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="css/converse.css" />
|
||||
<script src="node_modules/hellojs/dist/hello.all.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<div class="inner-content">
|
||||
<h1 class="brand-heading"><i class="icon-conversejs"></i> Converse</h1>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
zc.buildout==2.11.4
|
@ -1,4 +1,3 @@
|
||||
#converse-embedded-chat,
|
||||
#conversejs {
|
||||
[hidden] { display: none; }
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
#conversejs {
|
||||
.chatbox-navback {
|
||||
display: none;
|
||||
}
|
||||
.flyout {
|
||||
border-radius: $chatbox-border-radius;
|
||||
bottom: $chatbox-hover-height;
|
||||
position: absolute;
|
||||
|
||||
@media screen and (max-height: $mobile-landscape-height) {
|
||||
@ -38,7 +40,6 @@
|
||||
flex-wrap: nowrap;
|
||||
color: #ffffff;
|
||||
font-size: 100%;
|
||||
height: $chat-head-height;
|
||||
margin: 0;
|
||||
padding: 0.5em;
|
||||
position: relative;
|
||||
@ -53,6 +54,11 @@
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.chatbox-title {
|
||||
.chatroom-description {
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
.chatbox-buttons {
|
||||
flex-direction: row-reverse;
|
||||
@include make-col-ready();
|
||||
@ -120,8 +126,6 @@
|
||||
justify-content: space-between;
|
||||
background-color: $chat-head-color;
|
||||
box-shadow: 1px 3px 5px 3px rgba(0, 0, 0, 0.4);
|
||||
height: $chat-height;
|
||||
min-height: $chat-height/2;
|
||||
z-index: 1;
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
@ -246,7 +250,6 @@
|
||||
width: 100%;
|
||||
border: none;
|
||||
min-height: $chat-textarea-height;
|
||||
max-height: $max-chat-textarea-height;
|
||||
margin-bottom: -4px; // Not clear why this is necessar :(
|
||||
&.spoiler {
|
||||
height: 42px;
|
||||
@ -330,7 +333,6 @@
|
||||
}
|
||||
ul {
|
||||
&.emoji-picker {
|
||||
height: $emoji-picker-height;
|
||||
overflow: scroll;
|
||||
padding: 0.5em;
|
||||
}
|
||||
@ -434,33 +436,224 @@
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
.chatbox-btn {
|
||||
font-size: $fullpage-chatbox-button-size;
|
||||
}
|
||||
/* ******************* Overlay and embedded styles *************************** */
|
||||
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-overlayed {
|
||||
.chat-head {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
@media screen and (max-height: $mobile-landscape-height) {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
@media screen and (max-width: $mobile-portrait-length) {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
.chatbox-title {
|
||||
@include make-col(8);
|
||||
}
|
||||
.chatbox-buttons {
|
||||
@include make-col(3);
|
||||
@include make-col(4);
|
||||
}
|
||||
}
|
||||
|
||||
.chatbox {
|
||||
min-width: $overlayed-chat-width!important;
|
||||
width: $overlayed-chat-width;
|
||||
|
||||
.box-flyout {
|
||||
min-width: $overlayed-chat-width!important;
|
||||
width: $overlayed-chat-width;
|
||||
}
|
||||
|
||||
.chat-body {
|
||||
.chat-message {
|
||||
line-height: $line-height-large;
|
||||
.chat-msg-author {
|
||||
line-height: $line-height-large;
|
||||
}
|
||||
.chat-msg-content {
|
||||
line-height: $line-height-large;
|
||||
.emojione {
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatbox {
|
||||
form.sendXMPPMessage {
|
||||
.chat-toolbar {
|
||||
li {
|
||||
.toolbar-menu {
|
||||
min-width: 235px;
|
||||
|
||||
ul {
|
||||
&.emoji-toolbar {
|
||||
width: 100%;
|
||||
.emoji-category {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#conversejs.converse-overlayed {
|
||||
.flyout {
|
||||
bottom: $overlayed-chatbox-hover-height;
|
||||
}
|
||||
.box-flyout {
|
||||
height: $overlayed-chat-height;
|
||||
min-height: $overlayed-chat-height/2;
|
||||
}
|
||||
.chat-head {
|
||||
height: $overlayed-chat-head-height;
|
||||
}
|
||||
.chat-textarea {
|
||||
max-height: $overlayed-max-chat-textarea-height;
|
||||
}
|
||||
.emoji-picker {
|
||||
height: $overlayed-emoji-picker-height;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
#conversejs.converse-overlayed {
|
||||
> .row {
|
||||
flex-direction: column;
|
||||
|
||||
&.no-gutters {
|
||||
margin: -1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ******************* Fullpage styles *************************** */
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
border-top: 0.8em solid $chat-head-color;
|
||||
border: $flyout-padding solid $chat-head-color;
|
||||
bottom: 0;
|
||||
}
|
||||
.chatbox-btn {
|
||||
font-size: $fullpage-chatbox-button-size;
|
||||
margin: 0 0.3em;
|
||||
}
|
||||
.chat-head {
|
||||
height: $fullpage-chat-head-height;
|
||||
font-size: $font-size-huge;
|
||||
padding: 0;
|
||||
.user-custom-message {
|
||||
font-size: 50%;
|
||||
height: auto;
|
||||
line-height: $line-height;
|
||||
}
|
||||
.chatbox-title {
|
||||
@include make-col(10);
|
||||
}
|
||||
.chatbox-buttons {
|
||||
@include make-col(2);
|
||||
}
|
||||
}
|
||||
.chat-textarea {
|
||||
max-height: $fullpage-max-chat-textarea-height;
|
||||
}
|
||||
.emoji-picker {
|
||||
height: $fullpage-emoji-picker-height;
|
||||
}
|
||||
|
||||
.chatbox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
@include make-col-ready();
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(9);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(9);
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
@include make-col(10);
|
||||
}
|
||||
|
||||
.box-flyout {
|
||||
background-color: $chat-head-color;
|
||||
box-shadow: none;
|
||||
height: $fullpage-chat-height;
|
||||
min-height: $fullpage-chat-height/2;
|
||||
width: $fullpage-chat-width;
|
||||
}
|
||||
.chat-body {
|
||||
background-color: $chat-head-color;
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
|
||||
.chat-message {
|
||||
line-height: $line-height;
|
||||
font-size: $font-size-small;
|
||||
.chat-msg-author {
|
||||
line-height: $line-height;
|
||||
}
|
||||
.chat-msg-content {
|
||||
line-height: $line-height;
|
||||
.emojione {
|
||||
height: $line-height;
|
||||
margin-bottom: -$line-height/4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-content {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
}
|
||||
.chat-title {
|
||||
font-size: $font-size-huge;
|
||||
line-height: $line-height-huge;
|
||||
}
|
||||
.sendXMPPMessage {
|
||||
ul {
|
||||
width: 100%;
|
||||
}
|
||||
.toggle-smiley {
|
||||
ul {
|
||||
&.emoji-toolbar {
|
||||
.emoji-category-picker {
|
||||
margin-right: 5em;
|
||||
}
|
||||
.emoji-category {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
#conversejs:not(.converse-embedded) {
|
||||
> .row {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
#converse-login-panel {
|
||||
.converse-form {
|
||||
padding: 3em 2em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chatbox {
|
||||
width: calc(100% - 50px);
|
||||
.row {
|
||||
@ -473,4 +666,29 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-mobile,
|
||||
#conversejs.converse-overlayed,
|
||||
#conversejs.converse-embedded,
|
||||
#conversejs.converse-fullscreen {
|
||||
.chatbox {
|
||||
.box-flyout {
|
||||
.chatbox-navback {
|
||||
display: flex;
|
||||
@include make-col(2);
|
||||
.fa-arrow-left {
|
||||
&:before {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatbox-title {
|
||||
@include make-col(7);
|
||||
}
|
||||
.chatbox-buttons {
|
||||
@include make-col(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,12 +7,37 @@
|
||||
}
|
||||
}
|
||||
|
||||
#room-details-modal {
|
||||
.features-list {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.chatroom-features {
|
||||
width: 100%;
|
||||
.features-list {
|
||||
padding-top: 0;
|
||||
.feature {
|
||||
width: 100%;
|
||||
margin-right: 0.5em;
|
||||
padding-right: 0;
|
||||
font-size: 1em;
|
||||
cursor: help;
|
||||
.fa {
|
||||
margin-right: 0.5em;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.chat-head-chatroom {
|
||||
background-color: $chatroom-head-color;
|
||||
|
||||
.chatroom-description {
|
||||
color: lighten($chatroom-head-color, 25%);
|
||||
font-size: $font-size-large;
|
||||
font-size: $font-size;
|
||||
font-size: 70%;
|
||||
margin-top: 3px;
|
||||
overflow-y: hidden;
|
||||
@ -101,16 +126,12 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
word-wrap: break-word;
|
||||
min-width: $chat-width;
|
||||
.new-msgs-indicator {
|
||||
background-color: $chatroom-head-color;
|
||||
}
|
||||
.chat-content {
|
||||
height: 100%;
|
||||
}
|
||||
&.full {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
.occupants {
|
||||
display: flex;
|
||||
@ -124,21 +145,19 @@
|
||||
border-bottom-right-radius: $chatbox-border-radius;
|
||||
padding: 0.5em;
|
||||
|
||||
.occupants-heading {
|
||||
font-family: $heading-font;
|
||||
padding: 0.3em 0;
|
||||
}
|
||||
|
||||
.chatroom-features {
|
||||
width: 100%;
|
||||
.feature {
|
||||
float: left;
|
||||
margin-right: 0.5em;
|
||||
padding-right: 0;
|
||||
font-size: 1em;
|
||||
cursor: help;
|
||||
.occupants-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.hide-occupants {
|
||||
align-self: flex-end;
|
||||
cursor: pointer;
|
||||
}
|
||||
.occupants-heading {
|
||||
font-family: $heading-font;
|
||||
padding: 0.3em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.awesomplete {
|
||||
ul {
|
||||
padding: 0;
|
||||
@ -160,15 +179,6 @@
|
||||
flex-grow: 1;
|
||||
border-bottom: 1px solid lightgrey;
|
||||
}
|
||||
&.features-list {
|
||||
padding-top: 0;
|
||||
.feature {
|
||||
width: 100%;
|
||||
.fa {
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
li {
|
||||
cursor: default;
|
||||
display: block;
|
||||
@ -279,14 +289,129 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#conversejs:not(.converse-embedded) {
|
||||
.chatbox {
|
||||
/* ******************* Overlay styles *************************** */
|
||||
|
||||
#conversejs.converse-overlayed {
|
||||
.chatbox {
|
||||
&.chatroom {
|
||||
min-width: $chatroom-width !important;
|
||||
width: $chatroom-width;
|
||||
.box-flyout {
|
||||
.chatroom-body {
|
||||
.chat-area {
|
||||
min-width: $chatroom-width !important;
|
||||
width: $chatroom-width;
|
||||
}
|
||||
.chatbox-title {
|
||||
@include make-col(8);
|
||||
.chatroom-description {
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
.chatbox-buttons {
|
||||
@include make-col(4);
|
||||
}
|
||||
.chatroom-body {
|
||||
.occupants {
|
||||
.chatroom-features {
|
||||
.feature {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-area {
|
||||
min-width: $overlayed-chat-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
.chatroom {
|
||||
.box-flyout {
|
||||
.chatbox-title {
|
||||
@include make-col(9);
|
||||
}
|
||||
.chatbox-buttons {
|
||||
@include make-col(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
|
||||
#conversejs:not(.converse-embedded) {
|
||||
.chatroom {
|
||||
width: 100vw !important;
|
||||
.box-flyout {
|
||||
.chatbox-navback {
|
||||
@include make-col(2);
|
||||
}
|
||||
.chatbox-title {
|
||||
@include make-col(7);
|
||||
}
|
||||
.chatbox-buttons {
|
||||
@include make-col(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen,
|
||||
#conversejs.converse-mobile {
|
||||
|
||||
.chatroom {
|
||||
.box-flyout {
|
||||
background-color: $chatroom-head-color;
|
||||
border: $flyout-padding solid $chatroom-head-color;
|
||||
border-top: 0.8em solid $chatroom-head-color;
|
||||
width: 100%;
|
||||
|
||||
.chatbox-title {
|
||||
.chatroom-description {
|
||||
font-size: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.chatroom-body {
|
||||
@include border-top-radius($chatbox-border-radius);
|
||||
.chatroom-form-container {
|
||||
border-radius: $chatbox-border-radius;
|
||||
}
|
||||
.chat-area {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
.chat-content {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
}
|
||||
&.full {
|
||||
max-width: 100%;
|
||||
.new-msgs-indicator {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.occupants {
|
||||
border-top-right-radius: $chatbox-border-radius;;
|
||||
padding: $occupants-padding;
|
||||
.occupants-heading {
|
||||
font-size: $font-size-large;
|
||||
}
|
||||
ul {
|
||||
&.occupant-list {
|
||||
li {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.room-invite {
|
||||
span {
|
||||
.invited-contact {
|
||||
margin: 0 0 0.5em -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,24 @@
|
||||
#conversejs {
|
||||
.oauth-providers {
|
||||
text-align: center;
|
||||
.oauth-provider {
|
||||
margin: 1em 0;
|
||||
|
||||
.oauth-login {
|
||||
margin-left: 0;
|
||||
color: $link-color;
|
||||
font-size: $font-size-large;
|
||||
&:hover {
|
||||
color: darken($link-color, 20%);
|
||||
}
|
||||
i {
|
||||
color: $link-color;
|
||||
font-size: $font-size-huge;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.set-xmpp-status, .xmpp-status, .roster-contacts {
|
||||
.fa-circle {
|
||||
@ -173,15 +193,6 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.oauth-login {
|
||||
margin-left: 0;
|
||||
color: $text-color;
|
||||
.icon-social:before {
|
||||
font-size: $font-size-large;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.controlbox-pane {
|
||||
.userinfo {
|
||||
padding-bottom: 1em;
|
||||
@ -296,6 +307,7 @@
|
||||
}
|
||||
|
||||
.switch-form {
|
||||
text-align: center;
|
||||
padding: 2em 0;
|
||||
p {
|
||||
margin-top: 0.5em;
|
||||
@ -357,7 +369,6 @@
|
||||
|
||||
.chatbox {
|
||||
.box-flyout {
|
||||
top: -100vh;
|
||||
margin-left: 15px; // Counteracts Bootstrap margins, but
|
||||
// not clear why needed...
|
||||
left: 0;
|
||||
@ -369,10 +380,11 @@
|
||||
}
|
||||
|
||||
#controlbox {
|
||||
order: 0;
|
||||
width: 100vw !important;
|
||||
.box-flyout {
|
||||
width: 100vw !important;
|
||||
height: 100vh !important;
|
||||
margin-left: 30px;
|
||||
}
|
||||
.sidebar {
|
||||
display: block;
|
||||
@ -393,7 +405,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs:not(.converse-fullscreen) {
|
||||
#conversejs.converse-overlayed {
|
||||
#controlbox {
|
||||
order: -1;
|
||||
min-width: $controlbox-width !important;
|
||||
@ -444,3 +456,110 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen,
|
||||
#conversejs.converse-mobile {
|
||||
#controlbox {
|
||||
@include make-col-ready();
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(3);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(3);
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
@include make-col(2);
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
|
||||
.controlbox-pane {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#converse-login-panel {
|
||||
border-radius: 0;
|
||||
.converse-form {
|
||||
padding: 3em 2em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-register-login {
|
||||
line-height: $line-height-huge;
|
||||
}
|
||||
|
||||
.brand-heading-container {
|
||||
@include make-col(12);
|
||||
text-align: center;
|
||||
.brand-heading {
|
||||
font-size: 150%;
|
||||
font-size: 600%;
|
||||
padding: 0.7em 0 0 0;
|
||||
opacity: 0.8;
|
||||
color: $blue;
|
||||
}
|
||||
.brand-subtitle {
|
||||
font-size: 90%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: $mobile-portrait-length) {
|
||||
.brand-heading {
|
||||
font-size: 400%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
@include fade-in;
|
||||
width: 100%;
|
||||
.box-flyout {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.box-flyout {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background-color: $controlbox-head-color;
|
||||
|
||||
.controlbox-head {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-register, #converse-login {
|
||||
@include make-col-ready();
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(6);
|
||||
@include make-col-offset(3);
|
||||
}
|
||||
.title, .instructions {
|
||||
margin: 1em 0;
|
||||
}
|
||||
input[type=submit],
|
||||
input[type=button] {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,23 @@ body.reset {
|
||||
direction: ltr;
|
||||
z-index: 1031; // One more than bootstrap navbar
|
||||
|
||||
&.converse-overlayed {
|
||||
> .row {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
}
|
||||
|
||||
&.converse-fullscreen,
|
||||
&.converse-mobile {
|
||||
.converse-chatboxes {
|
||||
width: 100vw;
|
||||
right: 15px; // Hack due to padding added by bootstrap
|
||||
}
|
||||
}
|
||||
&.converse-overlayed {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.brand-heading {
|
||||
font-family: $heading-font;
|
||||
.icon-conversejs {
|
||||
@ -76,7 +93,6 @@ body.reset {
|
||||
z-index: 1031; // One more than bootstrap navbar
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
height: 2.7rem;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@ -143,6 +159,10 @@ body.reset {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
@ -156,10 +176,16 @@ body.reset {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a, a:visited, a:hover, a:not([href]):not([tabindex]) {
|
||||
a, a:visited, a:not([href]):not([tabindex]) {
|
||||
text-decoration: none;
|
||||
color: $link-color;
|
||||
text-shadow: none;
|
||||
&:hover {
|
||||
color: darken($link-color, 20%);
|
||||
text-decoration: none;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
&.fa {
|
||||
color: $subdued-color;
|
||||
&:hover {
|
||||
|
@ -1,5 +1,4 @@
|
||||
@import "bourbon";
|
||||
@import "converse/variables";
|
||||
#conversejs.converse-embedded {
|
||||
|
||||
@include box-sizing(border-box);
|
||||
|
@ -18,3 +18,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.converse-fullscreen {
|
||||
.chatbox.headlines {
|
||||
.box-flyout {
|
||||
background-color: $headline-head-color;
|
||||
}
|
||||
.chat-head {
|
||||
&.chat-head-chatbox {
|
||||
background-color: $headline-head-color;
|
||||
}
|
||||
}
|
||||
.flyout {
|
||||
border: $flyout-padding solid $headline-head-color;
|
||||
border-top: 0.8em solid $headline-head-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#conversejs:not(.fullscreen) {
|
||||
#conversejs.converse-overlayed {
|
||||
#minimized-chats {
|
||||
order: 100;
|
||||
|
@ -32,6 +32,10 @@
|
||||
.open-chatroom {
|
||||
&:hover {
|
||||
background-color: lighten($controlbox-head-color, 45%);
|
||||
a.add-bookmark,
|
||||
a.room-info {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
&.unread-msgs {
|
||||
.msgs-indicator {
|
||||
@ -48,7 +52,9 @@
|
||||
&:hover {
|
||||
color: $dark-link-color;
|
||||
}
|
||||
&.add-bookmark,
|
||||
&.room-info {
|
||||
display: none;
|
||||
&:before {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
@ -4,10 +4,8 @@
|
||||
position: relative;
|
||||
margin: 0;
|
||||
height: $roster-height;
|
||||
height: calc(~"100% - #{$controlbox-dropdown-height*2} - 20px");
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
|
||||
// XXX: FIXME
|
||||
height: calc(100% - 70px);
|
||||
|
||||
@ -43,7 +41,6 @@
|
||||
}
|
||||
.state-type {
|
||||
font-size: calc(#{$font-size} - 2px);
|
||||
height: $controlbox-dropdown-height;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@ -142,7 +139,6 @@
|
||||
.avatar {
|
||||
float: left;
|
||||
display: inline-block;
|
||||
height: $roster-item-height;
|
||||
}
|
||||
}
|
||||
&.current-xmpp-contact span {
|
||||
|
@ -63,6 +63,8 @@ $message-them-color: $green !default;
|
||||
|
||||
$roster-height: 194px !default;
|
||||
|
||||
$flyout-padding: 1.2em;
|
||||
|
||||
$chat-head-color: $green !default;
|
||||
$chat-head-text-color: white !default;
|
||||
$chat-head-inverse-text-color: white !default;
|
||||
@ -110,10 +112,11 @@ $font-path: "../fonticons/fonts/" !default;
|
||||
$normal-font: "Helvetica", "Arial", sans-serif;
|
||||
$heading-font: 'Century Gothic', futura, 'URW Gothic L', Verdana, sans-serif !default;
|
||||
|
||||
$chatroom-head-color: $red !default;
|
||||
$chatroom-color-light: $light-red !default;
|
||||
$chatroom-color-dark: $darkest-red !default;
|
||||
$chatroom-color-light: $light-red !default;
|
||||
$chatroom-head-color: $red !default;
|
||||
$chatroom-message-them-color: $green !default;
|
||||
$chatroom-width: 400px !default;
|
||||
|
||||
$headline-head-color: $orange !default;
|
||||
|
||||
@ -124,3 +127,30 @@ $box-close-button-padding-right: 4px !default;
|
||||
|
||||
$chatbox-button-size: 14px !default;
|
||||
$fullpage-chatbox-button-size: 16px !default;
|
||||
|
||||
$font-size-small: 12px !default;
|
||||
$font-size: 14px !default;
|
||||
$font-size-large: 16px !default;
|
||||
$font-size-huge: 20px !default;
|
||||
|
||||
$legend-font-size: 16px !default;
|
||||
|
||||
$line-height-small: 14px !default;
|
||||
$line-height: 16px !default;
|
||||
$line-height-large: 20px !default;
|
||||
$line-height-huge: 24px !default;
|
||||
|
||||
$occupants-padding: 1em;
|
||||
|
||||
$fullpage-chat-head-height: 62px !default;
|
||||
$fullpage-chat-height: 100vh;
|
||||
$fullpage-chat-width: 100%;
|
||||
$fullpage-emoji-picker-height: 150px !default;
|
||||
$fullpage-max-chat-textarea-height: 400px !default;
|
||||
|
||||
$overlayed-chat-head-height: 55px !default;
|
||||
$overlayed-chat-height: 450px !default;
|
||||
$overlayed-chat-width: 250px !default;
|
||||
$overlayed-chatbox-hover-height: 1em !default;
|
||||
$overlayed-emoji-picker-height: 100px !default;
|
||||
$overlayed-max-chat-textarea-height: 200px !default;
|
||||
|
@ -113,29 +113,41 @@ a:hover, a:focus {
|
||||
.features-section,
|
||||
.outro,
|
||||
.intro {
|
||||
width: 100%;
|
||||
padding: 100px 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
padding: 100px 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
}
|
||||
.intro {
|
||||
background: url(images/header.jpg) no-repeat bottom center scroll;
|
||||
background-color: #211018;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background: url(images/header.jpg) no-repeat bottom center scroll;
|
||||
background-color: #211018;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
background-size: cover;
|
||||
-o-background-size: cover;
|
||||
}
|
||||
.features-section {
|
||||
background: url('images/bgtr.svg') top right no-repeat, url('images/bgbl.svg') bottom left no-repeat, url('images/bgbl.svg') bottom left no-repeat, url('images/overlay.png'), linear-gradient(45deg, #85505f, #384955, #655361);
|
||||
background: url('images/bgtr.svg') top right no-repeat, url('images/bgbl.svg') bottom left no-repeat, url('images/bgbl.svg') bottom left no-repeat, url('images/overlay.png'), linear-gradient(45deg, #85505f, #384955, #655361);
|
||||
}
|
||||
.features-section a {
|
||||
color: #82B397;
|
||||
color: #82B397;
|
||||
}
|
||||
.outro {
|
||||
background: url('images/bgtr.svg') top right no-repeat, url('images/bgbl.svg') bottom left no-repeat, url('images/overlay.png'), linear-gradient(45deg, #384955, #655361, #85505f);
|
||||
background: url('images/bgtr.svg') top right no-repeat, url('images/bgbl.svg') bottom left no-repeat, url('images/overlay.png'), linear-gradient(45deg, #384955, #655361, #85505f);
|
||||
}
|
||||
|
||||
section {
|
||||
h2 {
|
||||
color: #E7A151;
|
||||
}
|
||||
h3 {
|
||||
color: #89B7CD;
|
||||
}
|
||||
h4 {
|
||||
color: #5CBC86;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.brand-heading {
|
||||
font-family: Futura,Helvetica,Trebuchet MS,Arial,sans-serif;
|
||||
@ -205,25 +217,38 @@ a:hover, a:focus {
|
||||
}
|
||||
|
||||
.content-section {
|
||||
padding-top: 100px;
|
||||
padding-top: 100px;
|
||||
padding-top: 100px;
|
||||
min-height: 100vh;
|
||||
|
||||
.privacy-policy {
|
||||
padding-top: 2em;
|
||||
h4 {
|
||||
padding-top: 1.5em;
|
||||
}
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.donate-section {
|
||||
width: 100%;
|
||||
padding: 50px 0;
|
||||
color: #ffffff;
|
||||
background-color: #211018;
|
||||
width: 100%;
|
||||
padding: 50px 0;
|
||||
color: #ffffff;
|
||||
background-color: #211018;
|
||||
}
|
||||
.donate-section p.bitcoin-header {
|
||||
margin: 0 0 5px;
|
||||
margin: 0 0 5px;
|
||||
}
|
||||
@media (min-width: 767px) {
|
||||
.content-section {
|
||||
padding-top: 150px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
.donate-section {
|
||||
padding: 100px 0;
|
||||
}
|
||||
.content-section {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
.donate-section {
|
||||
padding: 100px 0;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
font-family: Futura,Helvetica,Trebuchet MS,Arial,sans-serif;
|
||||
@ -332,6 +357,9 @@ ul.features {
|
||||
clear: both;
|
||||
font-size: 1.4em;
|
||||
padding: 2em 0 6em 0;
|
||||
ul {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.sponsors h2 {
|
||||
text-align: center;
|
||||
|
@ -2,13 +2,12 @@
|
||||
* Converse.js (Web-based XMPP instant messaging client)
|
||||
* http://conversejs.org
|
||||
*
|
||||
* Copyright (c) 2012-2016, JC Brand <jc@opkode.com>
|
||||
* Copyright (c) 2013-2018, JC Brand <jc@opkode.com>
|
||||
* Licensed under the Mozilla Public License
|
||||
*/
|
||||
@import "font-awesome";
|
||||
@import "bourbon";
|
||||
@import "variables";
|
||||
@import "converse/variables";
|
||||
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@ -40,19 +39,16 @@
|
||||
@import "bootstrap/scss/utilities";
|
||||
}
|
||||
@import "core";
|
||||
@import "converse/core";
|
||||
@import "forms";
|
||||
@import "profile";
|
||||
@import "chatbox";
|
||||
@import "converse/chatbox";
|
||||
@import "controlbox";
|
||||
@import "roomslist";
|
||||
@import "roster";
|
||||
@import "chatrooms";
|
||||
@import "converse/chatrooms";
|
||||
@import "headline";
|
||||
@import "messages";
|
||||
@import "converse/minimized_chats";
|
||||
@import "minimized_chats";
|
||||
@import "bookmarks";
|
||||
@import "awesomplete";
|
||||
@import "embedded";
|
||||
|
@ -1,71 +0,0 @@
|
||||
#converse-embedded-chat,
|
||||
#conversejs:not(.fullscreen) {
|
||||
.chat-head {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
@media screen and (max-height: $mobile-landscape-height) {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
@media screen and (max-width: $mobile-portrait-length) {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
}
|
||||
.chatbox {
|
||||
min-width: $chat-width!important;
|
||||
width: $chat-width;
|
||||
|
||||
.box-flyout {
|
||||
min-width: $chat-width!important;
|
||||
width: $chat-width;
|
||||
}
|
||||
|
||||
.chat-body {
|
||||
.chat-message {
|
||||
line-height: $line-height-large;
|
||||
.chat-msg-author {
|
||||
line-height: $line-height-large;
|
||||
}
|
||||
.chat-msg-content {
|
||||
line-height: $line-height-large;
|
||||
.emojione {
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chatbox {
|
||||
form.sendXMPPMessage {
|
||||
.chat-toolbar {
|
||||
li {
|
||||
.toolbar-menu {
|
||||
min-width: 235px;
|
||||
|
||||
ul {
|
||||
&.emoji-toolbar {
|
||||
width: 100%;
|
||||
.emoji-category {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
#conversejs:not(.converse-fullscreen):not(.converse-embedded) {
|
||||
> .row {
|
||||
flex-direction: column;
|
||||
|
||||
&.no-gutters {
|
||||
margin: -1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#conversejs {
|
||||
.chatbox {
|
||||
&.chatroom {
|
||||
min-width: $chatroom-width !important;
|
||||
width: $chatroom-width;
|
||||
.box-flyout {
|
||||
min-width: $chatroom-width !important;
|
||||
width: $chatroom-width;
|
||||
}
|
||||
|
||||
.chatroom-body {
|
||||
.occupants {
|
||||
.chatroom-features {
|
||||
.feature {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#conversejs {
|
||||
> .row {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
$max-chat-textarea-height: 200px !default;
|
||||
$emoji-picker-height: 100px !default;
|
||||
|
||||
$roster-item-height: 60px !default;
|
||||
|
||||
$chat-head-height: 55px !default;
|
||||
|
||||
$controlbox-dropdown-height: 25px !default;
|
||||
$controlbox-head-height: 55px !default;
|
||||
|
||||
$chatbox-hover-height: 1em !default;
|
||||
|
||||
$font-size-small: 12px !default;
|
||||
$font-size: 14px !default;
|
||||
$font-size-large: 16px !default;
|
||||
$font-size-huge: 20px !default;
|
||||
$legend-font-size: 16px !default;
|
||||
|
||||
$line-height-small: 14px !default;
|
||||
$line-height: 16px !default;
|
||||
$line-height-large: 20px !default;
|
||||
|
||||
$chat-width: 250px !default;
|
||||
$chat-height: 450px !default;
|
||||
|
||||
$chatroom-width: 400px !default;
|
@ -1,58 +0,0 @@
|
||||
/*!
|
||||
* Converse.js (Web-based XMPP instant messaging client)
|
||||
* http://conversejs.org
|
||||
*
|
||||
* Copyright (c) 2012-2014, JC Brand <jc@opkode.com>
|
||||
* Licensed under the Mozilla Public License
|
||||
*/
|
||||
@import "font-awesome";
|
||||
@import "bourbon";
|
||||
@import "variables";
|
||||
@import "inverse/variables";
|
||||
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/mixins";
|
||||
#conversejs {
|
||||
@import "bootstrap/scss/root";
|
||||
@import "bootstrap/scss/reboot";
|
||||
@import "bootstrap/scss/type";
|
||||
@import "bootstrap/scss/images";
|
||||
@import "bootstrap/scss/grid";
|
||||
@import "bootstrap/scss/forms";
|
||||
@import "bootstrap/scss/buttons";
|
||||
@import "bootstrap/scss/transitions";
|
||||
@import "bootstrap/scss/dropdown";
|
||||
@import "bootstrap/scss/button-group";
|
||||
@import "bootstrap/scss/input-group";
|
||||
@import "bootstrap/scss/custom-forms";
|
||||
@import "bootstrap/scss/card";
|
||||
@import "bootstrap/scss/breadcrumb";
|
||||
@import "bootstrap/scss/badge";
|
||||
@import "bootstrap/scss/alert";
|
||||
@import "bootstrap/scss/media";
|
||||
@import "bootstrap/scss/list-group";
|
||||
@import "bootstrap/scss/close";
|
||||
@import "bootstrap/scss/modal";
|
||||
@import "bootstrap/scss/tooltip";
|
||||
@import "bootstrap/scss/popover";
|
||||
@import "bootstrap/scss/utilities";
|
||||
}
|
||||
@import "core";
|
||||
@import "inverse/core";
|
||||
@import "forms";
|
||||
@import "profile";
|
||||
@import "chatbox";
|
||||
@import "inverse/chatbox";
|
||||
@import "controlbox";
|
||||
@import "inverse/controlbox";
|
||||
@import "roster";
|
||||
@import "roomslist";
|
||||
@import "inverse/roster";
|
||||
@import "bookmarks";
|
||||
@import "chatrooms";
|
||||
@import "inverse/chatrooms";
|
||||
@import "headline";
|
||||
@import "inverse/headline";
|
||||
@import "messages";
|
||||
@import "awesomplete"
|
@ -1,96 +0,0 @@
|
||||
#conversejs.fullscreen {
|
||||
.chatbox-btn {
|
||||
font-size: $font-size-large;
|
||||
margin: 0 0.3em;
|
||||
}
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
border: $flyout-padding solid $chat-head-color;
|
||||
border-top: 0.8em solid $chat-head-color;
|
||||
bottom: 0;
|
||||
}
|
||||
.chat-head {
|
||||
font-size: 20px;
|
||||
padding: 0;
|
||||
.user-custom-message {
|
||||
font-size: 50%;
|
||||
height: auto;
|
||||
line-height: $line-height;
|
||||
}
|
||||
}
|
||||
.chatbox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
@include make-col-ready();
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(9);
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
@include make-col(10);
|
||||
}
|
||||
|
||||
.box-flyout {
|
||||
background-color: $chat-head-color;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
box-shadow: none;
|
||||
}
|
||||
.chat-body {
|
||||
background-color: $chat-head-color;
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
|
||||
.chat-message {
|
||||
line-height: $line-height;
|
||||
font-size: $font-size-small;
|
||||
.chat-msg-author {
|
||||
line-height: $line-height;
|
||||
}
|
||||
.chat-msg-content {
|
||||
line-height: $line-height;
|
||||
.emojione {
|
||||
height: $line-height;
|
||||
margin-bottom: -$line-height/4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-content {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
}
|
||||
.chat-title {
|
||||
font-size: $font-size-huge;
|
||||
line-height: $line-height-huge;
|
||||
}
|
||||
|
||||
.sendXMPPMessage {
|
||||
ul {
|
||||
width: 100%;
|
||||
}
|
||||
.toggle-smiley {
|
||||
ul {
|
||||
&.emoji-toolbar {
|
||||
.emoji-category-picker {
|
||||
margin-right: 5em;
|
||||
}
|
||||
.emoji-category {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#conversejs:not(.converse-embedded).fullscreen {
|
||||
.chatbox {
|
||||
width: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
#conversejs.converse-fullscreen,
|
||||
#conversejs.converse-mobile {
|
||||
|
||||
.chat-head-chatroom {
|
||||
height: $chatroom-head-height;
|
||||
font-size: 20px;
|
||||
.chat-title {
|
||||
.chatroom-description {
|
||||
font-size: 65%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chatroom {
|
||||
.box-flyout {
|
||||
background-color: $chatroom-head-color;
|
||||
border: $flyout-padding solid $chatroom-head-color;
|
||||
border-top: 0.8em solid $chatroom-head-color;
|
||||
width: 100%;
|
||||
|
||||
.chatroom-body {
|
||||
@include border-top-radius($chatbox-border-radius);
|
||||
.chatroom-form-container {
|
||||
border-radius: $chatbox-border-radius;
|
||||
}
|
||||
.chat-area {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
min-width: auto;
|
||||
|
||||
.chat-content {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
}
|
||||
&.full {
|
||||
max-width: 100%;
|
||||
.new-msgs-indicator {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.occupants {
|
||||
border-top-right-radius: $chatbox-border-radius;;
|
||||
padding: $padding;
|
||||
.occupants-heading {
|
||||
font-size: $font-size-large;
|
||||
}
|
||||
ul {
|
||||
&.occupant-list {
|
||||
li {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.room-invite {
|
||||
span {
|
||||
.invited-contact {
|
||||
margin: 0 0 0.5em -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
#conversejs.fullscreen {
|
||||
#controlbox {
|
||||
@include make-col-ready();
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(3);
|
||||
}
|
||||
@include media-breakpoint-up(xl) {
|
||||
@include make-col(2);
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
|
||||
.controlbox-pane {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.flyout {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#converse-login-panel {
|
||||
border-radius: 0;
|
||||
.converse-form {
|
||||
padding: 3em 2em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-register-login {
|
||||
line-height: $line-height-huge;
|
||||
}
|
||||
|
||||
.brand-heading-container {
|
||||
@include make-col(12);
|
||||
text-align: center;
|
||||
.brand-heading {
|
||||
font-size: 150%;
|
||||
font-size: 600%;
|
||||
padding: 0.7em 0 0 0;
|
||||
opacity: 0.8;
|
||||
color: $blue;
|
||||
}
|
||||
.brand-subtitle {
|
||||
font-size: 90%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: $mobile-portrait-length) {
|
||||
.brand-heading {
|
||||
font-size: 400%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.logged-out {
|
||||
@include make-col(12);
|
||||
@include fade-in;
|
||||
width: 100%;
|
||||
.box-flyout {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.box-flyout {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
background-color: $controlbox-head-color;
|
||||
|
||||
.controlbox-head {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#converse-register, #converse-login {
|
||||
@include make-col-ready();
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
@include make-col(8);
|
||||
@include make-col-offset(2);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include make-col(6);
|
||||
@include make-col-offset(3);
|
||||
}
|
||||
.title, .instructions {
|
||||
margin: 1em 0;
|
||||
}
|
||||
input[type=submit],
|
||||
input[type=button] {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
body {
|
||||
font-family: "Lora", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #ffffff;
|
||||
background-color: $global-background-color;
|
||||
|
||||
.brand-heading {
|
||||
font-size: 600%;
|
||||
margin-left: -10%;
|
||||
&.fade-in {
|
||||
@include fade-in;
|
||||
@include animation-delay(2s);
|
||||
}
|
||||
.icon-conversejs {
|
||||
font-size: 88%;
|
||||
}
|
||||
}
|
||||
|
||||
div.content {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: fixed;
|
||||
background-color: $global-background-color;
|
||||
|
||||
.inner-content {
|
||||
text-align: center;
|
||||
padding: 7%;
|
||||
@include calc(padding-left, '5% + #{$controlbox-width}');
|
||||
|
||||
p.no-chats {
|
||||
padding-right: 10%;
|
||||
font-size: 120%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#conversejs.fullscreen {
|
||||
.converse-chatboxes {
|
||||
width: 100vw;
|
||||
right: 15px; // Hack due to padding added by bootstrap
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#conversejs.fullscreen {
|
||||
.chatbox.headlines {
|
||||
.box-flyout {
|
||||
background-color: $headline-head-color;
|
||||
}
|
||||
.chat-head {
|
||||
&.chat-head-chatbox {
|
||||
background-color: $headline-head-color;
|
||||
}
|
||||
}
|
||||
.flyout {
|
||||
border: $flyout-padding solid $headline-head-color;
|
||||
border-top: 0.8em solid $headline-head-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
#conversejs.fullscreen {
|
||||
#minimized-chats {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
color: $inverse-link-color;
|
||||
display: none;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
height: 100%;
|
||||
margin: 0 $chat-gutter;
|
||||
padding: 0;
|
||||
width: 130px;
|
||||
|
||||
#toggle-minimized-chats {
|
||||
border-top-left-radius: $chatbox-border-radius;
|
||||
border-top-right-radius: $chatbox-border-radius;
|
||||
background-color: $link-color;
|
||||
color: white;
|
||||
position: relative;
|
||||
padding: 10px 0 0 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.minimized-chats-flyout {
|
||||
height: auto;
|
||||
bottom: $bottom-gutter-height;
|
||||
.chat-head {
|
||||
padding: 0.3em;
|
||||
border-radius: $chatbox-border-radius;
|
||||
width: $minimized-chats-width;
|
||||
height: 35px;
|
||||
margin-bottom: 0.2em;
|
||||
box-shadow: 1px 3px 5px 3px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
&.minimized {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.unread-message-count {
|
||||
font-weight: bold;
|
||||
background-color: white;
|
||||
border: 1px solid;
|
||||
text-shadow: 1px 1px 0 $text-shadow-color;
|
||||
color: $warning-color;
|
||||
border-radius: 5px;
|
||||
padding: 2px 4px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 116px;
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#conversejs {
|
||||
#converse-roster {
|
||||
padding-bottom: 3em;
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
$max-chat-textarea-height: 400px !default;
|
||||
$emoji-picker-height: 150px !default;
|
||||
|
||||
$roster-item-height: 30px !default;
|
||||
|
||||
$flyout-padding: 1.2em;
|
||||
|
||||
$chat-head-height: 62px !default;
|
||||
|
||||
$controlbox-dropdown-height: 30px !default;
|
||||
$controlbox-head-height: 63px !default;
|
||||
|
||||
$rounded-border-radius: 4px !default;
|
||||
|
||||
$chatbox-hover-height: 6px !default;
|
||||
|
||||
$font-size-small: 14px !default;
|
||||
$font-size: 16px !default;
|
||||
$font-size-large: 18px !default;
|
||||
$font-size-huge: 26px !default;
|
||||
$legend-font-size: 18px !default;
|
||||
|
||||
$line-height-small: 20px !default;
|
||||
$line-height: 22px !default;
|
||||
$line-height-large: 24px !default;
|
||||
$line-height-huge: 30px !default;
|
||||
|
||||
$chat-width: 100% !default;
|
||||
$chat-height: 100%;
|
||||
|
||||
$padding: 1em;
|
||||
|
||||
$chatroom-head-height: 62px !default;
|
||||
$chatroom-width: 300px !default;
|
@ -4,12 +4,10 @@
|
||||
define([
|
||||
"jasmine",
|
||||
"jquery",
|
||||
"converse-core",
|
||||
"utils",
|
||||
"mock",
|
||||
"test-utils"
|
||||
], factory);
|
||||
} (this, function (jasmine, $, converse, utils, mock, test_utils) {
|
||||
} (this, function (jasmine, $, mock, test_utils) {
|
||||
"use strict";
|
||||
var $iq = converse.env.$iq,
|
||||
$msg = converse.env.$msg,
|
||||
@ -381,14 +379,14 @@
|
||||
['http://jabber.org/protocol/pubsub#publish-options']
|
||||
).then(function () {
|
||||
/* Client requests all items
|
||||
* -------------------------
|
||||
*
|
||||
* <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
|
||||
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
* <items node='storage:bookmarks'/>
|
||||
* </pubsub>
|
||||
* </iq>
|
||||
*/
|
||||
* -------------------------
|
||||
*
|
||||
* <iq from='juliet@capulet.lit/randomID' type='get' id='retrieve1'>
|
||||
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
* <items node='storage:bookmarks'/>
|
||||
* </pubsub>
|
||||
* </iq>
|
||||
*/
|
||||
var IQ_id;
|
||||
expect(_.filter(_converse.connection.send.calls.all(), function (call) {
|
||||
var stanza = call.args[0];
|
||||
@ -411,27 +409,29 @@
|
||||
}).length).toBe(1);
|
||||
|
||||
/*
|
||||
* Server returns all items
|
||||
* ------------------------
|
||||
* <iq type='result'
|
||||
* to='juliet@capulet.lit/randomID'
|
||||
* id='retrieve1'>
|
||||
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
* <items node='storage:bookmarks'>
|
||||
* <item id='current'>
|
||||
* <storage xmlns='storage:bookmarks'>
|
||||
* <conference name='The Play's the Thing'
|
||||
* autojoin='true'
|
||||
* jid='theplay@conference.shakespeare.lit'>
|
||||
* <nick>JC</nick>
|
||||
* </conference>
|
||||
* </storage>
|
||||
* </item>
|
||||
* </items>
|
||||
* </pubsub>
|
||||
* </iq>
|
||||
*/
|
||||
* Server returns all items
|
||||
* ------------------------
|
||||
* <iq type='result'
|
||||
* to='juliet@capulet.lit/randomID'
|
||||
* id='retrieve1'>
|
||||
* <pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||
* <items node='storage:bookmarks'>
|
||||
* <item id='current'>
|
||||
* <storage xmlns='storage:bookmarks'>
|
||||
* <conference name='The Play's the Thing'
|
||||
* autojoin='true'
|
||||
* jid='theplay@conference.shakespeare.lit'>
|
||||
* <nick>JC</nick>
|
||||
* </conference>
|
||||
* </storage>
|
||||
* </item>
|
||||
* </items>
|
||||
* </pubsub>
|
||||
* </iq>
|
||||
*/
|
||||
expect(_converse.bookmarks.models.length).toBe(0);
|
||||
|
||||
spyOn(_converse.bookmarks, 'onBookmarksReceived').and.callThrough();
|
||||
var stanza = $iq({'to': _converse.connection.jid, 'type':'result', 'id':IQ_id})
|
||||
.c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'node': 'storage:bookmarks'})
|
||||
@ -448,11 +448,13 @@
|
||||
'jid': 'another@conference.shakespeare.lit'
|
||||
}); // Purposefully exclude the <nick> element to test #1043
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
return test_utils.waitUntil(() => _converse.bookmarks.onBookmarksReceived.calls.count(), 300)
|
||||
}).then(() => {
|
||||
expect(_converse.bookmarks.models.length).toBe(2);
|
||||
expect(_converse.bookmarks.findWhere({'jid': 'theplay@conference.shakespeare.lit'}).get('autojoin')).toBe(true);
|
||||
expect(_converse.bookmarks.findWhere({'jid': 'another@conference.shakespeare.lit'}).get('autojoin')).toBe(false);
|
||||
done();
|
||||
});
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
|
||||
describe("The rooms panel", function () {
|
||||
|
@ -2,12 +2,10 @@
|
||||
define([
|
||||
"jquery",
|
||||
"jasmine",
|
||||
"utils",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"
|
||||
], factory);
|
||||
} (this, function ($, jasmine, utils, converse, mock, test_utils) {
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var _ = converse.env._;
|
||||
var $iq = converse.env.$iq;
|
||||
@ -429,9 +427,9 @@
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
expect(chatbox).toBeDefined();
|
||||
expect(view).toBeDefined();
|
||||
var $toolbar = $(view.el).find('ul.chat-toolbar');
|
||||
expect($toolbar.length).toBe(1);
|
||||
expect($toolbar.children('li').length).toBe(1);
|
||||
var toolbar = view.el.querySelector('ul.chat-toolbar');
|
||||
expect(_.isElement(toolbar)).toBe(true);
|
||||
expect(toolbar.querySelectorAll(':scope > li').length).toBe(1);
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -458,7 +456,7 @@
|
||||
var timeout = false;
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return utils.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container'));
|
||||
return u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker-container'));
|
||||
}, 500).then(function () {
|
||||
var picker = view.el.querySelector('.toggle-smiley .emoji-picker-container');
|
||||
var items = picker.querySelectorAll('.emoji-picker li');
|
||||
@ -747,7 +745,7 @@
|
||||
expect(chatbox.messages.length).toEqual(1);
|
||||
var msg_obj = chatbox.messages.models[0];
|
||||
expect(msg_obj.get('sender')).toEqual('me');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
var $chat_content = $(chatboxview.el).find('.chat-content');
|
||||
var status_text = $chat_content.find('.chat-info.chat-state-notification').text();
|
||||
expect(status_text).toBe('Typing from another device');
|
||||
@ -895,7 +893,7 @@
|
||||
expect(chatbox.messages.length).toEqual(1);
|
||||
var msg_obj = chatbox.messages.models[0];
|
||||
expect(msg_obj.get('sender')).toEqual('me');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
var $chat_content = $(chatboxview.el).find('.chat-content');
|
||||
var status_text = $chat_content.find('.chat-info.chat-state-notification').text();
|
||||
expect(status_text).toBe('Stopped typing on the other device');
|
||||
|
309
spec/chatroom.js
309
spec/chatroom.js
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils", "utils" ], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils, utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils" ], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $pres = converse.env.$pres;
|
||||
var $iq = converse.env.$iq;
|
||||
@ -657,6 +657,7 @@
|
||||
expect(indicator.getAttribute('data-isodate')).toEqual(moment().startOf('day').format());
|
||||
expect(indicator.querySelector('time').getAttribute('class')).toEqual('separator-text');
|
||||
expect(indicator.querySelector('time').textContent).toEqual(moment().startOf('day').format("dddd MMM Do YYYY"));
|
||||
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(2);
|
||||
expect(chat_content.querySelector('div.chat-info:last-child').textContent).toBe(
|
||||
"some1 has entered the room"
|
||||
);
|
||||
@ -672,9 +673,9 @@
|
||||
.c('status', 'Disconnected: Replaced by new connection').up()
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'affiliation': 'owner',
|
||||
'jid': 'some1@localhost/_converse.js-290929789',
|
||||
'role': 'none'
|
||||
'role': 'moderator'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
@ -685,7 +686,7 @@
|
||||
expect(indicator.getAttribute('data-isodate')).toEqual(moment().startOf('day').format());
|
||||
|
||||
expect(indicator.querySelector('time').textContent).toEqual(moment().startOf('day').format("dddd MMM Do YYYY"));
|
||||
expect($(chat_content).find('div.chat-info').length).toBe(4);
|
||||
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
|
||||
expect($(chat_content).find('div.chat-info:last').html()).toBe(
|
||||
'some1 has left the room. '+
|
||||
'"Disconnected: Replaced by new connection"');
|
||||
@ -713,14 +714,14 @@
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
var $time = $chat_content.find('time');
|
||||
expect($time.length).toEqual(4);
|
||||
let time = chat_content.querySelectorAll('time.separator-text');
|
||||
expect(time.length).toEqual(4);
|
||||
|
||||
var $indicator = $chat_content.find('.date-separator:eq(3)');
|
||||
expect($indicator.attr('class')).toEqual('message date-separator');
|
||||
expect($indicator.data('isodate')).toEqual(moment().startOf('day').format());
|
||||
expect($indicator.find('time').text()).toEqual(moment().startOf('day').format("dddd MMM Do YYYY"));
|
||||
expect($chat_content.find('div.chat-info').length).toBe(5);
|
||||
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(4);
|
||||
expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the room");
|
||||
|
||||
jasmine.clock().tick(ONE_DAY_LATER);
|
||||
@ -752,15 +753,15 @@
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
$time = $chat_content.find('time');
|
||||
expect($time.length).toEqual(6);
|
||||
time = chat_content.querySelectorAll('time.separator-text');
|
||||
expect(time.length).toEqual(6);
|
||||
|
||||
$indicator = $chat_content.find('.date-separator:eq(5)');
|
||||
expect($indicator.attr('class')).toEqual('message date-separator');
|
||||
expect($indicator.data('isodate')).toEqual(moment().startOf('day').format());
|
||||
|
||||
expect($indicator.find('time').text()).toEqual(moment().startOf('day').format("dddd MMM Do YYYY"));
|
||||
expect($chat_content.find('div.chat-info').length).toBe(6);
|
||||
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(5);
|
||||
expect($chat_content.find('div.chat-info:last').html()).toBe(
|
||||
'newguy has left the room. '+
|
||||
'"Disconnected: Replaced by new connection"');
|
||||
@ -813,9 +814,8 @@
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||
.c('value').t(0);
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
test_utils.waitUntil(function () {
|
||||
return _.get(view.el.querySelector('.chatroom-description'), 'textContent');
|
||||
}).then(function () {
|
||||
test_utils.waitUntil(() => _.get(view.el.querySelector('.chatroom-description'), 'textContent'))
|
||||
.then(function () {
|
||||
expect($(view.el.querySelector('.chatroom-description')).text()).toBe('This is the description');
|
||||
done();
|
||||
});
|
||||
@ -1113,7 +1113,7 @@
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}));
|
||||
|
||||
it("shows users currently present in the room",
|
||||
it("shows all members even if they're not currently present in the room",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
@ -1145,6 +1145,61 @@
|
||||
expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(mock.chatroom_names[i]);
|
||||
}
|
||||
|
||||
// Test users leaving the room
|
||||
// http://xmpp.org/extensions/xep-0045.html#exit
|
||||
for (i=mock.chatroom_names.length-1; i>-1; i--) {
|
||||
name = mock.chatroom_names[i];
|
||||
role = mock.chatroom_roles[name].role;
|
||||
// See example 21 http://xmpp.org/extensions/xep-0045.html#enter-pres
|
||||
presence = $pres({
|
||||
to:'dummy@localhost/pda',
|
||||
from:'lounge@localhost/'+name,
|
||||
type: 'unavailable'
|
||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||
.c('item').attrs({
|
||||
affiliation: mock.chatroom_roles[name].affiliation,
|
||||
jid: name.replace(/ /g,'.').toLowerCase() + '@localhost',
|
||||
role: 'none'
|
||||
}).nodeTree;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
expect(occupants.querySelectorAll('li').length).toBe(7);
|
||||
}
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
|
||||
it("shows users currently present in the room",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.openAndEnterChatRoom(_converse, 'lounge', 'localhost', 'dummy').then(function() {
|
||||
var name;
|
||||
var view = _converse.chatboxviews.get('lounge@localhost'),
|
||||
occupants = view.el.querySelector('.occupant-list');
|
||||
var presence, role, jid, model;
|
||||
for (var i=0; i<mock.chatroom_names.length; i++) {
|
||||
name = mock.chatroom_names[i];
|
||||
role = mock.chatroom_roles[name].role;
|
||||
// See example 21 http://xmpp.org/extensions/xep-0045.html#enter-pres
|
||||
jid =
|
||||
presence = $pres({
|
||||
to:'dummy@localhost/pda',
|
||||
from:'lounge@localhost/'+name
|
||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||
.c('item').attrs({
|
||||
affiliation: 'none',
|
||||
jid: name.replace(/ /g,'.').toLowerCase() + '@localhost',
|
||||
role: role
|
||||
}).up()
|
||||
.c('status').attrs({code:'110'}).nodeTree;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
expect(occupants.querySelectorAll('li').length).toBe(2+i);
|
||||
model = view.occupantsview.model.where({'nick': name})[0];
|
||||
var index = view.occupantsview.model.indexOf(model);
|
||||
expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(mock.chatroom_names[i]);
|
||||
}
|
||||
|
||||
// Test users leaving the room
|
||||
// http://xmpp.org/extensions/xep-0045.html#exit
|
||||
for (i=mock.chatroom_names.length-1; i>-1; i--) {
|
||||
@ -1710,7 +1765,11 @@
|
||||
.c('status').attrs({code:'110'}).nodeTree;
|
||||
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
expect($chat_content.find('div.chat-info').length).toBe(2);
|
||||
// XXX: currently we still have an additional "has entered the room"
|
||||
// notification for the new nickname. Ideally we'd not have
|
||||
// that, but that's probably not possible without some
|
||||
// significant refactoring.
|
||||
expect($chat_content.find('div.chat-info').length).toBe(3);
|
||||
expect($chat_content.find('div.chat-info').get(1).textContent).toBe(
|
||||
__(_converse.muc.new_nickname_messages["303"], "newnick")
|
||||
);
|
||||
@ -1741,6 +1800,8 @@
|
||||
"<query xmlns='http://jabber.org/protocol/disco#info'/>"+
|
||||
"</iq>");
|
||||
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
spyOn(view.model, 'parseRoomFeatures').and.callThrough();
|
||||
/* <iq from='coven@chat.shakespeare.lit'
|
||||
* id='ik3vs715'
|
||||
* to='hag66@shakespeare.lit/pda'
|
||||
@ -1780,16 +1841,17 @@
|
||||
.c('feature', {'var': 'muc_unmoderated'}).up()
|
||||
.c('feature', {'var': 'muc_nonanonymous'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
expect(view.model.get('features_fetched')).toBe(true);
|
||||
expect(view.model.get('passwordprotected')).toBe(true);
|
||||
expect(view.model.get('hidden')).toBe(true);
|
||||
expect(view.model.get('temporary')).toBe(true);
|
||||
expect(view.model.get('open')).toBe(true);
|
||||
expect(view.model.get('unmoderated')).toBe(true);
|
||||
expect(view.model.get('nonanonymous')).toBe(true);
|
||||
done();
|
||||
test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300)
|
||||
.then(() => {
|
||||
expect(view.model.get('features_fetched')).toBeTruthy();
|
||||
expect(view.model.get('passwordprotected')).toBe(true);
|
||||
expect(view.model.get('hidden')).toBe(true);
|
||||
expect(view.model.get('temporary')).toBe(true);
|
||||
expect(view.model.get('open')).toBe(true);
|
||||
expect(view.model.get('unmoderated')).toBe(true);
|
||||
expect(view.model.get('nonanonymous')).toBe(true);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("updates the shown features when the room configuration has changed",
|
||||
@ -2888,6 +2950,7 @@
|
||||
|
||||
var muc_iq;
|
||||
var sent_IQs = [], IQ_ids = [];
|
||||
var invitee_jid, sent_stanza, sent_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_IQs.push(iq);
|
||||
@ -2896,6 +2959,9 @@
|
||||
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'dummy'});
|
||||
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
spyOn(view.model, 'parseRoomFeatures').and.callThrough();
|
||||
|
||||
// State that the chat is members-only via the features IQ
|
||||
var features_stanza = $iq({
|
||||
from: 'coven@chat.shakespeare.lit',
|
||||
@ -2915,111 +2981,102 @@
|
||||
.c('feature', {'var': 'muc_membersonly'}).up();
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
var view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
expect(view.model.get('membersonly')).toBeTruthy();
|
||||
test_utils.waitUntil(() => view.model.parseRoomFeatures.calls.count(), 300)
|
||||
.then(() => {
|
||||
expect(view.model.get('membersonly')).toBeTruthy();
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
|
||||
var sent_stanza, sent_id;
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
if (stanza.nodeTree && stanza.nodeTree.nodeName === 'message') {
|
||||
sent_id = stanza.nodeTree.getAttribute('id');
|
||||
sent_stanza = stanza;
|
||||
}
|
||||
});
|
||||
var name = mock.cur_names[0];
|
||||
var invitee_jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var reason = "Please join this chat room";
|
||||
view.model.directInvite(invitee_jid, reason);
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
if (stanza.nodeTree && stanza.nodeTree.nodeName === 'message') {
|
||||
sent_id = stanza.nodeTree.getAttribute('id');
|
||||
sent_stanza = stanza;
|
||||
}
|
||||
});
|
||||
var name = mock.cur_names[0];
|
||||
invitee_jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var reason = "Please join this chat room";
|
||||
view.model.directInvite(invitee_jid, reason);
|
||||
|
||||
// Check in reverse order that we requested all three lists
|
||||
// (member, owner and admin).
|
||||
var admin_iq_id = IQ_ids.pop();
|
||||
var owner_iq_id = IQ_ids.pop();
|
||||
var member_iq_id = IQ_ids.pop();
|
||||
// Check in reverse order that we requested all three lists
|
||||
// (member, owner and admin).
|
||||
var admin_iq_id = IQ_ids.pop();
|
||||
var owner_iq_id = IQ_ids.pop();
|
||||
var member_iq_id = IQ_ids.pop();
|
||||
|
||||
expect(sent_IQs.pop().toLocaleString()).toBe(
|
||||
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+admin_iq_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
"<item affiliation='admin'/>"+
|
||||
"</query>"+
|
||||
"</iq>");
|
||||
expect(sent_IQs.pop().toLocaleString()).toBe(
|
||||
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+owner_iq_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
"<item affiliation='owner'/>"+
|
||||
"</query>"+
|
||||
"</iq>");
|
||||
expect(sent_IQs.pop().toLocaleString()).toBe(
|
||||
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+member_iq_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
"<item affiliation='member'/>"+
|
||||
"</query>"+
|
||||
"</iq>");
|
||||
expect(sent_IQs.pop().toLocaleString()).toBe(
|
||||
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+admin_iq_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
"<item affiliation='admin'/>"+
|
||||
"</query>"+
|
||||
"</iq>");
|
||||
expect(sent_IQs.pop().toLocaleString()).toBe(
|
||||
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+owner_iq_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
"<item affiliation='owner'/>"+
|
||||
"</query>"+
|
||||
"</iq>");
|
||||
expect(sent_IQs.pop().toLocaleString()).toBe(
|
||||
"<iq to='coven@chat.shakespeare.lit' type='get' xmlns='jabber:client' id='"+member_iq_id+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
"<item affiliation='member'/>"+
|
||||
"</query>"+
|
||||
"</iq>");
|
||||
|
||||
/* Now the service sends the member list to the user
|
||||
*
|
||||
* <iq from='coven@chat.shakespeare.lit'
|
||||
* id='member3'
|
||||
* to='crone1@shakespeare.lit/desktop'
|
||||
* type='result'>
|
||||
* <query xmlns='http://jabber.org/protocol/muc#admin'>
|
||||
* <item affiliation='member'
|
||||
* jid='hag66@shakespeare.lit'
|
||||
* nick='thirdwitch'
|
||||
* role='participant'/>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
var member_list_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': member_iq_id,
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'result'
|
||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||
.c('item', {
|
||||
'affiliation': 'member',
|
||||
'jid': 'hag66@shakespeare.lit',
|
||||
'nick': 'thirdwitch',
|
||||
'role': 'participant'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(member_list_stanza));
|
||||
/* Now the service sends the member list to the user
|
||||
*
|
||||
* <iq from='coven@chat.shakespeare.lit'
|
||||
* id='member3'
|
||||
* to='crone1@shakespeare.lit/desktop'
|
||||
* type='result'>
|
||||
* <query xmlns='http://jabber.org/protocol/muc#admin'>
|
||||
* <item affiliation='member'
|
||||
* jid='hag66@shakespeare.lit'
|
||||
* nick='thirdwitch'
|
||||
* role='participant'/>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
var member_list_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': member_iq_id,
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'result'
|
||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||
.c('item', {
|
||||
'affiliation': 'member',
|
||||
'jid': 'hag66@shakespeare.lit',
|
||||
'nick': 'thirdwitch',
|
||||
'role': 'participant'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(member_list_stanza));
|
||||
|
||||
var admin_list_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': admin_iq_id,
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'result'
|
||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||
.c('item', {
|
||||
'affiliation': 'admin',
|
||||
'jid': 'wiccarocks@shakespeare.lit',
|
||||
'nick': 'secondwitch'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(admin_list_stanza));
|
||||
var admin_list_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': admin_iq_id,
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'result'
|
||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||
.c('item', {
|
||||
'affiliation': 'admin',
|
||||
'jid': 'wiccarocks@shakespeare.lit',
|
||||
'nick': 'secondwitch'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(admin_list_stanza));
|
||||
|
||||
var owner_list_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': owner_iq_id,
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'result'
|
||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||
.c('item', {
|
||||
'affiliation': 'owner',
|
||||
'jid': 'crone1@shakespeare.lit',
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(owner_list_stanza));
|
||||
test_utils.waitUntil(() => {
|
||||
return _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
(iq) => {
|
||||
if (iq.nodeTree.getAttribute('to') === 'coven@chat.shakespeare.lit' && iq.nodeTree.getAttribute('type') === 'set') {
|
||||
muc_iq = iq;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).length;
|
||||
}).then(function () {
|
||||
var owner_list_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': owner_iq_id,
|
||||
'to': 'dummy@localhost/resource',
|
||||
'type': 'result'
|
||||
}).c('query', {'xmlns': Strophe.NS.MUC_ADMIN})
|
||||
.c('item', {
|
||||
'affiliation': 'owner',
|
||||
'jid': 'crone1@shakespeare.lit',
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(owner_list_stanza));
|
||||
return test_utils.waitUntil(() => IQ_ids.length, 300);
|
||||
}).then(() => {
|
||||
// Check that the member list now gets updated
|
||||
expect(muc_iq.toLocaleString()).toBe("<iq to='coven@chat.shakespeare.lit' type='set' xmlns='jabber:client' id='"+muc_iq.nodeTree.getAttribute('id')+"'>"+
|
||||
"<query xmlns='http://jabber.org/protocol/muc#admin'>"+
|
||||
@ -3112,7 +3169,7 @@
|
||||
|
||||
test_utils.openControlBox();
|
||||
var roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
|
||||
roomspanel.el.querySelector('.trigger-add-chatrooms-modal').click();
|
||||
roomspanel.el.querySelector('.show-add-muc-modal').click();
|
||||
test_utils.closeControlBox(_converse);
|
||||
const modal = roomspanel.add_room_modal;
|
||||
test_utils.waitUntil(function () {
|
||||
@ -3147,7 +3204,7 @@
|
||||
|
||||
test_utils.openControlBox();
|
||||
var roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
|
||||
roomspanel.el.querySelector('.trigger-list-chatrooms-modal').click();
|
||||
roomspanel.el.querySelector('.show-list-muc-modal').click();
|
||||
test_utils.closeControlBox(_converse);
|
||||
const modal = roomspanel.list_rooms_modal;
|
||||
test_utils.waitUntil(function () {
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $pres = converse.env.$pres;
|
||||
var $msg = converse.env.$msg;
|
||||
|
@ -2,10 +2,9 @@
|
||||
define([
|
||||
"jquery",
|
||||
"jasmine",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"], factory);
|
||||
} (this, function ($, jasmine, converse, mock, test_utils) {
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var b64_sha1 = converse.env.b64_sha1;
|
||||
var _ = converse.env._;
|
||||
|
||||
|
@ -2,10 +2,9 @@
|
||||
define([
|
||||
"jasmine",
|
||||
"jquery",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"], factory);
|
||||
} (this, function (jasmine, $, converse, mock, test_utils) {
|
||||
} (this, function (jasmine, $, mock, test_utils) {
|
||||
"use strict";
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $iq = converse.env.$iq;
|
||||
@ -15,7 +14,11 @@
|
||||
|
||||
describe("Whenever converse.js queries a server for its features", function () {
|
||||
|
||||
it("stores the features it receives", mock.initConverseWithAsync(function (done, _converse) {
|
||||
it("stores the features it receives",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['discoInitialized'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
var IQ_ids = _converse.connection.IQ_ids;
|
||||
test_utils.waitUntil(function () {
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, converse, test_utils) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
|
||||
return describe("The _converse Event Emitter", function() {
|
||||
|
||||
|
@ -2,15 +2,14 @@
|
||||
define([
|
||||
"jasmine",
|
||||
"jquery",
|
||||
"converse-core",
|
||||
"utils",
|
||||
"mock",
|
||||
"test-utils"
|
||||
], factory);
|
||||
} (this, function (jasmine, $, converse, utils, mock, test_utils) {
|
||||
} (this, function (jasmine, $, mock, test_utils) {
|
||||
"use strict";
|
||||
var $msg = converse.env.$msg,
|
||||
_ = converse.env._;
|
||||
_ = converse.env._,
|
||||
utils = converse.env.utils;
|
||||
|
||||
describe("A headlines box", function () {
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"jasmine",
|
||||
"jquery",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"], factory);
|
||||
} (this, function (jasmine, $, converse, mock, test_utils) {
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $iq = converse.env.$iq;
|
||||
@ -367,6 +365,7 @@
|
||||
}).then(function () {
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg-media').innerHTML.trim()).toEqual(
|
||||
'<!-- src/templates/image.html -->\n'+
|
||||
'<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">'+
|
||||
'<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg">'+
|
||||
'</a>');
|
||||
@ -474,6 +473,7 @@
|
||||
}).then(function () {
|
||||
// Check that the image renders
|
||||
expect(view.el.querySelector('.chat-msg .chat-msg-media').innerHTML.trim()).toEqual(
|
||||
'<!-- src/templates/image.html -->\n'+
|
||||
'<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">'+
|
||||
'<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg"></a>')
|
||||
XMLHttpRequest.prototype.send = send_backup;
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, converse, test_utils) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
|
||||
describe("The Login Form", function () {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, converse, test_utils) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var _ = converse.env._;
|
||||
var Backbone = converse.env.Backbone;
|
||||
|
@ -2,12 +2,10 @@
|
||||
define([
|
||||
"jquery",
|
||||
"jasmine",
|
||||
"utils",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"
|
||||
], factory);
|
||||
} (this, function ($, jasmine, utils, converse, mock, test_utils) {
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var _ = converse.env._;
|
||||
var $iq = converse.env.$iq;
|
||||
@ -62,7 +60,7 @@
|
||||
expect(msg_obj.get('message')).toEqual(message);
|
||||
expect(msg_obj.get('fullname')).toEqual(mock.cur_names[0]);
|
||||
expect(msg_obj.get('sender')).toEqual('them');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
var chat_content = chatboxview.el.querySelector('.chat-content');
|
||||
expect(chat_content.querySelector('.chat-msg .chat-msg-text').textContent).toEqual(message);
|
||||
@ -178,7 +176,7 @@
|
||||
expect(msg_obj.get('message')).toEqual(message);
|
||||
expect(msg_obj.get('fullname')).toEqual(undefined);
|
||||
expect(msg_obj.get('sender')).toEqual('them');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
var chat_content = chatboxview.el.querySelector('.chat-content');
|
||||
expect(chat_content.querySelector('.chat-msg .chat-msg-text').textContent).toEqual(message);
|
||||
@ -579,7 +577,7 @@
|
||||
expect($el.hasClass('chat-msg-followup')).toBe(false);
|
||||
expect($el.text()).toEqual('Older message');
|
||||
|
||||
$time = $chat_content.find('time:eq(1)');
|
||||
$time = $chat_content.find('time.separator-text:eq(1)');
|
||||
expect($time.text()).toEqual("Monday Jan 1st 2018");
|
||||
|
||||
$day = $chat_content.find('.date-separator:eq(1)');
|
||||
@ -593,7 +591,7 @@
|
||||
expect($el.find('.chat-msg-text').text()).toEqual('another inbetween message');
|
||||
expect($el.hasClass('chat-msg-followup')).toBe(true);
|
||||
|
||||
$time = $chat_content.find('time:nth(2)');
|
||||
$time = $chat_content.find('time.separator-text:nth(2)');
|
||||
expect($time.text()).toEqual("Tuesday Jan 2nd 2018");
|
||||
|
||||
$day = $chat_content.find('.date-separator:nth(2)');
|
||||
@ -630,7 +628,7 @@
|
||||
*/
|
||||
sinon.spy(_converse, 'log');
|
||||
sinon.spy(_converse.chatboxes, 'getChatBox');
|
||||
sinon.spy(utils, 'isHeadlineMessage');
|
||||
sinon.spy(u, 'isHeadlineMessage');
|
||||
var msg = $msg({
|
||||
from: 'localhost',
|
||||
to: _converse.bare_jid,
|
||||
@ -642,13 +640,13 @@
|
||||
"onMessage: Ignoring incoming headline message sent with type 'chat' from JID: localhost",
|
||||
Strophe.LogLevel.INFO
|
||||
)).toBeTruthy();
|
||||
expect(utils.isHeadlineMessage.called).toBeTruthy();
|
||||
expect(utils.isHeadlineMessage.returned(true)).toBeTruthy();
|
||||
expect(u.isHeadlineMessage.called).toBeTruthy();
|
||||
expect(u.isHeadlineMessage.returned(true)).toBeTruthy();
|
||||
expect(_converse.chatboxes.getChatBox.called).toBeFalsy();
|
||||
// Remove sinon spies
|
||||
_converse.log.restore();
|
||||
_converse.chatboxes.getChatBox.restore();
|
||||
utils.isHeadlineMessage.restore();
|
||||
u.isHeadlineMessage.restore();
|
||||
done();
|
||||
}));
|
||||
|
||||
@ -692,7 +690,7 @@
|
||||
expect(msg_obj.get('message')).toEqual(msgtext);
|
||||
expect(msg_obj.get('fullname')).toEqual(mock.cur_names[1]);
|
||||
expect(msg_obj.get('sender')).toEqual('them');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
var chat_content = chatboxview.el.querySelector('.chat-content');
|
||||
expect(chat_content.querySelector('.chat-msg .chat-msg-text').textContent).toEqual(msgtext);
|
||||
@ -745,7 +743,7 @@
|
||||
expect(msg_obj.get('message')).toEqual(msgtext);
|
||||
expect(msg_obj.get('fullname')).toEqual(_converse.xmppstatus.get('fullname'));
|
||||
expect(msg_obj.get('sender')).toEqual('me');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
// Now check that the message appears inside the chatbox in the DOM
|
||||
var $chat_content = $(chatboxview.el).find('.chat-content');
|
||||
var msg_txt = $chat_content.find('.chat-msg').find('.chat-msg-text').text();
|
||||
@ -901,7 +899,7 @@
|
||||
expect(msg_obj.get('message')).toEqual(message);
|
||||
expect(msg_obj.get('fullname')).toEqual(contact_name);
|
||||
expect(msg_obj.get('sender')).toEqual('them');
|
||||
expect(msg_obj.get('delayed')).toEqual(true);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(true);
|
||||
|
||||
return test_utils.waitUntil(() => chatbox.vcard.get('fullname') === 'Candice van der Knijff')
|
||||
.then(function () {
|
||||
@ -930,7 +928,7 @@
|
||||
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
// Check that there is a <time> element, with the required
|
||||
// props.
|
||||
expect($chat_content[0].querySelectorAll('time').length).toEqual(2); // There are now two time elements
|
||||
expect($chat_content[0].querySelectorAll('time.separator-text').length).toEqual(2); // There are now two time elements
|
||||
|
||||
var message_date = new Date();
|
||||
$day = $chat_content.find('.date-separator:last');
|
||||
@ -947,7 +945,7 @@
|
||||
expect(msg_obj.get('message')).toEqual(message);
|
||||
expect(msg_obj.get('fullname')).toEqual(contact_name);
|
||||
expect(msg_obj.get('sender')).toEqual('them');
|
||||
expect(msg_obj.get('delayed')).toEqual(false);
|
||||
expect(msg_obj.get('is_delayed')).toEqual(false);
|
||||
msg_txt = $chat_content.find('.chat-msg').last().find('.chat-msg-text').text();
|
||||
expect(msg_txt).toEqual(message);
|
||||
|
||||
@ -1069,6 +1067,43 @@
|
||||
done();
|
||||
}));
|
||||
|
||||
it("will render newlines", mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
let stanza = Strophe.xmlHtmlNode(
|
||||
"<message from='"+contact_jid+"'"+
|
||||
" type='chat'"+
|
||||
" to='dummy@localhost/resource'>"+
|
||||
" <body>Hey\nHave you heard the news?</body>"+
|
||||
"</message>").firstChild;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const chat_content = view.el.querySelector('.chat-content');
|
||||
expect(chat_content.querySelector('.chat-msg-text').innerHTML).toBe('Hey<br>Have you heard the news?');
|
||||
|
||||
stanza = Strophe.xmlHtmlNode(
|
||||
"<message from='"+contact_jid+"'"+
|
||||
" type='chat'"+
|
||||
" to='dummy@localhost/resource'>"+
|
||||
" <body>Hey\n\n\nHave you heard the news?</body>"+
|
||||
"</message>").firstChild;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(chat_content.querySelector('.message:last-child .chat-msg-text').innerHTML).toBe('Hey<br><br>Have you heard the news?');
|
||||
|
||||
stanza = Strophe.xmlHtmlNode(
|
||||
"<message from='"+contact_jid+"'"+
|
||||
" type='chat'"+
|
||||
" to='dummy@localhost/resource'>"+
|
||||
" <body>Hey\nHave you heard\nthe news?</body>"+
|
||||
"</message>").firstChild;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(chat_content.querySelector('.message:last-child .chat-msg-text').innerHTML).toBe('Hey<br>Have you heard<br>the news?');
|
||||
done();
|
||||
}));
|
||||
|
||||
it("will render images from their URLs",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
@ -1083,12 +1118,12 @@
|
||||
spyOn(view.model, 'sendMessage').and.callThrough();
|
||||
test_utils.sendMessage(view, message);
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return view.el.querySelectorAll('.chat-content .chat-image').length;
|
||||
}, 1000).then(function () {
|
||||
test_utils.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length)
|
||||
.then(() => {
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
var msg = $(view.el).find('.chat-content .chat-msg').last().find('.chat-msg-text');
|
||||
expect(msg.html().trim()).toEqual(
|
||||
'<!-- src/templates/image.html -->\n'+
|
||||
'<a href="'+base_url+'/logo/conversejs-filled.svg" target="_blank" rel="noopener"><img class="chat-image img-thumbnail"'+
|
||||
' src="' + message + '"></a>');
|
||||
message += "?param1=val1¶m2=val2";
|
||||
@ -1096,10 +1131,11 @@
|
||||
return test_utils.waitUntil(function () {
|
||||
return view.el.querySelectorAll('.chat-content .chat-image').length === 2;
|
||||
}, 1000);
|
||||
}).then(function () {
|
||||
}).then(() => {
|
||||
expect(view.model.sendMessage).toHaveBeenCalled();
|
||||
var msg = $(view.el).find('.chat-content').find('.chat-msg').last().find('.chat-msg-text');
|
||||
expect(msg.html().trim()).toEqual(
|
||||
'<!-- src/templates/image.html -->\n'+
|
||||
'<a href="'+base_url+'/logo/conversejs-filled.svg?param1=val1&param2=val2" target="_blank" rel="noopener"><img'+
|
||||
' class="chat-image img-thumbnail" src="'+message.replace(/&/g, '&')+'"></a>')
|
||||
|
||||
@ -1342,6 +1378,7 @@
|
||||
expect(msg.outerHTML).toEqual('<span class="chat-msg-text">Have you heard this funny audio?</span>');
|
||||
var media = view.el.querySelector('.chat-msg .chat-msg-media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/audio.html -->'+
|
||||
'<audio controls=""><source src="http://localhost/audio.mp3" type="audio/mpeg"></audio>'+
|
||||
'<a target="_blank" rel="noopener" href="http://localhost/audio.mp3">Download audio file</a>');
|
||||
|
||||
@ -1359,6 +1396,7 @@
|
||||
expect(msg.innerHTML).toEqual('');
|
||||
media = view.el.querySelector('.chat-msg:last-child .chat-msg-media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/audio.html -->'+
|
||||
'<audio controls=""><source src="http://localhost/audio.mp3" type="audio/mpeg"></audio>'+
|
||||
'<a target="_blank" rel="noopener" href="http://localhost/audio.mp3">Download audio file</a>');
|
||||
done();
|
||||
@ -1392,6 +1430,7 @@
|
||||
expect(msg.outerHTML).toEqual('<span class="chat-msg-text">Have you seen this funny video?</span>');
|
||||
var media = view.el.querySelector('.chat-msg .chat-msg-media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/video.html -->'+
|
||||
'<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>'+
|
||||
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
|
||||
|
||||
@ -1409,6 +1448,7 @@
|
||||
expect(msg.innerHTML).toEqual('');
|
||||
media = view.el.querySelector('.chat-msg:last-child .chat-msg-media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/video.html -->'+
|
||||
'<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>'+
|
||||
'<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>');
|
||||
done();
|
||||
@ -1442,6 +1482,7 @@
|
||||
expect(msg.outerHTML).toEqual('<span class="chat-msg-text">Have you downloaded this funny file?</span>');
|
||||
var media = view.el.querySelector('.chat-msg .chat-msg-media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/file.html -->'+
|
||||
'<a target="_blank" rel="noopener" href="http://localhost/funny.pdf">Download: "funny.pdf</a>');
|
||||
done();
|
||||
});
|
||||
@ -1476,6 +1517,7 @@
|
||||
expect(msg.outerHTML).toEqual('<span class="chat-msg-text">Have you seen this funny image?</span>');
|
||||
var media = view.el.querySelector('.chat-msg .chat-msg-media');
|
||||
expect(media.innerHTML.replace(/(\r\n|\n|\r)/gm, "")).toEqual(
|
||||
'<!-- src/templates/image.html -->'+
|
||||
'<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">'+
|
||||
'<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg">'+
|
||||
'</a>');
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $msg = converse.env.$msg;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils", "utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils, utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var _ = converse.env._;
|
||||
var $msg = converse.env.$msg;
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, converse, test_utils) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
var Strophe = converse.env.Strophe;
|
||||
var b64_sha1 = converse.env.b64_sha1;
|
||||
var $iq = converse.env.$iq;
|
||||
|
144
spec/otr.js
144
spec/otr.js
@ -1,72 +1,108 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var Strophe = converse.env.Strophe;
|
||||
var b64_sha1 = converse.env.b64_sha1;
|
||||
var $pres = converse.env.$pres;
|
||||
var _ = converse.env._;
|
||||
|
||||
describe("A chatbox with an active OTR session", function() {
|
||||
|
||||
it("will not show the spoiler toolbar button",
|
||||
describe("A chatbox", function() {
|
||||
|
||||
it("contains a button for starting an encrypted chat session",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var timeout = true, $toolbar, view;
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openControlBox();
|
||||
|
||||
// XXX: We need to send a presence from the contact, so that we
|
||||
// have a resource, that resource is then queried to see
|
||||
// whether Strophe.NS.SPOILER is supported, in which case
|
||||
// the spoiler button will appear.
|
||||
var presence = $pres({
|
||||
'from': contact_jid+'/phone',
|
||||
'to': 'dummy@localhost'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group').length;
|
||||
}, 300).then(function () {
|
||||
// TODO: More tests can be added here...
|
||||
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
view = _converse.chatboxviews.get(contact_jid);
|
||||
$toolbar = $(view.el).find('ul.chat-toolbar');
|
||||
expect($toolbar.find('.toggle-otr').length).toBe(1);
|
||||
// Register spies
|
||||
spyOn(view, 'toggleOTRMenu').and.callThrough();
|
||||
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
|
||||
var spoiler_toggle;
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view, 'addSpoilerButton').and.callThrough();
|
||||
view.model.set('otr_status', 1);
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return _.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).toBe(null);
|
||||
|
||||
view.model.set('otr_status', 3);
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
});
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).not.toBe(null);
|
||||
|
||||
view.model.set('otr_status', 2);
|
||||
return test_utils.waitUntil(function () {
|
||||
return _.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
});
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).toBe(null);
|
||||
|
||||
view.model.set('otr_status', 4);
|
||||
return test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
});
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).not.toBe(null);
|
||||
done();
|
||||
});
|
||||
timeout = false;
|
||||
$toolbar[0].querySelector('.toggle-otr').click();
|
||||
return test_utils.waitUntil(function () {
|
||||
return view.el.querySelector('.otr-menu').offsetHeight;
|
||||
}, 300)
|
||||
}).then(function () {
|
||||
expect(view.toggleOTRMenu).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
describe("with an active OTR session", function() {
|
||||
|
||||
it("will not show the spoiler toolbar button",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
|
||||
// XXX: We need to send a presence from the contact, so that we
|
||||
// have a resource, that resource is then queried to see
|
||||
// whether Strophe.NS.SPOILER is supported, in which case
|
||||
// the spoiler button will appear.
|
||||
var presence = $pres({
|
||||
'from': contact_jid+'/phone',
|
||||
'to': 'dummy@localhost'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, contact_jid+'/phone', [], [Strophe.NS.SPOILER]).then(function () {
|
||||
var spoiler_toggle;
|
||||
var view = _converse.chatboxviews.get(contact_jid);
|
||||
spyOn(view, 'addSpoilerButton').and.callThrough();
|
||||
view.model.set('otr_status', 1);
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return _.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).toBe(null);
|
||||
|
||||
view.model.set('otr_status', 3);
|
||||
|
||||
return test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
});
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).not.toBe(null);
|
||||
|
||||
view.model.set('otr_status', 2);
|
||||
return test_utils.waitUntil(function () {
|
||||
return _.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
});
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).toBe(null);
|
||||
|
||||
view.model.set('otr_status', 4);
|
||||
return test_utils.waitUntil(function () {
|
||||
return !_.isNull(view.el.querySelector('.toggle-compose-spoiler'));
|
||||
});
|
||||
}).then(function () {
|
||||
spoiler_toggle = view.el.querySelector('.toggle-compose-spoiler');
|
||||
expect(spoiler_toggle).not.toBe(null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("The OTR module", function() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "test-utils", "converse-ping"], factory);
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
|
||||
|
@ -4,15 +4,15 @@
|
||||
define([
|
||||
"jasmine",
|
||||
"jquery",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils",
|
||||
"lodash"], factory);
|
||||
} (this, function (jasmine, $, converse, mock, test_utils, _) {
|
||||
], factory);
|
||||
} (this, function (jasmine, $, mock, test_utils) {
|
||||
"use strict";
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $iq = converse.env.$iq;
|
||||
var $pres = converse.env.$pres;
|
||||
var _ = converse.env._;
|
||||
var u = converse.env.utils;
|
||||
// See: https://xmpp.org/rfcs/rfc3921.html
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "test-utils", "utils"], factory);
|
||||
} (this, function (jasmine, mock, converse, test_utils, u) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $iq = converse.env.$iq;
|
||||
var u = converse.env.utils;
|
||||
|
||||
describe("Profiling", function() {
|
||||
xit("adds hundreds of contacts to the roster",
|
||||
|
@ -2,10 +2,9 @@
|
||||
define([
|
||||
"jasmine",
|
||||
"jquery",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"], factory);
|
||||
} (this, function (jasmine, $, converse, mock, test_utils) {
|
||||
} (this, function (jasmine, $, mock, test_utils) {
|
||||
"use strict";
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $iq = converse.env.$iq;
|
||||
@ -210,7 +209,7 @@
|
||||
* </iq>
|
||||
*/
|
||||
spyOn(_converse.roster, "updateContact").and.callThrough();
|
||||
stanza = $iq({'type': 'set', 'from': 'dummy@localhost'})
|
||||
stanza = $iq({'type': 'set', 'from': _converse.connection.jid})
|
||||
.c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
|
164
spec/push.js
Normal file
164
spec/push.js
Normal file
@ -0,0 +1,164 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var $iq = converse.env.$iq;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var _ = converse.env._;
|
||||
|
||||
describe("XEP-0357 Push Notifications", function () {
|
||||
|
||||
it("can be enabled",
|
||||
mock.initConverseWithPromises(null,
|
||||
['rosterGroupsFetched'], {
|
||||
'push_app_servers': [{
|
||||
'jid': 'push-5@client.example',
|
||||
'node': 'yxs32uqsflafdk3iuqo'
|
||||
}]
|
||||
}, function (done, _converse) {
|
||||
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let stanza;
|
||||
|
||||
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.push_app_servers[0].jid,
|
||||
[{'category': 'pubsub', 'type':'push'}],
|
||||
['urn:xmpp:push:0'], [], 'info')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(
|
||||
_converse,
|
||||
_converse.bare_jid,
|
||||
[{'category': 'account', 'type':'registered'}],
|
||||
['urn:xmpp:push:0'], [], 'info'))
|
||||
.then(() => {
|
||||
return test_utils.waitUntil(() => {
|
||||
const node = _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]');
|
||||
}).pop();
|
||||
if (node) {
|
||||
stanza = node.nodeTree;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
}).then(() => {
|
||||
expect(stanza.outerHTML).toEqual(
|
||||
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
|
||||
'<enable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo"/>'+
|
||||
'</iq>'
|
||||
)
|
||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
})));
|
||||
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
|
||||
}).then(() => {
|
||||
done();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}));
|
||||
|
||||
it("can be disabled",
|
||||
mock.initConverseWithPromises(null,
|
||||
['rosterGroupsFetched'], {
|
||||
'push_app_servers': [{
|
||||
'jid': 'push-5@client.example',
|
||||
'node': 'yxs32uqsflafdk3iuqo',
|
||||
'disable': true
|
||||
}]
|
||||
}, function (done, _converse) {
|
||||
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let stanza;
|
||||
|
||||
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse,
|
||||
_converse.bare_jid,
|
||||
[{'category': 'account', 'type':'registered'}],
|
||||
['urn:xmpp:push:0'], [], 'info')
|
||||
.then(() => {
|
||||
return test_utils.waitUntil(() => {
|
||||
const node = _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[type="set"] disable[xmlns="urn:xmpp:push:0"]');
|
||||
}).pop();
|
||||
if (node) {
|
||||
stanza = node.nodeTree;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
}).then(() => {
|
||||
expect(stanza.outerHTML).toEqual(
|
||||
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
|
||||
'<disable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo"/>'+
|
||||
'</iq>'
|
||||
)
|
||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
})));
|
||||
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
|
||||
}).then(() => {
|
||||
done();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}));
|
||||
|
||||
|
||||
it("can require a secret token to be included",
|
||||
mock.initConverseWithPromises(null,
|
||||
['rosterGroupsFetched'], {
|
||||
'push_app_servers': [{
|
||||
'jid': 'push-5@client.example',
|
||||
'node': 'yxs32uqsflafdk3iuqo',
|
||||
'secret': 'eruio234vzxc2kla-91'
|
||||
}]
|
||||
}, function (done, _converse) {
|
||||
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
let stanza;
|
||||
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||
|
||||
test_utils.waitUntilDiscoConfirmed(
|
||||
_converse, _converse.push_app_servers[0].jid,
|
||||
[{'category': 'pubsub', 'type':'push'}],
|
||||
['urn:xmpp:push:0'], [], 'info')
|
||||
.then(() => test_utils.waitUntilDiscoConfirmed(
|
||||
_converse,
|
||||
_converse.bare_jid,
|
||||
[{'category': 'account', 'type':'registered'}],
|
||||
['urn:xmpp:push:0'], [], 'info'))
|
||||
.then(() => {
|
||||
return test_utils.waitUntil(() => {
|
||||
const node = _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]');
|
||||
}).pop();
|
||||
if (node) {
|
||||
stanza = node.nodeTree;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
}).then(() => {
|
||||
expect(stanza.outerHTML).toEqual(
|
||||
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
|
||||
'<enable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo">'+
|
||||
'<x xmlns="jabber:x:data" type="submit">'+
|
||||
'<field var="FORM_TYPE"><value>http://jabber.org/protocol/pubsub#publish-options</value></field>'+
|
||||
'<field var="secret"><value>eruio234vzxc2kla-91</value></field>'+
|
||||
'</x>'+
|
||||
'</enable>'+
|
||||
'</iq>'
|
||||
)
|
||||
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
})));
|
||||
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
|
||||
}).then(() => {
|
||||
done();
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}));
|
||||
});
|
||||
}));
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $iq = converse.env.$iq;
|
||||
var _ = converse.env._;
|
||||
@ -264,10 +264,24 @@
|
||||
registerview.el.querySelector('input[type=submit]').click();
|
||||
|
||||
expect(_converse.connection.send).toHaveBeenCalled();
|
||||
var $stanza = $(_converse.connection.send.calls.argsFor(0)[0].tree());
|
||||
expect($stanza.children('query').children().length).toBe(1);
|
||||
expect($stanza.children('query').children().children().length).toBe(3);
|
||||
expect($stanza.children('query').children().children()[0].tagName).toBe('field');
|
||||
stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
|
||||
expect(stanza.outerHTML.trim().replace(/(\n|\s{2,})/g, '')).toEqual(
|
||||
'<iq type="set" id="'+stanza.getAttribute('id')+'" xmlns="jabber:client">'+
|
||||
'<query xmlns="jabber:iq:register">'+
|
||||
'<x xmlns="jabber:x:data" type="submit">'+
|
||||
'<field xmlns="http://www.w3.org/1999/xhtml" var="username">'+
|
||||
'<value>testusername</value>'+
|
||||
'</field>'+
|
||||
'<field xmlns="http://www.w3.org/1999/xhtml" var="password">'+
|
||||
'<value>testpassword</value>'+
|
||||
'</field>'+
|
||||
'<field xmlns="http://www.w3.org/1999/xhtml" var="email">'+
|
||||
'<value>test@email.local</value>'+
|
||||
'</field>'+
|
||||
'</x>'+
|
||||
'</query>'+
|
||||
'</iq>'
|
||||
);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
@ -1,13 +1,17 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "mock", "converse-core", "converse-roomslist", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, converse, roomslist, test_utils) {
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var $msg = converse.env.$msg;
|
||||
var $iq = converse.env.$iq;
|
||||
var $pres = converse.env.$pres;
|
||||
var Promise = converse.env.Promise;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var u = converse.env.utils;
|
||||
|
||||
describe("The converse-roomslist plugin", function () {
|
||||
describe("A list of open rooms", function () {
|
||||
|
||||
it("is shown under a list of open rooms in the \"Rooms\" panel", mock.initConverseWithPromises(
|
||||
it("is shown in the \"Rooms\" panel", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
{ allow_bookmarks: false // Makes testing easier, otherwise we
|
||||
// have to mock stanza traffic.
|
||||
@ -50,7 +54,104 @@
|
||||
));
|
||||
});
|
||||
|
||||
describe("An room shown in the rooms list", function () {
|
||||
describe("A room shown in the rooms list", function () {
|
||||
|
||||
it("has an info icon which opens a details modal when clicked", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
{ whitelisted_plugins: ['converse-roomslist'],
|
||||
allow_bookmarks: false // Makes testing easier, otherwise we
|
||||
// have to mock stanza traffic.
|
||||
}, function (done, _converse) {
|
||||
|
||||
test_utils.openControlBox();
|
||||
_converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
|
||||
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
|
||||
const last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
|
||||
const IQ_id = last_stanza.getAttribute('id');
|
||||
const features_stanza = $iq({
|
||||
'from': 'coven@chat.shakespeare.lit',
|
||||
'id': IQ_id,
|
||||
'to': 'dummy@localhost/desktop',
|
||||
'type': 'result'
|
||||
})
|
||||
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||
.c('identity', {
|
||||
'category': 'conference',
|
||||
'name': 'A Dark Cave',
|
||||
'type': 'text'
|
||||
}).up()
|
||||
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
|
||||
.c('feature', {'var': 'muc_passwordprotected'}).up()
|
||||
.c('feature', {'var': 'muc_hidden'}).up()
|
||||
.c('feature', {'var': 'muc_temporary'}).up()
|
||||
.c('feature', {'var': 'muc_open'}).up()
|
||||
.c('feature', {'var': 'muc_unmoderated'}).up()
|
||||
.c('feature', {'var': 'muc_nonanonymous'}).up()
|
||||
.c('feature', {'var': 'urn:xmpp:mam:0'}).up()
|
||||
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
|
||||
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
|
||||
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
|
||||
.c('value').t('This is the description').up().up()
|
||||
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
|
||||
.c('value').t(0);
|
||||
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
|
||||
|
||||
test_utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING)
|
||||
.then(function () {
|
||||
var presence = $pres({
|
||||
to: _converse.connection.jid,
|
||||
from: 'coven@chat.shakespeare.lit/some1',
|
||||
id: 'DC352437-C019-40EC-B590-AF29E879AF97'
|
||||
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
|
||||
.c('item').attrs({
|
||||
affiliation: 'member',
|
||||
jid: _converse.bare_jid,
|
||||
role: 'participant'
|
||||
}).up()
|
||||
.c('status').attrs({code:'110'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
const room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
|
||||
expect(room_els.length).toBe(1);
|
||||
var info_el = _converse.rooms_list_view.el.querySelector(".room-info");
|
||||
info_el.click();
|
||||
|
||||
const modal = view.model.room_details_modal;
|
||||
return test_utils.waitUntil(() => u.isVisible(modal.el), 2000);
|
||||
}).then(() => {
|
||||
const modal = view.model.room_details_modal;
|
||||
let els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[0].textContent).toBe("Room address (JID): coven@chat.shakespeare.lit")
|
||||
expect(els[1].textContent).toBe("Name: A Dark Cave")
|
||||
expect(els[2].textContent).toBe("Description: This is the description")
|
||||
expect(els[3].textContent).toBe("Online users: 1")
|
||||
const features_list = modal.el.querySelector('.features-list');
|
||||
expect(features_list.textContent.replace(/(\n|\s{2,})/g, '')).toBe(
|
||||
'Password protected - This room requires a password before entry'+
|
||||
'Hidden - This room is not publicly searchable'+
|
||||
'Open - Anyone can join this room'+
|
||||
'Temporary - This room will disappear once the last person leaves'+
|
||||
'Not anonymous - All other room occupants can see your XMPP username'+
|
||||
'Not moderated - This room is not being moderated'
|
||||
);
|
||||
const presence = $pres({
|
||||
to: 'dummy@localhost/_converse.js-29092160',
|
||||
from: 'coven@chat.shakespeare.lit/newguy'
|
||||
})
|
||||
.c('x', {xmlns: Strophe.NS.MUC_USER})
|
||||
.c('item', {
|
||||
'affiliation': 'none',
|
||||
'jid': 'newguy@localhost/_converse.js-290929789',
|
||||
'role': 'participant'
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(presence));
|
||||
|
||||
els = modal.el.querySelectorAll('p.room-info');
|
||||
expect(els[3].textContent).toBe("Online users: 2")
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be closed", mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $pres = converse.env.$pres;
|
||||
@ -35,6 +35,68 @@
|
||||
|
||||
describe("The Contacts Roster", function () {
|
||||
|
||||
it("supports roster versioning",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
var stanza;
|
||||
|
||||
test_utils.waitUntil(() => {
|
||||
const node = _.filter(IQ_stanzas, function (iq) {
|
||||
return iq.nodeTree.querySelector('iq query[xmlns="jabber:iq:roster"]');
|
||||
}).pop();
|
||||
if (node) {
|
||||
stanza = node.nodeTree;
|
||||
return true;
|
||||
}
|
||||
}).then(() => {
|
||||
expect(_converse.roster.data.get('version')).toBeUndefined();
|
||||
expect(stanza.outerHTML).toBe(
|
||||
`<iq type="get" id="${stanza.getAttribute('id')}" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster"/>`+
|
||||
`</iq>`);
|
||||
let result = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
}).c('query', {
|
||||
'xmlns': 'jabber:iq:roster',
|
||||
'ver': 'ver7'
|
||||
}).c('item', {'jid': 'nurse@example.com'}).up()
|
||||
.c('item', {'jid': 'romeo@example.com'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
||||
expect(_converse.roster.data.get('version')).toBe('ver7');
|
||||
expect(_converse.roster.models.length).toBe(2);
|
||||
|
||||
_converse.roster.fetchFromServer();
|
||||
stanza = _converse.connection.IQ_stanzas.pop().nodeTree;
|
||||
expect(stanza.outerHTML).toBe(
|
||||
`<iq type="get" id="${stanza.getAttribute('id')}" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster" ver="ver7"/>`+
|
||||
`</iq>`);
|
||||
|
||||
result = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
||||
|
||||
const roster_push = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'set',
|
||||
}).c('query', {'xmlns': 'jabber:iq:roster', 'ver': 'ver34'})
|
||||
.c('item', {'jid': 'romeo@example.com', 'subscription': 'remove'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
|
||||
expect(_converse.roster.data.get('version')).toBe('ver34');
|
||||
expect(_converse.roster.models.length).toBe(1);
|
||||
expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
describe("The live filter", function () {
|
||||
|
||||
it("will only appear when roster contacts flow over the visible area",
|
||||
|
@ -1,13 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"jasmine",
|
||||
"utils",
|
||||
"mock",
|
||||
"converse-core",
|
||||
"test-utils"
|
||||
], factory);
|
||||
} (this, function (jasmine, utils, mock, converse, test_utils) {
|
||||
|
||||
define(["jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $msg = converse.env.$msg;
|
||||
|
@ -1,12 +1,10 @@
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"jasmine",
|
||||
"utils",
|
||||
"converse-core",
|
||||
"mock",
|
||||
"test-utils"
|
||||
], factory);
|
||||
} (this, function (jasmine, utils, converse, mock, test_utils) {
|
||||
} (this, function (jasmine, mock, test_utils) {
|
||||
"use strict";
|
||||
var _ = converse.env._;
|
||||
var $iq = converse.env.$iq;
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jasmine", "converse-core"], factory);
|
||||
} (this, function (jasmine, converse) {
|
||||
define(["jasmine"], factory);
|
||||
} (this, function (jasmine) {
|
||||
var utils = converse.env.utils,
|
||||
_ = converse.env._;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "converse-core", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, converse, test_utils) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
|
||||
return describe("The XMPPStatus model", function() {
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
({
|
||||
baseUrl: "../",
|
||||
name: "almond",
|
||||
mainConfigFile: 'config.js',
|
||||
wrap: {
|
||||
startFile: "start.frag",
|
||||
endFile: "end.frag"
|
||||
}
|
||||
});
|
@ -1,54 +0,0 @@
|
||||
({
|
||||
baseUrl: "../",
|
||||
name: "almond",
|
||||
out: "../dist/converse-no-dependencies.min.js",
|
||||
include: ["converse"],
|
||||
exclude: [
|
||||
"awesomplete",
|
||||
"backbone.browserStorage",
|
||||
"backbone.overview",
|
||||
"moment",
|
||||
"strophe",
|
||||
"strophe.rsm",
|
||||
"strophe.ping",
|
||||
"otr",
|
||||
"lodash",
|
||||
"lodash.converter",
|
||||
"lodash.noconflict",
|
||||
"es6-promise"
|
||||
],
|
||||
paths: {
|
||||
"backbone.vdomview": "builds/backbone.vdomview",
|
||||
"converse-bookmarks": "builds/converse-bookmarks",
|
||||
"converse-chatboxes": "builds/converse-chatboxes",
|
||||
"converse-chatview": "builds/converse-chatview",
|
||||
"converse-controlbox": "builds/converse-controlbox",
|
||||
"converse-core": "builds/converse-core",
|
||||
"converse-disco": "builds/converse-disco",
|
||||
"converse-dragresize": "builds/converse-dragresize",
|
||||
"converse-embedded": "builds/converse-embedded",
|
||||
"converse-fullscreen": "builds/converse-fullscreen",
|
||||
"converse-headline": "builds/converse-headline",
|
||||
"converse-mam": "builds/converse-mam",
|
||||
"converse-minimize": "builds/converse-minimize",
|
||||
"converse-muc": "builds/converse-muc",
|
||||
"converse-notification": "builds/converse-notification",
|
||||
"converse-otr": "builds/converse-otr",
|
||||
"converse-ping": "builds/converse-ping",
|
||||
"converse-profile": "builds/converse-profile",
|
||||
"converse-register": "builds/converse-register",
|
||||
"converse-roomslist": "builds/converse-roomslist",
|
||||
"converse-rosterview": "builds/converse-rosterview",
|
||||
"converse-singleton": "builds/converse-singleton",
|
||||
"converse-vcard": "builds/converse-vcard",
|
||||
"form-utils": "builds/utils/form",
|
||||
"i18n": "builds/i18n",
|
||||
"utils": "builds/utils/core",
|
||||
"muc-utils": "builds/utils/muc"
|
||||
},
|
||||
wrap: {
|
||||
startFile: "start.frag",
|
||||
endFile: "end-no-dependencies.frag"
|
||||
},
|
||||
mainConfigFile: "config.js"
|
||||
});
|
43
src/build.js
43
src/build.js
@ -1,43 +0,0 @@
|
||||
({
|
||||
baseUrl: "../",
|
||||
name: "almond",
|
||||
mainConfigFile: 'config.js',
|
||||
paths: {
|
||||
"backbone.vdomview": "builds/backbone.vdomview",
|
||||
"converse-bookmarks": "builds/converse-bookmarks",
|
||||
"converse-caps": "builds/converse-caps",
|
||||
"converse-chatboxes": "builds/converse-chatboxes",
|
||||
"converse-chatview": "builds/converse-chatview",
|
||||
"converse-controlbox": "builds/converse-controlbox",
|
||||
"converse-core": "builds/converse-core",
|
||||
"converse-disco": "builds/converse-disco",
|
||||
"converse-dragresize": "builds/converse-dragresize",
|
||||
"converse-embedded": "builds/converse-embedded",
|
||||
"converse-fullscreen": "builds/converse-fullscreen",
|
||||
"converse-headline": "builds/converse-headline",
|
||||
"converse-mam": "builds/converse-mam",
|
||||
"converse-message-view": "builds/converse-message-view",
|
||||
"converse-minimize": "builds/converse-minimize",
|
||||
"converse-modal": "builds/converse-modal",
|
||||
"converse-muc": "builds/converse-muc",
|
||||
"converse-muc-views": "builds/converse-muc-views",
|
||||
"converse-notification": "builds/converse-notification",
|
||||
"converse-otr": "builds/converse-otr",
|
||||
"converse-ping": "builds/converse-ping",
|
||||
"converse-profile": "builds/converse-profile",
|
||||
"converse-register": "builds/converse-register",
|
||||
"converse-roomslist": "builds/converse-roomslist",
|
||||
"converse-roster": "builds/converse-roster",
|
||||
"converse-rosterview": "builds/converse-rosterview",
|
||||
"converse-singleton": "builds/converse-singleton",
|
||||
"converse-vcard": "builds/converse-vcard",
|
||||
"form-utils": "builds/utils/form",
|
||||
"i18n": "builds/i18n",
|
||||
"muc-utils": "builds/utils/muc",
|
||||
"utils": "builds/utils/core"
|
||||
},
|
||||
wrap: {
|
||||
startFile: "start.frag",
|
||||
endFile: "end.frag"
|
||||
}
|
||||
});
|
168
src/config.js
168
src/config.js
@ -1,168 +0,0 @@
|
||||
var config;
|
||||
if (typeof(require) === 'undefined') {
|
||||
/* XXX: Hack to work around r.js's stupid parsing.
|
||||
* We want to save the configuration in a variable so that we can reuse it in
|
||||
* tests/main.js.
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
require = { // jshint ignore:line
|
||||
config: function (c) {
|
||||
config = c;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
require.config({
|
||||
baseUrl: '.',
|
||||
paths: {
|
||||
"IPv6": "node_modules/urijs/src/IPv6",
|
||||
"SecondLevelDomains": "node_modules/urijs/src/SecondLevelDomains",
|
||||
"almond": "node_modules/almond/almond",
|
||||
"awesomplete": "node_modules/awesomplete-avoid-xss/awesomplete",
|
||||
"babel": "node_modules/requirejs-babel/babel-5.8.34.min",
|
||||
"backbone": "node_modules/backbone/backbone",
|
||||
"backbone.browserStorage": "node_modules/backbone.browserStorage/backbone.browserStorage",
|
||||
"backbone.nativeview": "node_modules/backbone.nativeview/backbone.nativeview",
|
||||
"backbone.noconflict": "src/backbone.noconflict",
|
||||
"backbone.orderedlistview": "node_modules/backbone.overview/dist/backbone.orderedlistview",
|
||||
"backbone.overview": "node_modules/backbone.overview/dist/backbone.overview",
|
||||
"backbone.vdomview": "node_modules/backbone.vdomview/dist/backbone.vdomview",
|
||||
"bootstrap": "node_modules/bootstrap.native/dist/bootstrap-native-v4",
|
||||
"emojione": "node_modules/emojione/lib/js/emojione",
|
||||
"es6-promise": "node_modules/es6-promise/dist/es6-promise.auto",
|
||||
"eventemitter": "node_modules/otr/build/dep/eventemitter",
|
||||
"filesize": "node_modules/filesize/lib/filesize",
|
||||
"form-utils": "src/utils/form",
|
||||
"i18n": "src/i18n",
|
||||
"jed": "node_modules/jed/jed",
|
||||
"jquery": "src/jquery-stub",
|
||||
"lodash": "node_modules/lodash/lodash",
|
||||
"lodash.converter": "3rdparty/lodash.fp",
|
||||
"lodash.fp": "src/lodash.fp",
|
||||
"lodash.noconflict": "src/lodash.noconflict",
|
||||
"message-utils": "src/utils/message",
|
||||
"muc-utils": "src/utils/muc",
|
||||
"pluggable": "node_modules/pluggable.js/dist/pluggable",
|
||||
"polyfill": "src/polyfill",
|
||||
"punycode": "node_modules/urijs/src/punycode",
|
||||
"sizzle": "node_modules/sizzle/dist/sizzle",
|
||||
"snabbdom": "node_modules/snabbdom/dist/snabbdom",
|
||||
"snabbdom-attributes": "node_modules/snabbdom/dist/snabbdom-attributes",
|
||||
"snabbdom-class": "node_modules/snabbdom/dist/snabbdom-class",
|
||||
"snabbdom-dataset": "node_modules/snabbdom/dist/snabbdom-dataset",
|
||||
"snabbdom-eventlisteners": "node_modules/snabbdom/dist/snabbdom-eventlisteners",
|
||||
"snabbdom-props": "node_modules/snabbdom/dist/snabbdom-props",
|
||||
"snabbdom-style": "node_modules/snabbdom/dist/snabbdom-style",
|
||||
"strophe": "node_modules/strophe.js/strophe",
|
||||
"strophe.ping": "node_modules/strophejs-plugin-ping/strophe.ping",
|
||||
"strophe.rsm": "node_modules/strophejs-plugin-rsm/strophe.rsm",
|
||||
"text": "node_modules/text/text",
|
||||
"tovnode": "node_modules/snabbdom/dist/tovnode",
|
||||
"tpl": "node_modules/lodash-template-loader/loader",
|
||||
"underscore": "src/underscore-shim",
|
||||
"uri": "node_modules/urijs/src/URI",
|
||||
"utils": "src/utils/core",
|
||||
"vdom-parser": "node_modules/vdom-parser/dist",
|
||||
"xss": "node_modules/xss/dist/xss",
|
||||
"xss.noconflict": "src/xss.noconflict",
|
||||
|
||||
// OMEMO/libsignal requirements
|
||||
"Long": "3rdparty/long",
|
||||
"protobuf": "3rdparty/protobuf",
|
||||
"bytebuffer": "3rdparty/bytebuffer",
|
||||
"libsignal": "3rdparty/libsignal-protocol-javascript/dist/libsignal-protocol",
|
||||
|
||||
// Converse
|
||||
"converse": "src/converse",
|
||||
|
||||
"converse-bookmarks": "src/converse-bookmarks",
|
||||
"converse-caps": "src/converse-caps",
|
||||
"converse-chatboxes": "src/converse-chatboxes",
|
||||
"converse-chatview": "src/converse-chatview",
|
||||
"converse-controlbox": "src/converse-controlbox",
|
||||
"converse-core": "src/converse-core",
|
||||
"converse-disco": "src/converse-disco",
|
||||
"converse-dragresize": "src/converse-dragresize",
|
||||
"converse-embedded": "src/converse-embedded",
|
||||
"converse-fullscreen": "src/converse-fullscreen",
|
||||
"converse-headline": "src/converse-headline",
|
||||
"converse-mam": "src/converse-mam",
|
||||
"converse-message-view": "src/converse-message-view",
|
||||
"converse-minimize": "src/converse-minimize",
|
||||
"converse-modal": "src/converse-modal",
|
||||
"converse-muc": "src/converse-muc",
|
||||
"converse-muc-views": "src/converse-muc-views",
|
||||
"converse-notification": "src/converse-notification",
|
||||
"converse-omemo": "src/converse-omemo",
|
||||
"converse-otr": "src/converse-otr",
|
||||
"converse-ping": "src/converse-ping",
|
||||
"converse-profile": "src/converse-profile",
|
||||
"converse-register": "src/converse-register",
|
||||
"converse-roomslist": "src/converse-roomslist",
|
||||
"converse-roster": "src/converse-roster",
|
||||
"converse-rosterview": "src/converse-rosterview",
|
||||
"converse-singleton": "src/converse-singleton",
|
||||
"converse-vcard": "src/converse-vcard",
|
||||
|
||||
// Off-the-record-encryption
|
||||
// "bigint": "node_modules/otr/build/dep/bigint",
|
||||
"bigint": "3rdparty/bigint",
|
||||
"crypto": "node_modules/otr/build/dep/crypto",
|
||||
"salsa20": "node_modules/otr/build/dep/salsa20",
|
||||
"otr": "node_modules/otr/build/otr",
|
||||
},
|
||||
|
||||
packages: [{
|
||||
'name': 'moment',
|
||||
'location': 'node_modules/moment',
|
||||
'main': 'moment'
|
||||
}],
|
||||
|
||||
map: {
|
||||
// '*' means all modules will get the '*.noconflict' version
|
||||
// as their dependency.
|
||||
'*': {
|
||||
'backbone': 'backbone.noconflict',
|
||||
'lodash': 'lodash.noconflict'
|
||||
},
|
||||
// '*.noconflict' wants the real module
|
||||
// If this line was not here, there would
|
||||
// be an unresolvable cyclic dependency.
|
||||
'backbone.noconflict': { 'backbone': 'backbone' },
|
||||
'lodash.noconflict': { 'lodash': 'lodash' }
|
||||
},
|
||||
|
||||
lodashLoader: {
|
||||
// Configuration for requirejs-tpl
|
||||
// Use Mustache style syntax for variable interpolation
|
||||
root: "src/templates/",
|
||||
templateSettings: {
|
||||
"escape": /\{\{\{([\s\S]+?)\}\}\}/g,
|
||||
"evaluate": /\{\[([\s\S]+?)\]\}/g,
|
||||
"interpolate": /\{\{([\s\S]+?)\}\}/g,
|
||||
// By default, template places the values from your data in the
|
||||
// local scope via the with statement. However, you can specify
|
||||
// a single variable name with the variable setting. This can
|
||||
// significantly improve the speed at which a template is able
|
||||
// to render.
|
||||
"variable": 'o'
|
||||
}
|
||||
},
|
||||
|
||||
// define module dependencies for modules not using define
|
||||
shim: {
|
||||
'backbone.orderedlistview': { deps: ['backbone.nativeview'] },
|
||||
'backbone.overview': { deps: ['backbone.nativeview'] },
|
||||
'backbone.vdomview': { deps: ['backbone.nativeview'] },
|
||||
'awesomplete': { exports: 'Awesomplete'},
|
||||
'emojione': { exports: 'emojione'},
|
||||
'xss': {
|
||||
'init': function (xss_noconflict) {
|
||||
return {
|
||||
filterXSS: window.filterXSS,
|
||||
filterCSS: window.filterCSS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
@ -12,10 +12,10 @@
|
||||
(function (root, factory) {
|
||||
define(["converse-core",
|
||||
"converse-muc",
|
||||
"tpl!chatroom_bookmark_form",
|
||||
"tpl!chatroom_bookmark_toggle",
|
||||
"tpl!bookmark",
|
||||
"tpl!bookmarks_list"
|
||||
"templates/chatroom_bookmark_form.html",
|
||||
"templates/chatroom_bookmark_toggle.html",
|
||||
"templates/bookmark.html",
|
||||
"templates/bookmarks_list.html"
|
||||
],
|
||||
factory);
|
||||
}(this, function (
|
||||
@ -337,10 +337,9 @@
|
||||
'type': 'get',
|
||||
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'node': 'storage:bookmarks'});
|
||||
_converse.connection.sendIQ(
|
||||
stanza,
|
||||
_.bind(this.onBookmarksReceived, this, deferred),
|
||||
_.bind(this.onBookmarksReceivedError, this, deferred)
|
||||
_converse.api.sendIQ(stanza)
|
||||
.then((iq) => this.onBookmarksReceived(deferred, iq))
|
||||
.catch((iq) => this.onBookmarksReceivedError(deferred, iq)
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -9,9 +9,9 @@
|
||||
"converse-core",
|
||||
"emojione",
|
||||
"filesize",
|
||||
"tpl!chatboxes",
|
||||
"templates/chatboxes.html",
|
||||
"backbone.overview",
|
||||
"form-utils"
|
||||
"utils/form"
|
||||
], factory);
|
||||
}(this, function (converse, emojione, filesize, tpl_chatboxes) {
|
||||
"use strict";
|
||||
@ -29,18 +29,6 @@
|
||||
// plugin architecture they will replace existing methods on the
|
||||
// relevant objects or classes.
|
||||
|
||||
disconnect: function () {
|
||||
const { _converse } = this.__super__;
|
||||
_converse.chatboxviews.closeAllChatBoxes();
|
||||
return this.__super__.disconnect.apply(this, arguments);
|
||||
},
|
||||
|
||||
logOut: function () {
|
||||
const { _converse } = this.__super__;
|
||||
_converse.chatboxviews.closeAllChatBoxes();
|
||||
return this.__super__.logOut.apply(this, arguments);
|
||||
},
|
||||
|
||||
initStatus: function (reconnecting) {
|
||||
const { _converse } = this.__super__;
|
||||
if (!reconnecting) {
|
||||
@ -62,7 +50,9 @@
|
||||
// Refer to docs/source/configuration.rst for explanations of these
|
||||
// configuration settings.
|
||||
_converse.api.settings.update({
|
||||
auto_join_private_chats: [],
|
||||
'filter_by_resource': false,
|
||||
'auto_join_private_chats': [],
|
||||
'forward_messages': false,
|
||||
});
|
||||
_converse.api.promises.add([
|
||||
'chatBoxesFetched',
|
||||
@ -110,17 +100,35 @@
|
||||
}
|
||||
},
|
||||
|
||||
getVCardForChatroomOccupant () {
|
||||
const chatbox = this.collection.chatbox,
|
||||
nick = Strophe.getResourceFromJid(this.get('from'));
|
||||
|
||||
if (chatbox.get('nick') === nick) {
|
||||
return _converse.xmppstatus.vcard;
|
||||
} else {
|
||||
let vcard;
|
||||
if (this.get('vcard_jid')) {
|
||||
vcard = _converse.vcards.findWhere({'jid': this.get('vcard_jid')});
|
||||
}
|
||||
if (!vcard) {
|
||||
let jid;
|
||||
const occupant = chatbox.occupants.findWhere({'nick': nick});
|
||||
if (occupant && occupant.get('jid')) {
|
||||
jid = occupant.get('jid');
|
||||
this.save({'vcard_jid': jid}, {'silent': true});
|
||||
} else {
|
||||
jid = this.get('from');
|
||||
}
|
||||
vcard = _converse.vcards.findWhere({'jid': jid}) || _converse.vcards.create({'jid': jid});
|
||||
}
|
||||
return vcard;
|
||||
}
|
||||
},
|
||||
|
||||
setVCard () {
|
||||
if (this.get('type') === 'groupchat') {
|
||||
const chatbox = this.collection.chatbox,
|
||||
nick = Strophe.getResourceFromJid(this.get('from'));
|
||||
if (chatbox.get('nick') === nick) {
|
||||
this.vcard = _converse.xmppstatus.vcard;
|
||||
} else {
|
||||
const occupant = chatbox.occupants.findWhere({'nick': nick});
|
||||
const jid = (occupant && occupant.get('jid')) ? occupant.get('jid') : this.get('from');
|
||||
this.vcard = _converse.vcards.findWhere({'jid': jid}) || _converse.vcards.create({'jid': jid});
|
||||
}
|
||||
this.vcard = this.getVCardForChatroomOccupant();
|
||||
} else {
|
||||
const jid = this.get('from');
|
||||
this.vcard = _converse.vcards.findWhere({'jid': jid}) || _converse.vcards.create({'jid': jid});
|
||||
@ -231,13 +239,16 @@
|
||||
|
||||
|
||||
_converse.ChatBox = _converse.ModelWithVCardAndPresence.extend({
|
||||
defaults: {
|
||||
'bookmarked': false,
|
||||
'chat_state': undefined,
|
||||
'num_unread': 0,
|
||||
'type': 'chatbox',
|
||||
'message_type': 'chat',
|
||||
'url': ''
|
||||
defaults () {
|
||||
return {
|
||||
'bookmarked': false,
|
||||
'chat_state': undefined,
|
||||
'num_unread': 0,
|
||||
'type': 'chatbox',
|
||||
'message_type': 'chat',
|
||||
'url': '',
|
||||
'hidden': _.includes(['mobile', 'fullscreen'], _converse.view_mode)
|
||||
}
|
||||
},
|
||||
|
||||
initialize () {
|
||||
@ -401,12 +412,17 @@
|
||||
|
||||
getMessageBody (message) {
|
||||
const type = message.getAttribute('type');
|
||||
return (type === 'error') ?
|
||||
_.propertyOf(message.querySelector('error text'))('textContent') :
|
||||
_.propertyOf(message.querySelector('body'))('textContent');
|
||||
if (type === 'error') {
|
||||
const error = message.querySelector('error');
|
||||
return _.propertyOf(error.querySelector('text'))('textContent') ||
|
||||
__('Sorry, an error occured:') + ' ' + error.innerHTML;
|
||||
} else {
|
||||
return _.propertyOf(message.querySelector('body'))('textContent');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getMessageAttributesFromStanza (message, delay, original_stanza) {
|
||||
getMessageAttributesFromStanza (message, original_stanza) {
|
||||
/* Parses a passed in message stanza and returns an object
|
||||
* of attributes.
|
||||
*
|
||||
@ -418,11 +434,11 @@
|
||||
* that contains the message stanza, if it was
|
||||
* contained, otherwise it's the message stanza itself.
|
||||
*/
|
||||
delay = delay || message.querySelector('delay');
|
||||
|
||||
const { _converse } = this.__super__,
|
||||
{ __ } = _converse,
|
||||
spoiler = message.querySelector(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`),
|
||||
archive = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop(),
|
||||
spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
|
||||
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
|
||||
chat_state = message.getElementsByTagName(_converse.COMPOSING).length && _converse.COMPOSING ||
|
||||
message.getElementsByTagName(_converse.PAUSED).length && _converse.PAUSED ||
|
||||
message.getElementsByTagName(_converse.INACTIVE).length && _converse.INACTIVE ||
|
||||
@ -430,13 +446,14 @@
|
||||
message.getElementsByTagName(_converse.GONE).length && _converse.GONE;
|
||||
|
||||
const attrs = {
|
||||
'type': message.getAttribute('type'),
|
||||
'chat_state': chat_state,
|
||||
'delayed': !_.isNull(delay),
|
||||
'is_archived': !_.isNil(archive),
|
||||
'is_delayed': !_.isNil(delay),
|
||||
'is_spoiler': !_.isNil(spoiler),
|
||||
'message': this.getMessageBody(message) || undefined,
|
||||
'msgid': message.getAttribute('id'),
|
||||
'time': delay ? delay.getAttribute('stamp') : moment().format(),
|
||||
'is_spoiler': !_.isNull(spoiler)
|
||||
'type': message.getAttribute('type')
|
||||
};
|
||||
if (attrs.type === 'groupchat') {
|
||||
attrs.from = message.getAttribute('from');
|
||||
@ -466,14 +483,15 @@
|
||||
return attrs;
|
||||
},
|
||||
|
||||
createMessage (message, delay, original_stanza) {
|
||||
createMessage (message, original_stanza) {
|
||||
/* Create a Backbone.Message object inside this chat box
|
||||
* based on the identified message stanza.
|
||||
*/
|
||||
const attrs = this.getMessageAttributesFromStanza.apply(this, arguments)
|
||||
const attrs = this.getMessageAttributesFromStanza(message, original_stanza);
|
||||
const is_csn = u.isOnlyChatStateNotification(attrs);
|
||||
if (is_csn && attrs.delayed) {
|
||||
// No need showing old CSNs
|
||||
if (is_csn && (attrs.is_delayed || (attrs.type === 'groupchat' && Strophe.getResourceFromJid(attrs.from) == this.get('nick')))) {
|
||||
// XXX: MUC leakage
|
||||
// No need showing delayed or our own CSN messages
|
||||
return;
|
||||
} else if (!is_csn && !attrs.file && !attrs.message && !attrs.oob_url && attrs.type !== 'error') {
|
||||
// TODO: handle <subject> messages (currently being done by ChatRoom)
|
||||
@ -483,7 +501,7 @@
|
||||
}
|
||||
},
|
||||
|
||||
newMessageWillBeHidden () {
|
||||
isHidden () {
|
||||
/* Returns a boolean to indicate whether a newly received
|
||||
* message will be visible to the user or not.
|
||||
*/
|
||||
@ -500,7 +518,7 @@
|
||||
if (_.isNull(stanza.querySelector('body'))) {
|
||||
return; // The message has no text
|
||||
}
|
||||
if (utils.isNewMessage(stanza) && this.newMessageWillBeHidden()) {
|
||||
if (utils.isNewMessage(stanza) && this.isHidden()) {
|
||||
this.save({'num_unread': this.get('num_unread') + 1});
|
||||
_converse.incrementMsgCounter();
|
||||
}
|
||||
@ -524,12 +542,14 @@
|
||||
},
|
||||
|
||||
registerMessageHandler () {
|
||||
_converse.connection.addHandler(
|
||||
this.onMessage.bind(this), null, 'message', 'chat'
|
||||
);
|
||||
_converse.connection.addHandler(
|
||||
this.onErrorMessage.bind(this), null, 'message', 'error'
|
||||
);
|
||||
_converse.connection.addHandler((stanza) => {
|
||||
this.onMessage(stanza);
|
||||
return true;
|
||||
}, null, 'message', 'chat');
|
||||
_converse.connection.addHandler((stanza) => {
|
||||
this.onErrorMessage(stanza);
|
||||
return true;
|
||||
}, null, 'message', 'error');
|
||||
},
|
||||
|
||||
chatBoxMayBeShown (chatbox) {
|
||||
@ -547,29 +567,27 @@
|
||||
},
|
||||
|
||||
onConnected () {
|
||||
this.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
||||
this.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.chatboxes-${_converse.bare_jid}`));
|
||||
this.registerMessageHandler();
|
||||
this.fetch({
|
||||
add: true,
|
||||
success: this.onChatBoxesFetched.bind(this)
|
||||
'add': true,
|
||||
'success': this.onChatBoxesFetched.bind(this)
|
||||
});
|
||||
},
|
||||
|
||||
onErrorMessage (message) {
|
||||
/* Handler method for all incoming error message stanzas
|
||||
*/
|
||||
// TODO: we can likely just reuse "onMessage" below
|
||||
const from_jid = Strophe.getBareJidFromJid(message.getAttribute('from'));
|
||||
if (utils.isSameBareJID(from_jid, _converse.bare_jid)) {
|
||||
return true;
|
||||
}
|
||||
// Get chat box, but only create a new one when the message has a body.
|
||||
const chatbox = this.getChatBox(from_jid);
|
||||
if (!chatbox) {
|
||||
return true;
|
||||
}
|
||||
chatbox.createMessage(message, null, message);
|
||||
chatbox.createMessage(message, message);
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -580,8 +598,7 @@
|
||||
* Parameters:
|
||||
* (XMLElement) message - The incoming message stanza
|
||||
*/
|
||||
let contact_jid, delay, resource,
|
||||
from_jid = message.getAttribute('from'),
|
||||
let from_jid = message.getAttribute('from'),
|
||||
to_jid = message.getAttribute('to');
|
||||
|
||||
const original_stanza = message,
|
||||
@ -610,12 +627,10 @@
|
||||
const forwarded_from = forwarded_message.getAttribute('from');
|
||||
if (is_carbon && Strophe.getBareJidFromJid(forwarded_from) !== from_jid) {
|
||||
// Prevent message forging via carbons
|
||||
//
|
||||
// https://xmpp.org/extensions/xep-0280.html#security
|
||||
return true;
|
||||
}
|
||||
message = forwarded_message;
|
||||
delay = forwarded.querySelector('delay');
|
||||
from_jid = message.getAttribute('from');
|
||||
to_jid = message.getAttribute('to');
|
||||
}
|
||||
@ -624,13 +639,12 @@
|
||||
from_resource = Strophe.getResourceFromJid(from_jid),
|
||||
is_me = from_bare_jid === _converse.bare_jid;
|
||||
|
||||
let contact_jid;
|
||||
if (is_me) {
|
||||
// I am the sender, so this must be a forwarded message...
|
||||
contact_jid = Strophe.getBareJidFromJid(to_jid);
|
||||
resource = Strophe.getResourceFromJid(to_jid);
|
||||
} else {
|
||||
contact_jid = from_bare_jid;
|
||||
resource = from_resource;
|
||||
}
|
||||
// Get chat box, but only create a new one when the message has a body.
|
||||
const attrs = {
|
||||
@ -645,7 +659,7 @@
|
||||
// Only create the message when we're sure it's not a
|
||||
// duplicate
|
||||
chatbox.incrementUnreadMsgCounter(original_stanza);
|
||||
chatbox.createMessage(message, delay, original_stanza);
|
||||
chatbox.createMessage(message, original_stanza);
|
||||
}
|
||||
}
|
||||
_converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox});
|
||||
@ -700,9 +714,6 @@
|
||||
_converse.root.appendChild(el);
|
||||
}
|
||||
}
|
||||
if (_.includes(['mobile', 'fullscreen'], _converse.view_mode)) {
|
||||
el.classList.add('fullscreen');
|
||||
}
|
||||
el.innerHTML = '';
|
||||
this.setElement(el, false);
|
||||
} else {
|
||||
@ -814,12 +825,11 @@
|
||||
_converse.emit('chatBoxesInitialized');
|
||||
});
|
||||
|
||||
_converse.api.listen.on('beforeTearDown', () => {
|
||||
_converse.chatboxes.remove(); // Don't call off(), events won't get re-registered upon reconnect.
|
||||
delete _converse.chatboxes.browserStorage;
|
||||
_converse.api.listen.on('clearSession', () => {
|
||||
_converse.chatboxviews.closeAllChatBoxes();
|
||||
});
|
||||
|
||||
_converse.api.listen.on('statusInitialized', () => _converse.chatboxes.onConnected());
|
||||
_converse.api.listen.on('presencesInitialized', () => _converse.chatboxes.onConnected());
|
||||
/************************ END Event Handlers ************************/
|
||||
|
||||
|
||||
|
@ -5,26 +5,25 @@
|
||||
// Licensed under the Mozilla Public License (MPLv2)
|
||||
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"converse-core",
|
||||
define(["converse-core",
|
||||
"bootstrap",
|
||||
"emojione",
|
||||
"xss",
|
||||
"tpl!action",
|
||||
"tpl!chatbox",
|
||||
"tpl!chatbox_head",
|
||||
"tpl!chatbox_message_form",
|
||||
"tpl!emojis",
|
||||
"tpl!error_message",
|
||||
"tpl!help_message",
|
||||
"tpl!info",
|
||||
"tpl!new_day",
|
||||
"tpl!user_details_modal",
|
||||
"tpl!toolbar_fileupload",
|
||||
"tpl!spinner",
|
||||
"tpl!spoiler_button",
|
||||
"tpl!status_message",
|
||||
"tpl!toolbar",
|
||||
"templates/action.html",
|
||||
"templates/chatbox.html",
|
||||
"templates/chatbox_head.html",
|
||||
"templates/chatbox_message_form.html",
|
||||
"templates/emojis.html",
|
||||
"templates/error_message.html",
|
||||
"templates/help_message.html",
|
||||
"templates/info.html",
|
||||
"templates/new_day.html",
|
||||
"templates/user_details_modal.html",
|
||||
"templates/toolbar_fileupload.html",
|
||||
"templates/spinner.html",
|
||||
"templates/spoiler_button.html",
|
||||
"templates/status_message.html",
|
||||
"templates/toolbar.html",
|
||||
"converse-modal",
|
||||
"converse-chatboxes",
|
||||
"converse-message-view"
|
||||
@ -101,10 +100,11 @@
|
||||
{ __ } = _converse;
|
||||
|
||||
_converse.api.settings.update({
|
||||
'use_emojione': false,
|
||||
'emojione_image_path': emojione.imagePathPNG,
|
||||
'show_send_button': false,
|
||||
'show_toolbar': true,
|
||||
'time_format': 'HH:mm',
|
||||
'use_emojione': false,
|
||||
'visible_toolbar_buttons': {
|
||||
'call': false,
|
||||
'clear': true,
|
||||
@ -151,6 +151,7 @@
|
||||
return tpl_emojis(
|
||||
_.extend(
|
||||
this.model.toJSON(), {
|
||||
'_': _,
|
||||
'transform': _converse.use_emojione ? emojione.shortnameToImage : emojione.shortnameToUnicode,
|
||||
'emojis_by_category': u.getEmojisByCategory(_converse, emojione),
|
||||
'toned_emojis': u.getTonedEmojis(_converse),
|
||||
@ -320,16 +321,17 @@
|
||||
|
||||
events: {
|
||||
'change input.fileupload': 'onFileSelection',
|
||||
'click .chatbox-navback': 'showControlBox',
|
||||
'click .close-chatbox-button': 'close',
|
||||
'click .show-user-details-modal': 'showUserDetailsModal',
|
||||
'click .new-msgs-indicator': 'viewUnreadMessages',
|
||||
'click .send-button': 'onFormSubmitted',
|
||||
'click .show-user-details-modal': 'showUserDetailsModal',
|
||||
'click .spoiler-toggle': 'toggleSpoilerMessage',
|
||||
'click .toggle-call': 'toggleCall',
|
||||
'click .toggle-clear': 'clearMessages',
|
||||
'click .toggle-compose-spoiler': 'toggleComposeSpoilerMessage',
|
||||
'click .toggle-smiley ul.emoji-picker li': 'insertEmoji',
|
||||
'click .toggle-smiley': 'toggleEmojiMenu',
|
||||
'click .spoiler-toggle': 'toggleSpoilerMessage',
|
||||
'click .upload-file': 'toggleFileUpload',
|
||||
'keypress .chat-textarea': 'keyPressed',
|
||||
'input .chat-textarea': 'inputChanged'
|
||||
@ -413,7 +415,15 @@
|
||||
this.renderToolbar();
|
||||
},
|
||||
|
||||
showControlBox () {
|
||||
// Used in mobile view, to navigate back to the controlbox
|
||||
const view = _converse.chatboxviews.get('controlbox');
|
||||
view.show();
|
||||
this.hide();
|
||||
},
|
||||
|
||||
showUserDetailsModal (ev) {
|
||||
ev.preventDefault();
|
||||
if (_.isUndefined(this.user_details_modal)) {
|
||||
this.user_details_modal = new _converse.UserDetailsModal({model: this.model});
|
||||
}
|
||||
@ -901,7 +911,7 @@
|
||||
keyPressed (ev) {
|
||||
/* Event handler for when a key is pressed in a chat box textarea.
|
||||
*/
|
||||
if (ev.keyCode === KEY.ENTER) {
|
||||
if (ev.keyCode === KEY.ENTER && !ev.shiftKey) {
|
||||
this.onFormSubmitted(ev);
|
||||
} else if (ev.keyCode !== KEY.FORWARD_SLASH && this.model.get('chat_state') !== _converse.COMPOSING) {
|
||||
// Set chat state to composing if keyCode is not a forward-slash
|
||||
@ -1075,10 +1085,7 @@
|
||||
},
|
||||
|
||||
afterShown () {
|
||||
if (u.isPersistableModel(this.model)) {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
this.model.save();
|
||||
}
|
||||
this.model.clearUnreadMsgCounter();
|
||||
this.setChatState(_converse.ACTIVE);
|
||||
this.renderEmojiPicker();
|
||||
this.scrollDown();
|
||||
@ -1155,7 +1162,7 @@
|
||||
},
|
||||
|
||||
onWindowStateChanged (state) {
|
||||
if (this.model.get('num_unread', 0) && !this.model.newMessageWillBeHidden()) {
|
||||
if (this.model.get('num_unread', 0) && !this.model.isHidden()) {
|
||||
this.model.clearUnreadMsgCounter();
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,10 @@
|
||||
define(["converse-core",
|
||||
"bootstrap",
|
||||
"lodash.fp",
|
||||
"tpl!converse_brand_heading",
|
||||
"tpl!controlbox",
|
||||
"tpl!controlbox_toggle",
|
||||
"tpl!login_panel",
|
||||
"templates/converse_brand_heading.html",
|
||||
"templates/controlbox.html",
|
||||
"templates/controlbox_toggle.html",
|
||||
"templates/login_panel.html",
|
||||
"converse-chatview",
|
||||
"converse-rosterview",
|
||||
"converse-profile"
|
||||
@ -91,8 +91,8 @@
|
||||
//
|
||||
// New functions which don't exist yet can also be added.
|
||||
|
||||
_tearDown () {
|
||||
this.__super__._tearDown.apply(this, arguments);
|
||||
tearDown () {
|
||||
this.__super__.tearDown.apply(this, arguments);
|
||||
if (this.rosterview) {
|
||||
// Removes roster groups
|
||||
this.rosterview.model.off().reset();
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Converse.js
|
||||
// https://conversejs.org
|
||||
//
|
||||
// Copyright (c) 2012-2018, the Converse.js developers
|
||||
// Copyright (c) 2013-2018, the Converse.js developers
|
||||
// Licensed under the Mozilla Public License (MPLv2)
|
||||
|
||||
(function (root, factory) {
|
||||
@ -11,7 +11,7 @@
|
||||
"lodash.fp",
|
||||
"polyfill",
|
||||
"i18n",
|
||||
"utils",
|
||||
"utils/core",
|
||||
"moment",
|
||||
"strophe",
|
||||
"pluggable",
|
||||
@ -20,11 +20,7 @@
|
||||
"backbone.browserStorage"
|
||||
], factory);
|
||||
}(this, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
|
||||
|
||||
/* Cannot use this due to Safari bug.
|
||||
* See https://github.com/jcbrand/converse.js/issues/196
|
||||
*/
|
||||
// "use strict";
|
||||
"use strict";
|
||||
|
||||
// Strophe globals
|
||||
const { $build, $iq, $msg, $pres } = Strophe;
|
||||
@ -72,9 +68,9 @@
|
||||
// Core plugins are whitelisted automatically
|
||||
_converse.core_plugins = [
|
||||
'converse-bookmarks',
|
||||
'converse-caps',
|
||||
'converse-chatboxes',
|
||||
'converse-chatview',
|
||||
'converse-caps',
|
||||
'converse-controlbox',
|
||||
'converse-core',
|
||||
'converse-disco',
|
||||
@ -90,8 +86,10 @@
|
||||
'converse-muc-views',
|
||||
'converse-notification',
|
||||
'converse-omemo',
|
||||
'converse-oauth',
|
||||
'converse-ping',
|
||||
'converse-profile',
|
||||
'converse-push',
|
||||
'converse-register',
|
||||
'converse-roomslist',
|
||||
'converse-roster',
|
||||
@ -153,6 +151,64 @@
|
||||
_converse.DEFAULT_IMAGE_TYPE = 'image/png';
|
||||
_converse.DEFAULT_IMAGE = "iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwHCy455JBsggAABkJJREFUeNrtnM1PE1sUwHvvTD8otWLHST/Gimi1CEgr6M6FEWuIBo2pujDVsNDEP8GN/4MbN7oxrlipG2OCgZgYlxAbkRYw1KqkIDRCSkM7nXvvW8x7vjyNeQ9m7p1p3z1LQk/v/Dhz7vkEXL161cHl9wI5Ag6IA+KAOCAOiAPigDggLhwQB2S+iNZ+PcYY/SWEEP2HAAAIoSAIoihCCP+ngDDGtVotGAz29/cfOXJEUZSOjg6n06lp2sbGRqlUWlhYyGazS0tLbrdbEASrzgksyeYJId3d3el0uqenRxRFAAAA4KdfIIRgjD9+/Pj8+fOpqSndslofEIQwHA6Pjo4mEon//qmFhYXHjx8vLi4ihBgDEnp7e9l8E0Jo165dQ0NDd+/eDYVC2/qsJElDQ0OEkKWlpa2tLZamxAhQo9EIBoOjo6MXL17csZLe3l5FUT59+lQul5l5JRaAVFWNRqN37tw5ceKEQVWRSOTw4cOFQuHbt2+iKLYCIISQLMu3b99OJpOmKAwEAgcPHszn8+vr6wzsiG6UQQhxuVyXLl0aGBgwUW0sFstkMl6v90fo1KyAMMYDAwPnzp0zXfPg4GAqlWo0Gk0MiBAiy/L58+edTqf5Aa4onj59OhaLYYybFRCEMBaL0fNxBw4cSCQStN0QRUBut3t4eJjq6U+dOiVJElVPRBFQIBDo6+ujCqirqyscDlONGykC2lYyYSR6pBoQQapHZwAoHo/TuARYAOrs7GQASFEUqn6aIiBJkhgA6ujooFpUo6iaTa7koFwnaoWadLNe81tbWwzoaJrWrICWl5cZAFpbW6OabVAEtLi4yABQsVjUNK0pAWWzWQaAcrlcswKanZ1VVZUqHYRQEwOq1Wpv3ryhCmh6erpcLjdrNl+v1ycnJ+l5UELI27dvv3//3qxxEADgy5cvExMT9Mznw4cPtFtAdAPFarU6Pj5eKpVM17yxsfHy5cvV1VXazXu62gVBKBQKT58+rdVqJqrFGL948eLdu3dU8/g/H4FBUaJYLAqC0NPTY9brMD4+PjY25mDSracOCABACJmZmXE6nUePHjWu8NWrV48ePSKEsGlAs7Agfd5nenq6Wq0mk0kjDzY2NvbkyRMIIbP2PLvhBUEQ8vl8NpuNx+M+n29bzhVjvLKycv/+/YmJCcazQuwA6YzW1tYmJyf1SY+2trZ/rRk1Go1SqfT69esHDx4UCgVmNaa/zZ/9ABUhRFXVYDB48uTJeDweiUQkSfL7/T9MA2NcqVTK5fLy8vL8/PzU1FSxWHS5XJaM4wGr9sUwxqqqer3eUCgkSZJuUBBCfTRvc3OzXC6vrKxUKhWn02nhCJ5lM4oQQo/HgxD6+vXr58+fHf8sDOp+HQDg8XgclorFU676dKLlo6yWRdItIBwQB8QBcUCtfosRQjRNQwhhjPUC4w46WXryBSHU1zgEQWBz99EFhDGu1+t+v//48ePxeFxRlD179ng8nh0Efgiher2+vr6ur3HMzMysrq7uTJVdACGEurq6Ll++nEgkPB7Pj9jPoDHqOxyqqubz+WfPnuVyuV9XPeyeagAAAoHArVu3BgcHab8CuVzu4cOHpVKJUnfA5GweY+xyuc6cOXPv3r1IJMLAR8iyPDw8XK/Xi8Wiqqqmm5KZgBBC7e3tN27cuHbtGuPVpf7+/lAoNDs7W61WzfVKpgHSSzw3b95MpVKW3MfRaDQSiczNzVUqFRMZmQOIEOL1eq9fv3727FlL1t50URRFluX5+flqtWpWEGAOIFEUU6nUlStXLKSjy759+xwOx9zcnKZpphzGHMzhcDiTydgk9r1w4YIp7RPTAAmCkMlk2FeLf/tIEKbTab/fbwtAhJBoNGrutpNx6e7uPnTokC1eMU3T0um0DZPMkZER6wERQnw+n/FFSxpy7Nix3bt3WwwIIcRgIWnHkkwmjecfRgGx7DtuV/r6+iwGhDHev3+/bQF1dnYaH6E2CkiWZdsC2rt3r8WAHA5HW1ubbQGZcjajgOwTH/4qNko1Wlg4IA6IA+KAOKBWBUQIsfNojyliKIoRRfH9+/dut9umf3wzpoUNNQ4BAJubmwz+ic+OxefzWWlBhJD29nbug7iT5sIBcUAcEAfEAXFAHBAHxOVn+QMrmWpuPZx12gAAAABJRU5ErkJggg==";
|
||||
|
||||
_converse.TIMEOUTS = { // Set as module attr so that we can override in tests.
|
||||
'PAUSED': 10000,
|
||||
'INACTIVE': 90000
|
||||
};
|
||||
|
||||
// XEP-0085 Chat states
|
||||
// http://xmpp.org/extensions/xep-0085.html
|
||||
_converse.INACTIVE = 'inactive';
|
||||
_converse.ACTIVE = 'active';
|
||||
_converse.COMPOSING = 'composing';
|
||||
_converse.PAUSED = 'paused';
|
||||
_converse.GONE = 'gone';
|
||||
|
||||
// Default configuration values
|
||||
// ----------------------------
|
||||
_converse.default_settings = {
|
||||
allow_non_roster_messaging: false,
|
||||
animate: true,
|
||||
authentication: 'login', // Available values are "login", "prebind", "anonymous" and "external".
|
||||
auto_away: 0, // Seconds after which user status is set to 'away'
|
||||
auto_login: false, // Currently only used in connection with anonymous login
|
||||
auto_reconnect: true,
|
||||
auto_xa: 0, // Seconds after which user status is set to 'xa'
|
||||
blacklisted_plugins: [],
|
||||
bosh_service_url: undefined,
|
||||
connection_options: {},
|
||||
credentials_url: null, // URL from where login credentials can be fetched
|
||||
csi_waiting_time: 0, // Support for XEP-0352. Seconds before client is considered idle and CSI is sent out.
|
||||
debug: false,
|
||||
default_state: 'online',
|
||||
expose_rid_and_sid: false,
|
||||
geouri_regex: /https:\/\/www.openstreetmap.org\/.*#map=[0-9]+\/([\-0-9.]+)\/([\-0-9.]+)\S*/g,
|
||||
geouri_replacement: 'https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2',
|
||||
jid: undefined,
|
||||
keepalive: true,
|
||||
locales_url: 'locale/{{{locale}}}/LC_MESSAGES/converse.json',
|
||||
locales: [
|
||||
'af', 'ar', 'bg', 'ca', 'de', 'es', 'eu', 'en', 'fr', 'he',
|
||||
'hu', 'id', 'it', 'ja', 'nb', 'nl',
|
||||
'pl', 'pt_BR', 'ru', 'tr', 'uk', 'zh_CN', 'zh_TW'
|
||||
],
|
||||
message_carbons: true,
|
||||
nickname: undefined,
|
||||
password: undefined,
|
||||
prebind_url: null,
|
||||
priority: 0,
|
||||
rid: undefined,
|
||||
root: window.document,
|
||||
sid: undefined,
|
||||
storage: 'session',
|
||||
strict_plugin_dependencies: false,
|
||||
trusted: true,
|
||||
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
|
||||
websocket_url: undefined,
|
||||
whitelisted_plugins: []
|
||||
};
|
||||
|
||||
|
||||
_converse.log = function (message, level, style='') {
|
||||
/* Logs messages to the browser's developer console.
|
||||
*
|
||||
@ -242,7 +298,6 @@
|
||||
|
||||
|
||||
_converse.initialize = function (settings, callback) {
|
||||
"use strict";
|
||||
settings = !_.isUndefined(settings) ? settings : {};
|
||||
const init_promise = u.getResolveablePromise();
|
||||
|
||||
@ -262,89 +317,21 @@
|
||||
_converse.connection.reset();
|
||||
_converse.off();
|
||||
_converse.stopListening();
|
||||
_converse._tearDown();
|
||||
_converse.tearDown();
|
||||
}
|
||||
|
||||
let unloadevent;
|
||||
if ('onpagehide' in window) {
|
||||
// Pagehide gets thrown in more cases than unload. Specifically it
|
||||
// gets thrown when the page is cached and not just
|
||||
// closed/destroyed. It's the only viable event on mobile Safari.
|
||||
// https://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/
|
||||
unloadevent = 'pagehide';
|
||||
_converse.unloadevent = 'pagehide';
|
||||
} else if ('onbeforeunload' in window) {
|
||||
unloadevent = 'beforeunload';
|
||||
_converse.unloadevent = 'beforeunload';
|
||||
} else if ('onunload' in window) {
|
||||
unloadevent = 'unload';
|
||||
_converse.unloadevent = 'unload';
|
||||
}
|
||||
|
||||
// Instance level constants
|
||||
this.TIMEOUTS = { // Set as module attr so that we can override in tests.
|
||||
'PAUSED': 10000,
|
||||
'INACTIVE': 90000
|
||||
};
|
||||
|
||||
// XEP-0085 Chat states
|
||||
// http://xmpp.org/extensions/xep-0085.html
|
||||
this.INACTIVE = 'inactive';
|
||||
this.ACTIVE = 'active';
|
||||
this.COMPOSING = 'composing';
|
||||
this.PAUSED = 'paused';
|
||||
this.GONE = 'gone';
|
||||
|
||||
// Default configuration values
|
||||
// ----------------------------
|
||||
this.default_settings = {
|
||||
allow_contact_requests: true,
|
||||
allow_non_roster_messaging: false,
|
||||
animate: true,
|
||||
authentication: 'login', // Available values are "login", "prebind", "anonymous" and "external".
|
||||
auto_away: 0, // Seconds after which user status is set to 'away'
|
||||
auto_login: false, // Currently only used in connection with anonymous login
|
||||
auto_reconnect: true,
|
||||
auto_subscribe: false,
|
||||
auto_xa: 0, // Seconds after which user status is set to 'xa'
|
||||
blacklisted_plugins: [],
|
||||
bosh_service_url: undefined,
|
||||
connection_options: {},
|
||||
credentials_url: null, // URL from where login credentials can be fetched
|
||||
csi_waiting_time: 0, // Support for XEP-0352. Seconds before client is considered idle and CSI is sent out.
|
||||
debug: false,
|
||||
default_state: 'online',
|
||||
expose_rid_and_sid: false,
|
||||
filter_by_resource: false,
|
||||
forward_messages: false,
|
||||
geouri_regex: /https:\/\/www.openstreetmap.org\/.*#map=[0-9]+\/([\-0-9.]+)\/([\-0-9.]+)\S*/g,
|
||||
geouri_replacement: 'https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2',
|
||||
hide_offline_users: false,
|
||||
include_offline_state: false,
|
||||
jid: undefined,
|
||||
keepalive: true,
|
||||
locales_url: 'locale/{{{locale}}}/LC_MESSAGES/converse.json',
|
||||
locales: [
|
||||
'af', 'ar', 'bg', 'ca', 'de', 'es', 'eu', 'en', 'fr', 'he',
|
||||
'hu', 'id', 'it', 'ja', 'nb', 'nl',
|
||||
'pl', 'pt_BR', 'ru', 'tr', 'uk', 'zh_CN', 'zh_TW'
|
||||
],
|
||||
message_carbons: true,
|
||||
nickname: undefined,
|
||||
password: undefined,
|
||||
prebind_url: null,
|
||||
priority: 0,
|
||||
registration_domain: '',
|
||||
rid: undefined,
|
||||
root: window.document,
|
||||
show_only_online_users: false,
|
||||
show_send_button: false,
|
||||
sid: undefined,
|
||||
storage: 'session',
|
||||
strict_plugin_dependencies: false,
|
||||
synchronize_availability: true,
|
||||
trusted: true,
|
||||
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
|
||||
websocket_url: undefined,
|
||||
whitelisted_plugins: []
|
||||
};
|
||||
_.assignIn(this, this.default_settings);
|
||||
// Allow only whitelisted configuration attributes to be overwritten
|
||||
_.assignIn(this, _.pick(settings, _.keys(this.default_settings)));
|
||||
@ -460,7 +447,8 @@
|
||||
window.addEventListener('focus', _converse.onUserActivity);
|
||||
window.addEventListener('keypress', _converse.onUserActivity);
|
||||
window.addEventListener('mousemove', _converse.onUserActivity);
|
||||
window.addEventListener(unloadevent, _converse.onUserActivity);
|
||||
const options = {'once': true, 'passive': true};
|
||||
window.addEventListener(_converse.unloadevent, _converse.onUserActivity, options);
|
||||
_converse.everySecondTrigger = window.setInterval(_converse.onEverySecond, 1000);
|
||||
};
|
||||
|
||||
@ -492,7 +480,7 @@
|
||||
__('The connection has dropped, attempting to reconnect.')
|
||||
);
|
||||
_converse.connection.reconnecting = true;
|
||||
_converse._tearDown();
|
||||
_converse.tearDown();
|
||||
_converse.logIn(null, true);
|
||||
}, 3000, {'leading': true});
|
||||
|
||||
@ -500,7 +488,7 @@
|
||||
_converse.log('DISCONNECTED');
|
||||
delete _converse.connection.reconnecting;
|
||||
_converse.connection.reset();
|
||||
_converse._tearDown();
|
||||
_converse.tearDown();
|
||||
_converse.emit('disconnected');
|
||||
};
|
||||
|
||||
@ -649,8 +637,9 @@
|
||||
_converse.session = new Backbone.Model();
|
||||
const id = b64_sha1('converse.bosh-session');
|
||||
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage
|
||||
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
|
||||
_converse.session.browserStorage = new Backbone.BrowserStorage.session(id);
|
||||
_converse.session.fetch();
|
||||
_converse.emit('sessionInitialized');
|
||||
};
|
||||
|
||||
this.clearSession = function () {
|
||||
@ -669,7 +658,7 @@
|
||||
if (!_.isUndefined(_converse.connection)) {
|
||||
_converse.connection.disconnect();
|
||||
} else {
|
||||
_converse._tearDown();
|
||||
_converse.tearDown();
|
||||
}
|
||||
// Recreate all the promises
|
||||
_.each(_.keys(_converse.promises), addPromise);
|
||||
@ -727,6 +716,7 @@
|
||||
if( document[hidden] !== undefined ) {
|
||||
_.partial(_converse.saveWindowState, _, hidden)({type: document[hidden] ? "blur" : "focus"});
|
||||
}
|
||||
_converse.emit('registeredGlobalEventHandlers');
|
||||
};
|
||||
|
||||
this.enableCarbons = function () {
|
||||
@ -748,7 +738,7 @@
|
||||
'An error occured while trying to enable message carbons.',
|
||||
Strophe.LogLevel.ERROR);
|
||||
} else {
|
||||
this.session.save({carbons_enabled: true});
|
||||
this.session.save({'carbons_enabled': true});
|
||||
_converse.log('Message carbons have been enabled.');
|
||||
}
|
||||
}, null, "iq", null, "enablecarbons");
|
||||
@ -1087,7 +1077,7 @@
|
||||
};
|
||||
|
||||
|
||||
this._tearDown = function () {
|
||||
this.tearDown = function () {
|
||||
/* Remove those views which are only allowed with a valid
|
||||
* connection.
|
||||
*/
|
||||
@ -1099,7 +1089,7 @@
|
||||
window.removeEventListener('focus', _converse.onUserActivity);
|
||||
window.removeEventListener('keypress', _converse.onUserActivity);
|
||||
window.removeEventListener('mousemove', _converse.onUserActivity);
|
||||
window.removeEventListener(unloadevent, _converse.onUserActivity);
|
||||
window.removeEventListener(_converse.unloadevent, _converse.onUserActivity);
|
||||
window.clearInterval(_converse.everySecondTrigger);
|
||||
_converse.emit('afterTearDown');
|
||||
return _converse;
|
||||
@ -1298,6 +1288,11 @@
|
||||
'send' (stanza) {
|
||||
_converse.connection.send(stanza);
|
||||
},
|
||||
'sendIQ' (stanza) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// The public API
|
||||
|
@ -36,24 +36,24 @@
|
||||
this.waitUntilFeaturesDiscovered = utils.getResolveablePromise();
|
||||
|
||||
this.dataforms = new Backbone.Collection();
|
||||
this.dataforms.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
||||
this.dataforms.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.dataforms-{this.get('jid')}`)
|
||||
);
|
||||
|
||||
this.features = new Backbone.Collection();
|
||||
this.features.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
||||
this.features.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.features-${this.get('jid')}`)
|
||||
);
|
||||
this.features.on('add', this.onFeatureAdded, this);
|
||||
|
||||
this.identities = new Backbone.Collection();
|
||||
this.identities.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
||||
this.identities.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.identities-${this.get('jid')}`)
|
||||
);
|
||||
this.fetchFeatures();
|
||||
|
||||
this.items = new _converse.DiscoEntities();
|
||||
this.items.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
||||
this.items.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.disco-items-${this.get('jid')}`)
|
||||
);
|
||||
this.items.fetch();
|
||||
@ -125,7 +125,12 @@
|
||||
},
|
||||
|
||||
queryInfo () {
|
||||
_converse.api.disco.info(this.get('jid'), null, this.onInfo.bind(this));
|
||||
_converse.api.disco.info(this.get('jid'), null)
|
||||
.then((stanza) => this.onInfo(stanza))
|
||||
.catch((iq) => {
|
||||
this.waitUntilFeaturesDiscovered.resolve();
|
||||
_converse.log(iq, Strophe.LogLevel.ERROR);
|
||||
});
|
||||
},
|
||||
|
||||
onDiscoItems (stanza) {
|
||||
@ -137,7 +142,12 @@
|
||||
}
|
||||
const jid = item.getAttribute('jid');
|
||||
if (_.isUndefined(this.items.get(jid))) {
|
||||
this.items.create({'jid': jid});
|
||||
const entity = _converse.disco_entities.get(jid);
|
||||
if (entity) {
|
||||
this.items.add(entity);
|
||||
} else {
|
||||
this.items.create({'jid': jid});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -216,12 +226,34 @@
|
||||
return this;
|
||||
}
|
||||
|
||||
function initStreamFeatures () {
|
||||
_converse.stream_features = new Backbone.Collection();
|
||||
_converse.stream_features.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.stream-features-${_converse.bare_jid}`)
|
||||
);
|
||||
_converse.stream_features.fetch({
|
||||
success (collection) {
|
||||
if (collection.length === 0 && _converse.connection.features) {
|
||||
_.forEach(
|
||||
_converse.connection.features.childNodes,
|
||||
(feature) => {
|
||||
_converse.stream_features.create({
|
||||
'name': feature.nodeName,
|
||||
'xmlns': feature.getAttribute('xmlns')
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
_converse.emit('streamFeaturesAdded');
|
||||
}
|
||||
|
||||
function initializeDisco () {
|
||||
addClientFeatures();
|
||||
_converse.connection.addHandler(onDiscoInfoRequest, Strophe.NS.DISCO_INFO, 'iq', 'get', null, null);
|
||||
|
||||
_converse.disco_entities = new _converse.DiscoEntities();
|
||||
_converse.disco_entities.browserStorage = new Backbone.BrowserStorage[_converse.storage](
|
||||
_converse.disco_entities.browserStorage = new Backbone.BrowserStorage.session(
|
||||
b64_sha1(`converse.disco-entities-${_converse.bare_jid}`)
|
||||
);
|
||||
|
||||
@ -235,6 +267,7 @@
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}
|
||||
|
||||
_converse.api.listen.on('sessionInitialized', initStreamFeatures);
|
||||
_converse.api.listen.on('reconnected', initializeDisco);
|
||||
_converse.api.listen.on('connected', initializeDisco);
|
||||
|
||||
@ -290,6 +323,15 @@
|
||||
* @namespace
|
||||
*/
|
||||
'disco': {
|
||||
'stream': {
|
||||
'getFeature': function (name, xmlns) {
|
||||
if (_.isNil(name) || _.isNil(xmlns)) {
|
||||
throw new Error("name and xmlns need to be provided when calling disco.stream.getFeature");
|
||||
}
|
||||
return _converse.stream_features.findWhere({'name': name, 'xmlns': xmlns});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The "own" grouping
|
||||
* @namespace
|
||||
@ -389,7 +431,7 @@
|
||||
}
|
||||
},
|
||||
|
||||
'info' (jid, node, callback, errback, timeout) {
|
||||
'info' (jid, node) {
|
||||
const attrs = {xmlns: Strophe.NS.DISCO_INFO};
|
||||
if (node) {
|
||||
attrs.node = node;
|
||||
@ -399,7 +441,7 @@
|
||||
'to':jid,
|
||||
'type':'get'
|
||||
}).c('query', attrs);
|
||||
_converse.connection.sendIQ(info, callback, errback, timeout);
|
||||
return _converse.api.sendIQ(info);
|
||||
},
|
||||
|
||||
'items' (jid, node, callback, errback, timeout) {
|
||||
@ -481,10 +523,8 @@
|
||||
* (String) entity_jid - The JID of the entity which might have the identity
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.api.waitUntil('discoInitialized').then(() => {
|
||||
_converse.api.disco.entities.get(entity_jid, true)
|
||||
.then((entity) => resolve(entity.getIdentity(category, type)));
|
||||
})
|
||||
_converse.api.disco.entities.get(entity_jid, true)
|
||||
.then((entity) => resolve(entity.getIdentity(category, type)));
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
(function (root, factory) {
|
||||
define(["converse-core",
|
||||
"tpl!dragresize",
|
||||
"templates/dragresize.html",
|
||||
"converse-chatview",
|
||||
"converse-controlbox"
|
||||
], factory);
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
(function (root, factory) {
|
||||
define(["converse-core",
|
||||
"tpl!inverse_brand_heading",
|
||||
"templates/inverse_brand_heading.html",
|
||||
"converse-chatview",
|
||||
"converse-controlbox",
|
||||
"converse-muc",
|
||||
|
@ -9,7 +9,7 @@
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"converse-core",
|
||||
"tpl!chatbox",
|
||||
"templates/chatbox.html",
|
||||
"converse-chatview",
|
||||
], factory);
|
||||
}(this, function (converse, tpl_chatbox) {
|
||||
@ -138,7 +138,7 @@
|
||||
'type': 'headline',
|
||||
'from': from_jid
|
||||
});
|
||||
chatbox.createMessage(message, undefined, message);
|
||||
chatbox.createMessage(message, message);
|
||||
_converse.emit('message', {'chatbox': chatbox, 'stanza': message});
|
||||
}
|
||||
return true;
|
||||
|
@ -11,14 +11,14 @@
|
||||
(function (root, factory) {
|
||||
define(["sizzle",
|
||||
"converse-core",
|
||||
"utils",
|
||||
"converse-disco",
|
||||
"strophe.rsm"
|
||||
], factory);
|
||||
}(this, function (sizzle, converse, utils) {
|
||||
}(this, function (sizzle, converse) {
|
||||
"use strict";
|
||||
const CHATROOMS_TYPE = 'chatroom';
|
||||
const { Promise, Strophe, $iq, _, moment } = converse.env;
|
||||
const u = converse.env.utils;
|
||||
|
||||
const RSM_ATTRIBUTES = ['max', 'first', 'last', 'after', 'before', 'index', 'count'];
|
||||
// XEP-0313 Message Archive Management
|
||||
@ -128,7 +128,7 @@
|
||||
//
|
||||
// New functions which don't exist yet can also be added.
|
||||
ChatBox: {
|
||||
getMessageAttributesFromStanza (message, delay, original_stanza) {
|
||||
getMessageAttributesFromStanza (message, original_stanza) {
|
||||
const attrs = this.__super__.getMessageAttributesFromStanza.apply(this, arguments);
|
||||
const archive_id = getMessageArchiveID(original_stanza);
|
||||
if (archive_id) {
|
||||
@ -153,7 +153,7 @@
|
||||
*/
|
||||
if (this.disable_mam) { return; }
|
||||
const { _converse } = this.__super__,
|
||||
most_recent_msg = utils.getMostRecentMessage(this.model);
|
||||
most_recent_msg = u.getMostRecentMessage(this.model);
|
||||
|
||||
if (_.isNil(most_recent_msg)) {
|
||||
this.fetchArchivedMessages();
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Converse.js
|
||||
// https://conversejs.org
|
||||
//
|
||||
// Copyright (c) 2012-2018, the Converse.js developers
|
||||
// Copyright (c) 2013-2018, the Converse.js developers
|
||||
// Licensed under the Mozilla Public License (MPLv2)
|
||||
|
||||
(function (root, factory) {
|
||||
@ -10,12 +10,12 @@
|
||||
"xss",
|
||||
"emojione",
|
||||
"filesize",
|
||||
"tpl!action",
|
||||
"tpl!csn",
|
||||
"tpl!file_progress",
|
||||
"tpl!info",
|
||||
"tpl!message",
|
||||
"tpl!spoiler_message"
|
||||
"templates/action.html",
|
||||
"templates/csn.html",
|
||||
"templates/file_progress.html",
|
||||
"templates/info.html",
|
||||
"templates/message.html",
|
||||
"templates/spoiler_message.html"
|
||||
], factory);
|
||||
}(this, function (
|
||||
converse,
|
||||
@ -145,6 +145,7 @@
|
||||
msg_content.innerHTML = _.flow(
|
||||
_.partial(u.geoUriToHttp, _, _converse.geouri_replacement),
|
||||
u.addHyperlinks,
|
||||
u.renderNewLines,
|
||||
_.partial(u.addEmoji, _converse, emojione, _)
|
||||
)(text);
|
||||
}
|
||||
@ -225,7 +226,7 @@
|
||||
},
|
||||
|
||||
getExtraMessageClasses () {
|
||||
let extra_classes = this.model.get('delayed') && 'delayed' || '';
|
||||
let extra_classes = this.model.get('is_delayed') && 'delayed' || '';
|
||||
if (this.model.get('type') === 'groupchat' && this.model.get('sender') === 'them') {
|
||||
if (this.model.collection.chatbox.isUserMentioned(this.model.get('message'))) {
|
||||
// Add special class to mark groupchat messages
|
||||
|
@ -8,10 +8,10 @@
|
||||
|
||||
(function (root, factory) {
|
||||
define(["converse-core",
|
||||
"tpl!chatbox_minimize",
|
||||
"tpl!toggle_chats",
|
||||
"tpl!trimmed_chat",
|
||||
"tpl!chats_panel",
|
||||
"templates/chatbox_minimize.html",
|
||||
"templates/toggle_chats.html",
|
||||
"templates/trimmed_chat.html",
|
||||
"templates/chats_panel.html",
|
||||
"converse-chatview"
|
||||
], factory);
|
||||
}(this, function (
|
||||
@ -52,16 +52,6 @@
|
||||
//
|
||||
// New functions which don't exist yet can also be added.
|
||||
|
||||
registerGlobalEventHandlers () {
|
||||
const { _converse } = this.__super__;
|
||||
window.addEventListener("resize", _.debounce(function (ev) {
|
||||
if (_converse.connection.connected) {
|
||||
_converse.chatboxviews.trimChats();
|
||||
}
|
||||
}, 200));
|
||||
return this.__super__.registerGlobalEventHandlers.apply(this, arguments);
|
||||
},
|
||||
|
||||
ChatBox: {
|
||||
initialize () {
|
||||
this.__super__.initialize.apply(this, arguments);
|
||||
@ -541,6 +531,15 @@
|
||||
_converse.emit('minimizedChatsInitialized');
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
|
||||
|
||||
_converse.on('registeredGlobalEventHandlers', function () {
|
||||
window.addEventListener("resize", _.debounce(function (ev) {
|
||||
if (_converse.connection.connected) {
|
||||
_converse.chatboxviews.trimChats();
|
||||
}
|
||||
}, 200));
|
||||
});
|
||||
|
||||
_converse.on('controlBoxOpened', function (chatbox) {
|
||||
// Wrapped in anon method because at scan time, chatboxviews
|
||||
// attr not set yet.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user