Compare commits
119 Commits
v10.1.2
...
main-chapr
Author | SHA1 | Date | |
---|---|---|---|
a461444bed | |||
1307f87912 | |||
23cf858a02 | |||
b49146b36f | |||
8d67dce865 | |||
543807aa50 | |||
|
82a8c3f9fc | ||
|
3e680e88d8 | ||
|
005f5374f0 | ||
|
79bb8e76ce | ||
|
61192f91d9 | ||
|
e31d4c7bac | ||
|
c30569dfd3 | ||
|
5e02b9bd5d | ||
|
9114db8764 | ||
|
bc7621c25d | ||
|
ae518aa2c3 | ||
|
e4a4b2819c | ||
|
5310021b67 | ||
|
e18fdd56b1 | ||
|
94963662e7 | ||
|
4f14d50f5d | ||
|
699ab71f21 | ||
|
daeb641530 | ||
|
6e71555ee4 | ||
|
27d61411ab | ||
|
3328e1c94c | ||
|
c63c787a6d | ||
|
0efeead71a | ||
|
5822fade32 | ||
|
621612d126 | ||
|
536350155d | ||
|
841a57fd66 | ||
|
175595098a | ||
|
03655b45b2 | ||
|
fa9ae16ead | ||
|
cb1f929045 | ||
|
9ba339a6d9 | ||
|
bc452596a7 | ||
|
2b732cdb94 | ||
|
1e4937bf41 | ||
|
8b28ffecfe | ||
|
80bf81db6f | ||
|
7fdbcd0e64 | ||
|
975a2c2305 | ||
|
abad4d054b | ||
|
b5b6d1f8b2 | ||
|
64aef7f70d | ||
|
4f0f210e21 | ||
|
c4299e92be | ||
|
0cc03e7e7a | ||
|
f9f246282b | ||
|
3e4a8b23fe | ||
|
cdda140137 | ||
|
0a15b003dc | ||
|
23539ecf47 | ||
|
efa448956e | ||
|
743f336dc5 | ||
|
8a0386fdcc | ||
|
b647f5463f | ||
|
46f2e40f91 | ||
|
8b1b4b6446 | ||
|
9407d00c67 | ||
|
f0d584aed6 | ||
|
2768c2a3ec | ||
|
8fb1716681 | ||
|
507cfa9ef2 | ||
|
5ef7807a68 | ||
|
952d3cf440 | ||
|
c9a95faa35 | ||
|
02185cee5f | ||
|
40290f27e7 | ||
|
bbfcb74eaa | ||
|
a2e618a8f6 | ||
|
ebbb39a9aa | ||
|
2d66a974d0 | ||
|
fa12dae7bc | ||
|
df25e16438 | ||
|
c39d61f62c | ||
|
01ce344d82 | ||
|
bb428fa1d7 | ||
|
5a710e4601 | ||
|
f91f4cb7ab | ||
|
f2ac748e06 | ||
|
27a47c6ee8 | ||
|
0a338feb40 | ||
|
d74daccfbb | ||
|
5c3acc8a4d | ||
|
48e7987f38 | ||
|
4d2a8e9f8d | ||
|
3d0e9a7374 | ||
|
fb054c40be | ||
|
c3c666e568 | ||
|
6b365458f5 | ||
|
885a3d92b5 | ||
|
6df80507f3 | ||
|
16754c15aa | ||
|
70a10efd49 | ||
|
9a63629b40 | ||
|
dcfc0d50f4 | ||
|
fde55bea2c | ||
|
3530ccc35d | ||
|
05c5cd1046 | ||
|
c38c706079 | ||
|
e1e93c2ec9 | ||
|
16b442ac19 | ||
|
0122bd7bab | ||
|
56259fd22e | ||
|
85181053e6 | ||
|
26062df4e5 | ||
|
2fb9fec8f8 | ||
|
d4cb67dc5f | ||
|
ad7b4ae343 | ||
|
57f489f61b | ||
|
6ce8879e9c | ||
|
1ee4cce2fd | ||
|
b69e5b5482 | ||
|
3f6ad0d950 | ||
|
9899351597 |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"parser": "@babel/eslint-parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2017,
|
"ecmaVersion": 2020,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"allowImportExportEverywhere": true
|
"allowImportExportEverywhere": true
|
||||||
},
|
},
|
||||||
@ -10,8 +10,12 @@
|
|||||||
"jasmine": true,
|
"jasmine": true,
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"plugins": [],
|
"plugins": ["@typescript-eslint"],
|
||||||
"extends": ["eslint:recommended"],
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
],
|
||||||
"globals": {
|
"globals": {
|
||||||
"Uint8Array": true,
|
"Uint8Array": true,
|
||||||
"Promise": true,
|
"Promise": true,
|
||||||
|
3
.github/workflows/karma-tests.yml
vendored
3
.github/workflows/karma-tests.yml
vendored
@ -8,6 +8,7 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -17,7 +18,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x]
|
node-version: [18.x]
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,9 @@
|
|||||||
# Distribution directory
|
# Distribution directory
|
||||||
dist
|
dist
|
||||||
|
|
||||||
|
# conversejs/media repo checkout
|
||||||
|
media
|
||||||
|
|
||||||
# Editor fluff
|
# Editor fluff
|
||||||
*~
|
*~
|
||||||
.sw?
|
.sw?
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"arrowParens": "avoid",
|
|
||||||
"printWidth": 120,
|
"printWidth": 120,
|
||||||
"quoteProps": "preserve",
|
"quoteProps": "preserve",
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
|
36541
3rdparty/libsignal-protocol.js
vendored
Normal file
36541
3rdparty/libsignal-protocol.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
3rdparty/libsignal-protocol.min.js
vendored
Normal file
1
3rdparty/libsignal-protocol.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
32
CHANGES.md
32
CHANGES.md
@ -1,5 +1,35 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 10.1.6 (2023-08-31)
|
||||||
|
|
||||||
|
- #3246: Badge color not responsive to dark theme
|
||||||
|
- Fix a GIF rendering bug that causes a memory overflow
|
||||||
|
|
||||||
|
## 10.1.5 (2023-06-29)
|
||||||
|
|
||||||
|
- #3209: Fix error when importing the `converse` global with bootstrap modal API
|
||||||
|
- #3207: `.po` translation files weren't included in previous release
|
||||||
|
- Updated Galician and Portuguese translations
|
||||||
|
|
||||||
|
## 10.1.4 (2023-06-25)
|
||||||
|
|
||||||
|
- Fix `dist` directory not included in NPM package
|
||||||
|
|
||||||
|
## 10.1.3 (2023-06-23)
|
||||||
|
|
||||||
|
- Add the ability to set roles and affiliations via the MUC occupant modal
|
||||||
|
- Fix `isOnlyEmojis is not a function` when using only `@converse/headless`
|
||||||
|
- Fix `autojoin` checkbox state in MUC bookmark form
|
||||||
|
- Remove call to `api.confirm` in `@converse/headless`
|
||||||
|
- Generate TypeScript declaration files into `dist/types`
|
||||||
|
- Removed documentation about the no longer implemented `fullname` option.
|
||||||
|
- Updated translations
|
||||||
|
- #3123: Contacts do not show up online until chat is opened with them.
|
||||||
|
- #3156: Add function to prevent drag stutter effect over iframes when resize is called in overlay mode
|
||||||
|
- #3165: Use configured nickname in profile view in the control box
|
||||||
|
|
||||||
|
- New config option [stanza_timeout](https://conversejs.org/docs/html/configuration.html#stanza-timeout)
|
||||||
|
|
||||||
## 10.1.2 (2023-02-17)
|
## 10.1.2 (2023-02-17)
|
||||||
|
|
||||||
- #1490: Busy-loop when fetching registration form fails
|
- #1490: Busy-loop when fetching registration form fails
|
||||||
@ -22,7 +52,7 @@
|
|||||||
- #2925: File upload is not always enabled
|
- #2925: File upload is not always enabled
|
||||||
- #3001: Add option to save SCRAM details and to use them to stay logged in upon reload
|
- #3001: Add option to save SCRAM details and to use them to stay logged in upon reload
|
||||||
- Add a "Add to Contacts" button in MUC occupant modals
|
- Add a "Add to Contacts" button in MUC occupant modals
|
||||||
- Updated tranlsations and new language Uyghur
|
- Updated translations and add support for Uyghur
|
||||||
|
|
||||||
- New config option [reuse_scram_keys](https://conversejs.org/docs/html/configuration.html#reuse-scram-keys)
|
- New config option [reuse_scram_keys](https://conversejs.org/docs/html/configuration.html#reuse-scram-keys)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* An XMPP chat client that runs in the browser.
|
* An XMPP chat client that runs in the browser.
|
||||||
*
|
*
|
||||||
* Version: 10.1.2
|
* Version: 10.1.6
|
||||||
*
|
*
|
||||||
* Copyright: JC Brand 2013-2018
|
* Copyright: JC Brand 2013-2018
|
||||||
* Except for 3rd party dependencies.
|
* Except for 3rd party dependencies.
|
||||||
|
73
Makefile
73
Makefile
@ -3,13 +3,11 @@ BOOTSTRAP = ./node_modules/
|
|||||||
BUILDDIR = ./docs
|
BUILDDIR = ./docs
|
||||||
KARMA ?= ./node_modules/.bin/karma
|
KARMA ?= ./node_modules/.bin/karma
|
||||||
CLEANCSS ?= ./node_modules/clean-css-cli/bin/cleancss
|
CLEANCSS ?= ./node_modules/clean-css-cli/bin/cleancss
|
||||||
ESLINT ?= ./node_modules/.bin/eslint
|
|
||||||
HTTPSERVE ?= ./node_modules/.bin/http-server
|
HTTPSERVE ?= ./node_modules/.bin/http-server
|
||||||
HTTPSERVE_PORT ?= 8000
|
HTTPSERVE_PORT ?= 8000
|
||||||
INKSCAPE ?= inkscape
|
INKSCAPE ?= inkscape
|
||||||
INSTALL ?= install
|
INSTALL ?= install
|
||||||
JSDOC ?= ./node_modules/.bin/jsdoc
|
JSDOC ?= ./node_modules/.bin/jsdoc
|
||||||
LERNA ?= ./node_modules/.bin/lerna
|
|
||||||
OXIPNG ?= oxipng
|
OXIPNG ?= oxipng
|
||||||
PAPER =
|
PAPER =
|
||||||
RJS ?= ./node_modules/.bin/r.js
|
RJS ?= ./node_modules/.bin/r.js
|
||||||
@ -60,13 +58,14 @@ serve: node_modules dist
|
|||||||
serve_bg: node_modules
|
serve_bg: node_modules
|
||||||
$(HTTPSERVE) -p $(HTTPSERVE_PORT) -c-1 -s &
|
$(HTTPSERVE) -p $(HTTPSERVE_PORT) -c-1 -s &
|
||||||
|
|
||||||
|
certs:
|
||||||
|
mkdir certs
|
||||||
|
cd certs && openssl req -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out chat.example.org.crt -keyout chat.example.org.key
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
## Translation machinery
|
## Translation machinery
|
||||||
|
|
||||||
dist/converse-no-dependencies.js: src webpack/webpack.common.js webpack/webpack.nodeps.js @converse/headless node_modules
|
GETTEXT = $(XGETTEXT) --from-code=UTF-8 --language=JavaScript --keyword=__ --keyword=___ --keyword=i18n_ --force-po --output=src/i18n/converse.pot --package-name=Converse.js --copyright-holder="Jan-Carel Brand" --package-version=10.1.6 dist/converse-no-dependencies.js -c
|
||||||
npm run nodeps
|
|
||||||
|
|
||||||
GETTEXT = $(XGETTEXT) --from-code=UTF-8 --language=JavaScript --keyword=__ --keyword=___ --keyword=i18n_ --force-po --output=src/i18n/converse.pot --package-name=Converse.js --copyright-holder="Jan-Carel Brand" --package-version=10.1.2 dist/converse-no-dependencies.js -c
|
|
||||||
|
|
||||||
src/i18n/converse.pot: dist/converse-no-dependencies.js
|
src/i18n/converse.pot: dist/converse-no-dependencies.js
|
||||||
$(GETTEXT) 2>&1 > /dev/null; exit $$?;
|
$(GETTEXT) 2>&1 > /dev/null; exit $$?;
|
||||||
@ -83,10 +82,9 @@ po:
|
|||||||
########################################################################
|
########################################################################
|
||||||
## Release management
|
## Release management
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: version
|
||||||
release:
|
version:
|
||||||
find ./src -name "*~" -exec rm {} \;
|
$(SED) -i '/^export const VERSION_NAME =/s/=.*/= "v$(VERSION)";/' src/headless/shared/constants.js
|
||||||
$(SED) -i '/^_converse.VERSION_NAME =/s/=.*/= "v$(VERSION)";/' src/headless/core.js
|
|
||||||
$(SED) -i '/Version:/s/:.*/: $(VERSION)/' COPYRIGHT
|
$(SED) -i '/Version:/s/:.*/: $(VERSION)/' COPYRIGHT
|
||||||
$(SED) -i '/Project-Id-Version:/s/:.*/: Converse.js $(VERSION)\n"/' src/i18n/converse.pot
|
$(SED) -i '/Project-Id-Version:/s/:.*/: Converse.js $(VERSION)\n"/' src/i18n/converse.pot
|
||||||
$(SED) -i '/"version":/s/:.*/: "$(VERSION)",/' manifest.json
|
$(SED) -i '/"version":/s/:.*/: "$(VERSION)",/' manifest.json
|
||||||
@ -101,19 +99,33 @@ release:
|
|||||||
make pot
|
make pot
|
||||||
make po
|
make po
|
||||||
make dist
|
make dist
|
||||||
npm pack
|
|
||||||
cd src/headless && npm pack
|
release-checkout:
|
||||||
|
git clone git@github.com:conversejs/converse.js.git --depth 1 --branch $(BRANCH) release-$(BRANCH)
|
||||||
|
cd release-$(BRANCH) && make dist
|
||||||
|
|
||||||
|
.PHONY: publish
|
||||||
|
publish:
|
||||||
|
make release-checkout
|
||||||
|
cd release-$(BRANCH) && npm pack && npm publish
|
||||||
|
cd release-$(BRANCH)/src/headless && npm pack && npm publish
|
||||||
|
find ./release-$(BRANCH)/ -name "converse.js-*.tgz" -exec mv {} . \;
|
||||||
|
find ./release-$(BRANCH)/src/headless -name "converse-headless-*.tgz" -exec mv {} . \;
|
||||||
|
rm -rf release-$(BRANCH)
|
||||||
|
|
||||||
.PHONY: postrelease
|
.PHONY: postrelease
|
||||||
postrelease:
|
postrelease:
|
||||||
$(SED) -i '/^_converse.VERSION_NAME =/s/=.*/= "v$(VERSION)dev";/' src/headless/core.js
|
$(SED) -i '/^export const VERSION_NAME =/s/=.*/= "v$(VERSION)dev";/' src/headless/shared/constants.js
|
||||||
|
|
||||||
|
.PHONY: deploy
|
||||||
|
deploy:
|
||||||
|
git clone --branch v$(VERSION) git@github.com:conversejs/converse.js.git --depth 1 $(VERSION)
|
||||||
|
cd $(VERSION) && make node && ASSET_PATH=https://cdn.conversejs.org/$(VERSION)/dist/ make dist && make doc
|
||||||
|
cd .. && git pull && make node && ASSET_PATH=https://cdn.conversejs.org/dist/ make dist && make doc
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
## Install dependencies
|
## Install dependencies
|
||||||
|
|
||||||
$(LERNA):
|
|
||||||
npm install lerna
|
|
||||||
|
|
||||||
${NVM_DIR}/nvm.sh:
|
${NVM_DIR}/nvm.sh:
|
||||||
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
|
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
@ -125,12 +137,9 @@ nvm: ${NVM_DIR}/nvm.sh
|
|||||||
node: .nvmrc
|
node: .nvmrc
|
||||||
. $(HOME)/.nvm/nvm.sh && nvm install
|
. $(HOME)/.nvm/nvm.sh && nvm install
|
||||||
|
|
||||||
package-lock.json: package.json
|
node_modules: package.json src/headless/package.json
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
node_modules: $(LERNA) package.json package-lock.json src/headless/package.json src/headless/package-lock.json
|
|
||||||
npm run lerna
|
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
npm run clean
|
npm run clean
|
||||||
@ -147,6 +156,9 @@ devserver: node_modules
|
|||||||
########################################################################
|
########################################################################
|
||||||
## Builds
|
## Builds
|
||||||
|
|
||||||
|
dist/converse-no-dependencies.js: src webpack/webpack.common.js webpack/webpack.nodeps.js @converse/headless node_modules
|
||||||
|
npm run nodeps
|
||||||
|
|
||||||
dist/converse.js:: node_modules
|
dist/converse.js:: node_modules
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
@ -193,7 +205,16 @@ src/headless/dist/converse-headless.min.js: src webpack/webpack.common.js node_m
|
|||||||
|
|
||||||
dist:: node_modules src/* | dist/website.css dist/website.min.css
|
dist:: node_modules src/* | dist/website.css dist/website.min.css
|
||||||
npm run headless
|
npm run headless
|
||||||
npm run build
|
# Ideally this should just be `npm run build`.
|
||||||
|
# The additional steps are necessary to properly generate JSON chunk files
|
||||||
|
# from the .po files. The nodeps config uses preset-env with IE11.
|
||||||
|
# Somehow this is necessary.
|
||||||
|
npm run nodeps
|
||||||
|
$(eval TMPD := $(shell mktemp -d))
|
||||||
|
mv dist/locales $(TMPD) && \
|
||||||
|
npm run build && \
|
||||||
|
mv $(TMPD)/locales/*-po.js dist/locales/ && \
|
||||||
|
rm -rf $(TMPD)
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
install:: dist
|
install:: dist
|
||||||
@ -202,20 +223,24 @@ install:: dist
|
|||||||
cdn:: node_modules
|
cdn:: node_modules
|
||||||
npm run cdn
|
npm run cdn
|
||||||
|
|
||||||
|
.PHONY: types
|
||||||
|
types:: node_modules
|
||||||
|
npm run types
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
.PHONY: eslint
|
.PHONY: eslint
|
||||||
eslint: node_modules
|
eslint: node_modules
|
||||||
$(ESLINT) src/**/*.js
|
npm run lint
|
||||||
|
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: eslint | dist/converse.js dist/converse.css
|
check: eslint | dist/converse.js dist/converse.css
|
||||||
$(KARMA) start karma.conf.js $(ARGS)
|
npm run test -- $(ARGS)
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test:
|
||||||
$(KARMA) start karma.conf.js $(ARGS)
|
npm run test -- $(ARGS)
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
## Documentation
|
## Documentation
|
||||||
|
17
README.chapril.md
Normal file
17
README.chapril.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Construire une version Chapril de ConverseJS
|
||||||
|
|
||||||
|
```
|
||||||
|
cd .../conversejs
|
||||||
|
# La première fois, installer nvm (attention, ça va modifier le .bashrc, entre autres choses)
|
||||||
|
make nvm
|
||||||
|
|
||||||
|
export V=7.0.4
|
||||||
|
git rebase v${V?}
|
||||||
|
# [... Résoudre les conflits]
|
||||||
|
git checkout -b v${V?}-chapril
|
||||||
|
nvm install
|
||||||
|
make dist
|
||||||
|
# [... Tester les livrables présents dans dist/, et si tout est ok :]
|
||||||
|
make version VERSION=${V?}-chapril
|
||||||
|
rsync -av dist/ chapril-xmpp:/var/www/xmpp.chapril.org/public_html/dist-custom-chapril-${V?}/
|
||||||
|
```
|
13
README.md
13
README.md
@ -167,13 +167,13 @@ We accept donations via [Patreon](https://www.patreon.com/jcbrand) and [Liberapa
|
|||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="https://blokt.com?utm_source=conversejs" target="_blank" rel="noopener">
|
<a href="https://bairesdev.com/sponsoring-open-source-projects/?utm_source=conversejs" target="_blank" rel="noopener">
|
||||||
<img alt="Blokt Crypto & Privacy" src="https://raw.githubusercontent.com/conversejs/converse.js/541613d1fea8aef364af00180f60e959162e5e4b/logo/blokt.png" width="200">
|
<img alt="BairesDev" src="https://raw.githubusercontent.com/conversejs/media/main/logos/bairesdev-primary.png" width="200">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="https://www.keycdn.com?utm_source=conversejs" target="_blank" rel="noopener">
|
<a href="https://blokt.com?utm_source=conversejs" target="_blank" rel="noopener">
|
||||||
<img alt="KeyCDN" src="https://raw.githubusercontent.com/conversejs/converse.js/541613d1fea8aef364af00180f60e959162e5e4b/logo/keycdn.png" width="200">
|
<img alt="Blokt Crypto & Privacy" src="https://raw.githubusercontent.com/conversejs/converse.js/541613d1fea8aef364af00180f60e959162e5e4b/logo/blokt.png" width="200">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@ -181,3 +181,8 @@ We accept donations via [Patreon](https://www.patreon.com/jcbrand) and [Liberapa
|
|||||||
<img alt="Prime Sound" src="https://raw.githubusercontent.com/conversejs/media/main/logos/primesound.png" width="200">
|
<img alt="Prime Sound" src="https://raw.githubusercontent.com/conversejs/media/main/logos/primesound.png" width="200">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="https://www.keycdn.com?utm_source=conversejs" target="_blank" rel="noopener">
|
||||||
|
<img alt="KeyCDN" src="https://raw.githubusercontent.com/conversejs/converse.js/541613d1fea8aef364af00180f60e959162e5e4b/logo/keycdn.png" width="200">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
23
RELEASE.md
23
RELEASE.md
@ -1,19 +1,18 @@
|
|||||||
# Release checklist
|
# Release checklist
|
||||||
|
|
||||||
1. Check that weblate translations are all merged in
|
1. Merge weblate translations: https://hosted.weblate.org/projects/conversejs/translations/#repository
|
||||||
2. Run `make check` to check that all tests pass.
|
2. Run `make check` to check that all tests pass.
|
||||||
3. Run `make release VERSION=10.1.2`
|
3. Run `make version VERSION=10.1.6`
|
||||||
4. Do a `git diff` to check if things look sane.
|
4. Do a `git diff` to check if things look sane.
|
||||||
5. Do a quick manual test with the `dist` files (via `index.html`)
|
5. Do a quick manual test with the `dist` files (via `index.html`)
|
||||||
6. `git commit -am "Release 10.1.2"`
|
6. `git commit -am "Release 10.1.6"`
|
||||||
7. `git tag -s v10.1.2 -m "Release 10.1.2"`
|
7. `git tag -s v10.1.6 -m "Release 10.1.6"`
|
||||||
8. Run `git push && git push origin v10.1.2`
|
8. `git push && git push origin v10.1.6`
|
||||||
9. Update https://conversejs.org
|
9. `make publish BRANCH=v10.1.6`
|
||||||
* `cd /home/conversejs/converse.js`
|
|
||||||
* `git clone --branch v10.1.2 git@github.com:conversejs/converse.js.git 10.1.2`
|
|
||||||
* `cd 10.1.2 && nvm install && ASSET_PATH=https://cdn.conversejs.org/10.1.2/dist/ make dist && make doc`
|
|
||||||
* `cd .. && git pull && nvm install && ASSET_PATH=https://cdn.conversejs.org/dist/ make dist && make doc`
|
|
||||||
10. Update release page on Github
|
10. Update release page on Github
|
||||||
11. Run `npm publish && cd src/headless/ && npm publish`
|
* Upload tar files
|
||||||
|
11. Update https://conversejs.org
|
||||||
|
* `cd /home/conversejs/converse.js`
|
||||||
|
* `make deploy VERSION=10.1.6`
|
||||||
12. Update the repository on weblate
|
12. Update the repository on weblate
|
||||||
13. Decide on next release number and run `make postrelease VERSION=9.1.2`
|
13. Decide on next release number and run `make postrelease VERSION=10.1.7`
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
<category rdf:resource="https://linkmauve.fr/ns/xmpp-doap#category-client"/>
|
<category rdf:resource="https://linkmauve.fr/ns/xmpp-doap#category-client"/>
|
||||||
<programming-language>JavaScript</programming-language>
|
<programming-language>JavaScript</programming-language>
|
||||||
<os>Browser</os>
|
<os>Browser</os>
|
||||||
|
<os>Linux</os>
|
||||||
|
<os>macOS</os>
|
||||||
|
<os>Windows</os>
|
||||||
<schema:logo rdf:resource="https://raw.githubusercontent.com/conversejs/converse.js/master/logo/conversejs-filled.svg"/>
|
<schema:logo rdf:resource="https://raw.githubusercontent.com/conversejs/converse.js/master/logo/conversejs-filled.svg"/>
|
||||||
<repository>
|
<repository>
|
||||||
<GitRepository>
|
<GitRepository>
|
||||||
|
7
dev.html
7
dev.html
@ -28,6 +28,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
converse.initialize({
|
converse.initialize({
|
||||||
|
i18n: 'af',
|
||||||
theme: 'dracula',
|
theme: 'dracula',
|
||||||
auto_away: 300,
|
auto_away: 300,
|
||||||
enable_smacks: true,
|
enable_smacks: true,
|
||||||
@ -39,10 +40,10 @@
|
|||||||
muc_show_logs_before_join: true,
|
muc_show_logs_before_join: true,
|
||||||
notify_all_room_messages: ['discuss@conference.conversejs.org'],
|
notify_all_room_messages: ['discuss@conference.conversejs.org'],
|
||||||
view_mode: 'fullscreen',
|
view_mode: 'fullscreen',
|
||||||
websocket_url: 'wss://conversejs.org/xmpp-websocket',
|
// websocket_url: 'wss://conversejs.org/xmpp-websocket',
|
||||||
// websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
|
websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
|
||||||
whitelisted_plugins: ['converse-debug'],
|
whitelisted_plugins: ['converse-debug'],
|
||||||
connection_options: { worker: '/dist/shared-connection-worker.js' }
|
// connection_options: { worker: '/dist/shared-connection-worker.js' }
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
<h4 class="sidebar-title">Sponsored by</h4>
|
<h4 class="sidebar-title">Sponsored by</h4>
|
||||||
</span>
|
</span>
|
||||||
<ul class="sponsors-list">
|
<ul class="sponsors-list">
|
||||||
<li><a href="https://www.keycdn.com/?utm_source=conversejs" target="_blank" rel="noopener">
|
<li><a href="https://bairesdev.com/sponsoring-open-source-projects/?utm_source=conversejs" target="_blank" rel="noopener">
|
||||||
<img style="height: 2.5em" src="/logo/keycdn.png" alt="KeyCDN">
|
<img style="width: 10em" src="/media/logos/bairesdev-primary.png" alt="BairesDev">
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="https://blokt.com/?utm_source=conversejs" target="_blank" rel="noopener">
|
<li><a href="https://blokt.com/?utm_source=conversejs" target="_blank" rel="noopener">
|
||||||
@ -14,5 +14,9 @@
|
|||||||
<img style="width: 9em" src="/media/logos/primesound.png" alt="Prime Sound">
|
<img style="width: 9em" src="/media/logos/primesound.png" alt="Prime Sound">
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a href="https://www.keycdn.com/?utm_source=conversejs" target="_blank" rel="noopener">
|
||||||
|
<img style="height: 2.5em" src="/logo/keycdn.png" alt="KeyCDN">
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span class="centered-text-container patreon-link-container"><a href="https://conversejs.org#sponsors">Become a sponsor</a></span>
|
<span class="centered-text-container patreon-link-container"><a href="https://conversejs.org#sponsors">Become a sponsor</a></span>
|
||||||
|
@ -48,9 +48,9 @@ copyright = u'2018, JC Brand'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '10.1.2'
|
version = '10.1.6'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '10.1.2'
|
release = '10.1.6'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -925,12 +925,6 @@ filter_url_query_params
|
|||||||
|
|
||||||
Accepts a string or array of strings. Any query strings from URLs that match this setting will be removed.
|
Accepts a string or array of strings. Any query strings from URLs that match this setting will be removed.
|
||||||
|
|
||||||
fullname
|
|
||||||
--------
|
|
||||||
|
|
||||||
If you are using prebinding, can specify the fullname of the currently
|
|
||||||
logged in user, otherwise the user's vCard will be fetched.
|
|
||||||
|
|
||||||
geouri_regex
|
geouri_regex
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@ -2089,6 +2083,13 @@ themselves).
|
|||||||
In order to support all browsers we need both an MP3 and an Ogg file. Make sure
|
In order to support all browsers we need both an MP3 and an Ogg file. Make sure
|
||||||
to name your files ``msg_received.ogg`` and ``msg_received.mp3``.
|
to name your files ``msg_received.ogg`` and ``msg_received.mp3``.
|
||||||
|
|
||||||
|
stanza_timeout
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* Default: ``20000`` (20 seconds)
|
||||||
|
|
||||||
|
The time to wait, in milliseconds, for a response stanza (for example to an IQ
|
||||||
|
request), before a timeout error is thrown and Converse stops waiting.
|
||||||
|
|
||||||
sticky_controlbox
|
sticky_controlbox
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -56,16 +56,16 @@ might break when a new backwards-incompatible version of Converse is released.
|
|||||||
|
|
||||||
To load a specific version of Converse you can put the version in the URL:
|
To load a specific version of Converse you can put the version in the URL:
|
||||||
|
|
||||||
* https://cdn.conversejs.org/10.1.2/dist/converse.min.js
|
* https://cdn.conversejs.org/10.1.6/dist/converse.min.js
|
||||||
* https://cdn.conversejs.org/10.1.2/dist/converse.min.css
|
* https://cdn.conversejs.org/10.1.6/dist/converse.min.css
|
||||||
|
|
||||||
You can include these two URLs inside the *<head>* element of your website
|
You can include these two URLs inside the *<head>* element of your website
|
||||||
via the *script* and *link* tags:
|
via the *script* and *link* tags:
|
||||||
|
|
||||||
.. code-block:: html
|
.. code-block:: html
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/10.1.2/dist/converse.min.css">
|
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/10.1.6/dist/converse.min.css">
|
||||||
<script src="https://cdn.conversejs.org/10.1.2/dist/converse.min.js" charset="utf-8"></script>
|
<script src="https://cdn.conversejs.org/10.1.6/dist/converse.min.js" charset="utf-8"></script>
|
||||||
|
|
||||||
|
|
||||||
Option 2: Download the builds from Github
|
Option 2: Download the builds from Github
|
||||||
|
@ -240,10 +240,11 @@
|
|||||||
<div class="sponsors">
|
<div class="sponsors">
|
||||||
<h2>Converse is supported by:</h2>
|
<h2>Converse is supported by:</h2>
|
||||||
<ul >
|
<ul >
|
||||||
<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://bairesdev.com/sponsoring-open-source-projects/?utm_source=conversejs" target="_blank" rel="noopener"><img style="width: 13em" src="/media/logos/bairesdev-primary.png" alt="BairesDev"></a></li>
|
||||||
<li><a href="https://weblate.org?utm_source=conversejs" target="_blank" rel="noopener"><img style="height: 2.6em" src="/logo/weblate-button.svg" alt="Weblate"></a></li>
|
|
||||||
<li><a href="https://blokt.com?utm_source=conversejs" target="_blank" rel="noopener"><img style="width: 12em" src="/logo/blokt.png" alt="Blokt Crypto & Privacy"></a></li>
|
<li><a href="https://blokt.com?utm_source=conversejs" target="_blank" rel="noopener"><img style="width: 12em" src="/logo/blokt.png" alt="Blokt Crypto & Privacy"></a></li>
|
||||||
<li><a href="https://primesound.org/?utm_source=conversejs" target="_blank" rel="noopener"><img style="width: 10em" src="/media/logos/primesound.png" alt="Prime Sound"></a></li>
|
<li><a href="https://primesound.org/?utm_source=conversejs" target="_blank" rel="noopener"><img style="width: 10em" src="/media/logos/primesound.png" alt="Prime Sound"></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://weblate.org?utm_source=conversejs" target="_blank" rel="noopener"><img style="height: 2.6em" src="/logo/weblate-button.svg" alt="Weblate"></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -11,17 +11,17 @@
|
|||||||
|
|
||||||
<!-- These files are NOT needed when using converse.js in your own project. -->
|
<!-- These files are NOT needed when using converse.js in your own project. -->
|
||||||
<link rel="shortcut icon" type="image/ico" href="images/favicon.ico"/>
|
<link rel="shortcut icon" type="image/ico" href="images/favicon.ico"/>
|
||||||
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.2/css/font-awesome.min.css" />
|
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.6/css/font-awesome.min.css" />
|
||||||
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.2/css/website.min.css" />
|
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.6/css/website.min.css" />
|
||||||
<noscript><p><img src="//stats.opkode.com/piwik.php?idsite=1" style="border:0;" alt="" /></p></noscript>
|
<noscript><p><img src="//stats.opkode.com/piwik.php?idsite=1" style="border:0;" alt="" /></p></noscript>
|
||||||
<script type="text/javascript" src="/src/website.js"></script>
|
<script type="text/javascript" src="/src/website.js"></script>
|
||||||
<script type="text/javascript" src="analytics.js"></script>
|
<script type="text/javascript" src="analytics.js"></script>
|
||||||
<!-- *********************************************************************** -->
|
<!-- *********************************************************************** -->
|
||||||
|
|
||||||
<![if gte IE 11]>
|
<![if gte IE 11]>
|
||||||
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.2/css/converse.min.css" />
|
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.6/css/converse.min.css" />
|
||||||
<script src="https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js"></script>
|
<script src="https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js"></script>
|
||||||
<script src="https://cdn.conversejs.org/10.1.2/dist/converse.min.js"></script>
|
<script src="https://cdn.conversejs.org/10.1.6/dist/converse.min.js"></script>
|
||||||
<![endif]>
|
<![endif]>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<table id="jslicense-labels1" style="width: 100%">
|
<table id="jslicense-labels1" style="width: 100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://cdn.conversejs.org/10.1.2/dist/converse.min.js">converse.min.js</a>
|
<a href="https://cdn.conversejs.org/10.1.6/dist/converse.min.js">converse.min.js</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://www.mozilla.org/en-US/MPL/2.0/">MPL-2.0</a>
|
<a href="https://www.mozilla.org/en-US/MPL/2.0/">MPL-2.0</a>
|
||||||
|
@ -104,6 +104,8 @@ module.exports = function(config) {
|
|||||||
{ pattern: "src/plugins/omemo/tests/muc.js", type: 'module' },
|
{ pattern: "src/plugins/omemo/tests/muc.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/omemo/tests/omemo.js", type: 'module' },
|
{ pattern: "src/plugins/omemo/tests/omemo.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/profile/tests/password-reset.js", type: 'module' },
|
{ pattern: "src/plugins/profile/tests/password-reset.js", type: 'module' },
|
||||||
|
{ pattern: "src/plugins/profile/tests/profile.js", type: 'module' },
|
||||||
|
{ pattern: "src/plugins/profile/tests/status.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/push/tests/push.js", type: 'module' },
|
{ pattern: "src/plugins/push/tests/push.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/register/tests/register.js", type: 'module' },
|
{ pattern: "src/plugins/register/tests/register.js", type: 'module' },
|
||||||
{ pattern: "src/plugins/roomslist/tests/roomslist.js", type: 'module' },
|
{ pattern: "src/plugins/roomslist/tests/roomslist.js", type: 'module' },
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"packages": [
|
|
||||||
".",
|
|
||||||
"src/*"
|
|
||||||
],
|
|
||||||
"version": "4.0.3"
|
|
||||||
}
|
|
@ -1,19 +1,34 @@
|
|||||||
<svg class="converse-svg-logo"
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg108" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
xml:space="preserve" version="1.1"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
viewBox="0 0 376 311" height="20%" width="10rem"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
sodipodi:docname="chapril-logo.svg" inkscape:version="0.92.1 r15371">
|
||||||
viewBox="0 0 364 364">
|
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="640" inkscape:window-height="480" id="namedview16" showgrid="false" inkscape:zoom="0.75884244" inkscape:cx="188" inkscape:cy="155.5" inkscape:window-x="0" inkscape:window-y="24" inkscape:window-maximized="0" inkscape:current-layer="svg108"/>
|
||||||
<title>Converse</title>
|
<metadata id="metadata114">
|
||||||
<g class="cls-1" id="g904">
|
<rdf:RDF>
|
||||||
<g data-name="Layer 2">
|
<cc:Work rdf:about="">
|
||||||
<g data-name="Layer 7">
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<path
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||||
class="cls-3"
|
<dc:title/>
|
||||||
d="M221.46,103.71c0,18.83-29.36,18.83-29.12,0C192.1,84.88,221.46,84.88,221.46,103.71Z" />
|
<cc:license rdf:resource="GFDL version 1.3 ou ultérieure, Creative Commons By Sa version 2.0 ou ultérieure, Licence Art Libre version 1.3 ou ultérieure"/>
|
||||||
<path
|
<dc:creator>
|
||||||
class="cls-4"
|
<cc:Agent>
|
||||||
d="M179.9,4.15A175.48,175.48,0,1,0,355.38,179.63,175.48,175.48,0,0,0,179.9,4.15Zm-40.79,264.5c-.23-17.82,27.58-17.82,27.58,0S138.88,286.48,139.11,268.65ZM218.6,168.24A79.65,79.65,0,0,1,205.15,174a12.76,12.76,0,0,0-6.29,4.65L167.54,222a1.36,1.36,0,0,1-2.46-.8v-35.8a2.58,2.58,0,0,0-3.06-2.53c-15.43,3-30.23,7.7-42.73,19.94-38.8,38-29.42,105.69,16.09,133.16a162.25,162.25,0,0,1-91.47-67.27C-3.86,182.26,34.5,47.25,138.37,25.66c46.89-9.75,118.25,5.16,123.73,62.83C265.15,120.64,246.56,152.89,218.6,168.24Z" />
|
<dc:title>Antoine BARDELLI</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs id="defs112"/>
|
||||||
|
<g id="g250" style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996" transform="translate(4.6079614e-7,-4.4571451e-6)">
|
||||||
|
<path id="path124" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 96.70711,209.69029 c -2.742,1.114 -5.399,1.8 -7.885,2.057 -0.771,0.085 -1.629,0.171 -2.4,0.171 -2.571,0 -5.314,-0.428 -8.228,-1.286 -2.486,-0.857 -4.628,-2.314 -6.514,-4.371 -1.886,-1.8 -3.343,-3.942 -4.371,-6.428 -0.943,-2.486 -1.457,-5.057 -1.543,-7.714 0,-0.086 0,-0.257 0,-0.343 0,-2.485 0.514,-4.971 1.543,-7.371 1.028,-2.314 2.485,-4.457 4.371,-6.428 1.886,-2.057 4.028,-3.514 6.514,-4.371 2.828,-1.029 5.571,-1.543 8.142,-1.543 0.257,0 0.6,0 0.857,0 3.686,0.171 6.857,1.028 9.686,2.657 -0.086,1.457 -0.343,3.514 -0.6,6.343 -2.743,-1.372 -5.4,-2.143 -7.971,-2.315 -1.972,-0.171 -3.943,0.086 -6,0.772 -1.629,0.514 -3.171,1.457 -4.457,2.914 -1.286,1.371 -2.228,2.828 -2.914,4.457 -0.772,1.628 -1.114,3.342 -1.114,5.142 0.085,1.886 0.428,3.6 1.114,5.229 0.686,1.714 1.628,3.171 2.914,4.457 1.286,1.285 2.828,2.228 4.457,2.914 2.486,0.685 4.543,1.028 6.343,1.028 3.342,-0.343 5.999,-1.2 8.056,-2.657 0,1.457 0,3.686 0,6.686 z"/>
|
||||||
|
<path id="path126" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 137.33411,184.91929 c 0,1.8 0,3.515 0,5.314 0,2.657 0,5.4 -0.086,8.057 0,4.457 0,8.743 0,12.771 -1.714,0 -4.285,0 -7.799,0 0,-3.857 0,-11.571 0.085,-23.142 0.086,-1.114 -0.171,-2.228 -0.6,-3.257 -0.428,-1.028 -1.028,-1.971 -1.8,-2.742 -0.942,-0.943 -2.142,-1.715 -3.599,-2.143 -1.029,-0.257 -2.229,-0.429 -3.6,-0.343 -1.115,0.086 -2.229,0.343 -3.257,0.686 -1.029,0.428 -2.143,1.028 -3.343,1.8 -0.6,0.6 -1.029,1.2 -1.457,1.8 v 27.341 h -8.057 v -62.997 h 8.057 v 29.313 c 0.943,-1.114 1.8,-1.971 2.571,-2.486 1.629,-0.942 3,-1.542 4.2,-1.885 1.971,-0.429 3.771,-0.6 5.571,-0.6 2.143,0.085 3.943,0.343 5.4,0.943 1.543,0.6 2.914,1.542 4.028,2.742 2.4,2.572 3.6,5.486 3.686,8.828 z"/>
|
||||||
|
<path id="path128" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 169.38911,146.86429 c 4.714,10.714 14.228,32.056 28.37,64.111 -1.371,0 -4.114,0 -8.313,0 -1.286,-2.657 -3.772,-7.971 -7.543,-15.942 -4.028,0 -12.085,0 -24.17,0 -1.114,2.657 -3.514,7.971 -7.028,15.942 -1.457,0 -4.2,0 -8.4,0 4.543,-10.713 13.542,-32.055 27.084,-64.111 z m 9.171,40.884 c -1.457,-3.686 -4.542,-10.885 -9.085,-21.77 -1.457,3.599 -4.285,10.885 -8.571,21.77 3,0 8.828,0 17.656,0 z"/>
|
||||||
|
<path id="path130" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 212.15911,199.83329 c 0.257,0.429 0.6,0.771 0.857,1.114 1.114,1.457 2.657,2.743 4.457,3.686 1.457,0.685 3.085,1.028 4.8,1.028 0.085,0 0.257,0 0.428,0 1.8,0.086 3.514,-0.257 5.143,-1.028 1.628,-0.6 3.171,-1.629 4.457,-2.914 1.285,-1.286 2.228,-2.743 2.914,-4.457 0.685,-1.543 1.028,-3.343 1.028,-5.314 0.086,-1.715 -0.257,-3.429 -1.028,-5.057 -0.6,-1.629 -1.629,-3.171 -2.914,-4.457 -1.286,-1.286 -2.743,-2.229 -4.457,-2.914 -1.115,-0.515 -2.572,-0.772 -4.2,-0.772 -0.172,0 -0.343,0 -0.429,0 -2.657,0.086 -4.714,0.429 -5.999,1.2 -3.429,1.8 -5.143,3.857 -5.143,6.171 0,3 0,7.629 0.086,13.714 z m 0,8.314 c -0.086,3.343 -0.086,10.028 -0.086,20.056 -1.286,0 -4.028,0 -8.057,0 v -54.769 c 2.657,0 5.4,0 8.057,0 0.086,1.286 0.086,2.4 0.086,3.257 0.857,-1.114 2.314,-2.142 4.457,-3.085 2.4,-1.029 4.971,-1.543 7.714,-1.543 2.657,0 5.228,0.514 7.628,1.543 2.485,1.028 4.714,2.485 6.514,4.371 1.971,1.886 3.428,4.028 4.371,6.428 1.028,2.486 1.543,4.971 1.543,7.543 0,0.085 0,0.085 0,0.171 0,2.657 -0.515,5.228 -1.543,7.714 -1.029,2.486 -2.486,4.628 -4.371,6.428 -1.886,1.972 -4.029,3.429 -6.514,4.371 -2.486,1.029 -5.057,1.543 -7.628,1.543 -2.657,-0.085 -5.229,-0.6 -7.714,-1.543 -1.372,-0.514 -2.829,-1.371 -4.457,-2.485 z"/>
|
||||||
|
<path id="path132" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 271.04211,180.46329 c 0,-0.086 -0.686,-0.172 -2.143,-0.429 -2.743,-0.086 -5.228,0.857 -7.371,2.828 -0.857,0.772 -1.543,1.886 -2.057,3.343 -0.343,1.371 -0.515,2.829 -0.6,4.457 0,4.543 0,11.399 0,20.399 -1.286,0 -3.943,0 -7.971,0 0,-6.257 0,-18.856 -0.086,-37.627 1.286,0 3.943,0 7.8,0 0.085,0.772 0.085,2.4 0.085,4.8 0,0.514 0,1.543 -0.085,3.171 1.028,-4.199 3.085,-6.856 6.085,-7.971 1.2,-0.343 2.4,-0.514 3.686,-0.514 0.857,-0.086 1.714,0 2.657,0.171 0,1.629 0,4.115 0,7.372 z"/>
|
||||||
|
<path id="path134" style="clip-rule:evenodd;fill:#005184;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 277.47011,163.23529 c 0,-1.372 0.514,-2.4 1.457,-3.171 0.943,-0.772 1.971,-1.2 3.085,-1.2 0.086,0 0.172,0 0.258,0 1.114,0 2.057,0.342 2.999,1.028 0.943,0.771 1.372,1.8 1.372,3.257 0,1.457 -0.429,2.571 -1.372,3.428 -0.942,0.858 -2.057,1.286 -3.257,1.286 -1.114,0 -2.142,-0.428 -3.085,-1.2 -0.943,-0.771 -1.457,-1.971 -1.457,-3.428 z"/>
|
||||||
|
<path style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996" id="path136" d="m 278.15611,173.34929 c 1.371,0 4.028,0 8.056,0 0,6.342 0,18.942 0,37.883 -1.285,0 -3.942,0 -7.885,0 0,-6.256 -0.086,-18.941 -0.171,-37.883 z"/>
|
||||||
|
<path id="path138" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 295.55511,146.26429 v 64.797 c 1.285,0 3.942,0 7.885,0 0,-10.799 0,-32.398 0,-64.797 -1.286,0 -3.943,0 -7.885,0 z"/>
|
||||||
|
<path id="path144" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 79.90511,45.008286 c 0.902,0.305 0.903,0.306 1.74,0.76 0,0 2.36,1.6 3.541,2.399 16.192,11.056 46.905,36.807 46.905,36.807 l -0.62,0.933 c 0,0 -30.962,-17.269 -47.812,-25.837 -0.154,2.104 -0.309,4.208 -0.465,6.312 l -0.126,1.689 c -0.635,7.993 -1.295,15.97 -2,23.945 l -0.096,1.076 c -0.824,8.583004 -1.124,17.369004 -3.069,25.573004 -1.802,7.601 -10.27,13.477 -15.485,20.114 -10.856,13.816 -19.361,29.582 -21.64,47.603 -2.579,20.389 5.773,40.853 21.062,55.815 5.92,5.794 12.534,10.853 19.323,15.617 l -3.768,5.852 c -20.581,-12.139 -40.182,-28.618 -47.181,-51.981 -6.615,-22.081 -1.608,-47.917 10.144,-67.278 6.689,-11.02 14.834,-21.098 23.413,-30.201 0,0 0.585,-2.521 0.874,-4.27 3.14,-19.016004 5.383,-38.057004 7.92,-57.227004 l 0.274,-2.074 0.28,-1.686 c 0.307,-0.8 0.337,-1.033 0.841,-1.737 1.119,-1.562 2.062,-2.818 5.945,-2.204 z"/>
|
||||||
|
<path id="path146" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 300.65411,44.858286 c 2.74,0.486 2.778,0.936 3.448,1.587 2.555,2.484 2.191,7.238 2.75,11.471 2.467,18.612 4.172,37.353 7.871,55.935004 0,0 3.607,4.013 6.264,7.099 11.064,12.849 21.019,26.411 26.284,43.975 6.27,20.92 3.585,41.82 -7.633,60.315 -9.349,15.414 -24.268,26.668 -39.964,35.962 l -0.593,-1.853 c 17.279,-12.08 34.133,-26.972 39.318,-48.24 3.677,-15.083 -0.809,-32.515 -6.571,-47.292 -5.094,-13.065 -14.589,-24.209 -23.233,-34.394 -1.789,-2.107 -3.603,-4.192 -5.472,-6.229 0,0 -2.204,-3.069 -2.806,-6.739 -2.582,-15.749 -3.416,-31.540004 -4.699,-47.326004 0,0 -0.34,-4.424 -0.589,-7.754 l -0.098,-1.322 -30.582,18.428 -15.221,9.11 -0.801,0.477 -3.955,-6.151 0.767,-0.531 14.605,-10.067 37.28,-25.534 c 0,0 1.172,-0.939 3.63,-0.927 z m 14.362,70.312004 c 0.178,0.639 -0.049,-0.186 0,0 z"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 8.9 KiB |
19
logo/conversejs-transparent.svg
Normal file
19
logo/conversejs-transparent.svg
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<svg class="converse-svg-logo"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 364 364">
|
||||||
|
<title>Converse</title>
|
||||||
|
<g class="cls-1" id="g904">
|
||||||
|
<g data-name="Layer 2">
|
||||||
|
<g data-name="Layer 7">
|
||||||
|
<path
|
||||||
|
class="cls-3"
|
||||||
|
d="M221.46,103.71c0,18.83-29.36,18.83-29.12,0C192.1,84.88,221.46,84.88,221.46,103.71Z" />
|
||||||
|
<path
|
||||||
|
class="cls-4"
|
||||||
|
d="M179.9,4.15A175.48,175.48,0,1,0,355.38,179.63,175.48,175.48,0,0,0,179.9,4.15Zm-40.79,264.5c-.23-17.82,27.58-17.82,27.58,0S138.88,286.48,139.11,268.65ZM218.6,168.24A79.65,79.65,0,0,1,205.15,174a12.76,12.76,0,0,0-6.29,4.65L167.54,222a1.36,1.36,0,0,1-2.46-.8v-35.8a2.58,2.58,0,0,0-3.06-2.53c-15.43,3-30.23,7.7-42.73,19.94-38.8,38-29.42,105.69,16.09,133.16a162.25,162.25,0,0,1-91.47-67.27C-3.86,182.26,34.5,47.25,138.37,25.66c46.89-9.75,118.25,5.16,123.73,62.83C265.15,120.64,246.56,152.89,218.6,168.24Z" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
@ -7,102 +8,39 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
id="chapril-logo"
|
||||||
|
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
|
||||||
class="converse-svg-logo"
|
class="converse-svg-logo"
|
||||||
viewBox="0 0 364 364"
|
xml:space="preserve" version="1.1"
|
||||||
version="1.1"
|
viewBox="0 0 376 311" height="20%" width="6rem"
|
||||||
id="svg13"
|
sodipodi:docname="chapril-logo.svg" inkscape:version="0.92.1 r15371">
|
||||||
sodipodi:docname="conversejs-with-byline.svg"
|
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="640" inkscape:window-height="480" id="namedview16" showgrid="false" inkscape:zoom="0.75884244" inkscape:cx="188" inkscape:cy="155.5" inkscape:window-x="0" inkscape:window-y="24" inkscape:window-maximized="0" inkscape:current-layer="svg108"/>
|
||||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06">
|
<metadata id="metadata114">
|
||||||
<metadata
|
|
||||||
id="metadata19">
|
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work
|
<cc:Work rdf:about="">
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:type
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:title/>
|
||||||
<dc:title>Converse</dc:title>
|
<cc:license rdf:resource="GFDL version 1.3 ou ultérieure, Creative Commons By Sa version 2.0 ou ultérieure, Licence Art Libre version 1.3 ou ultérieure"/>
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>Antoine BARDELLI</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
<defs
|
<defs id="defs112"/>
|
||||||
id="defs17">
|
<g id="g250" style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996" transform="translate(4.6079614e-7,-4.4571451e-6)">
|
||||||
<inkscape:perspective
|
<path id="path124" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 96.70711,209.69029 c -2.742,1.114 -5.399,1.8 -7.885,2.057 -0.771,0.085 -1.629,0.171 -2.4,0.171 -2.571,0 -5.314,-0.428 -8.228,-1.286 -2.486,-0.857 -4.628,-2.314 -6.514,-4.371 -1.886,-1.8 -3.343,-3.942 -4.371,-6.428 -0.943,-2.486 -1.457,-5.057 -1.543,-7.714 0,-0.086 0,-0.257 0,-0.343 0,-2.485 0.514,-4.971 1.543,-7.371 1.028,-2.314 2.485,-4.457 4.371,-6.428 1.886,-2.057 4.028,-3.514 6.514,-4.371 2.828,-1.029 5.571,-1.543 8.142,-1.543 0.257,0 0.6,0 0.857,0 3.686,0.171 6.857,1.028 9.686,2.657 -0.086,1.457 -0.343,3.514 -0.6,6.343 -2.743,-1.372 -5.4,-2.143 -7.971,-2.315 -1.972,-0.171 -3.943,0.086 -6,0.772 -1.629,0.514 -3.171,1.457 -4.457,2.914 -1.286,1.371 -2.228,2.828 -2.914,4.457 -0.772,1.628 -1.114,3.342 -1.114,5.142 0.085,1.886 0.428,3.6 1.114,5.229 0.686,1.714 1.628,3.171 2.914,4.457 1.286,1.285 2.828,2.228 4.457,2.914 2.486,0.685 4.543,1.028 6.343,1.028 3.342,-0.343 5.999,-1.2 8.056,-2.657 0,1.457 0,3.686 0,6.686 z"/>
|
||||||
sodipodi:type="inkscape:persp3d"
|
<path id="path126" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 137.33411,184.91929 c 0,1.8 0,3.515 0,5.314 0,2.657 0,5.4 -0.086,8.057 0,4.457 0,8.743 0,12.771 -1.714,0 -4.285,0 -7.799,0 0,-3.857 0,-11.571 0.085,-23.142 0.086,-1.114 -0.171,-2.228 -0.6,-3.257 -0.428,-1.028 -1.028,-1.971 -1.8,-2.742 -0.942,-0.943 -2.142,-1.715 -3.599,-2.143 -1.029,-0.257 -2.229,-0.429 -3.6,-0.343 -1.115,0.086 -2.229,0.343 -3.257,0.686 -1.029,0.428 -2.143,1.028 -3.343,1.8 -0.6,0.6 -1.029,1.2 -1.457,1.8 v 27.341 h -8.057 v -62.997 h 8.057 v 29.313 c 0.943,-1.114 1.8,-1.971 2.571,-2.486 1.629,-0.942 3,-1.542 4.2,-1.885 1.971,-0.429 3.771,-0.6 5.571,-0.6 2.143,0.085 3.943,0.343 5.4,0.943 1.543,0.6 2.914,1.542 4.028,2.742 2.4,2.572 3.6,5.486 3.686,8.828 z"/>
|
||||||
inkscape:vp_x="0 : 182 : 1"
|
<path id="path128" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 169.38911,146.86429 c 4.714,10.714 14.228,32.056 28.37,64.111 -1.371,0 -4.114,0 -8.313,0 -1.286,-2.657 -3.772,-7.971 -7.543,-15.942 -4.028,0 -12.085,0 -24.17,0 -1.114,2.657 -3.514,7.971 -7.028,15.942 -1.457,0 -4.2,0 -8.4,0 4.543,-10.713 13.542,-32.055 27.084,-64.111 z m 9.171,40.884 c -1.457,-3.686 -4.542,-10.885 -9.085,-21.77 -1.457,3.599 -4.285,10.885 -8.571,21.77 3,0 8.828,0 17.656,0 z"/>
|
||||||
inkscape:vp_y="0 : 1000 : 0"
|
<path id="path130" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 212.15911,199.83329 c 0.257,0.429 0.6,0.771 0.857,1.114 1.114,1.457 2.657,2.743 4.457,3.686 1.457,0.685 3.085,1.028 4.8,1.028 0.085,0 0.257,0 0.428,0 1.8,0.086 3.514,-0.257 5.143,-1.028 1.628,-0.6 3.171,-1.629 4.457,-2.914 1.285,-1.286 2.228,-2.743 2.914,-4.457 0.685,-1.543 1.028,-3.343 1.028,-5.314 0.086,-1.715 -0.257,-3.429 -1.028,-5.057 -0.6,-1.629 -1.629,-3.171 -2.914,-4.457 -1.286,-1.286 -2.743,-2.229 -4.457,-2.914 -1.115,-0.515 -2.572,-0.772 -4.2,-0.772 -0.172,0 -0.343,0 -0.429,0 -2.657,0.086 -4.714,0.429 -5.999,1.2 -3.429,1.8 -5.143,3.857 -5.143,6.171 0,3 0,7.629 0.086,13.714 z m 0,8.314 c -0.086,3.343 -0.086,10.028 -0.086,20.056 -1.286,0 -4.028,0 -8.057,0 v -54.769 c 2.657,0 5.4,0 8.057,0 0.086,1.286 0.086,2.4 0.086,3.257 0.857,-1.114 2.314,-2.142 4.457,-3.085 2.4,-1.029 4.971,-1.543 7.714,-1.543 2.657,0 5.228,0.514 7.628,1.543 2.485,1.028 4.714,2.485 6.514,4.371 1.971,1.886 3.428,4.028 4.371,6.428 1.028,2.486 1.543,4.971 1.543,7.543 0,0.085 0,0.085 0,0.171 0,2.657 -0.515,5.228 -1.543,7.714 -1.029,2.486 -2.486,4.628 -4.371,6.428 -1.886,1.972 -4.029,3.429 -6.514,4.371 -2.486,1.029 -5.057,1.543 -7.628,1.543 -2.657,-0.085 -5.229,-0.6 -7.714,-1.543 -1.372,-0.514 -2.829,-1.371 -4.457,-2.485 z"/>
|
||||||
inkscape:vp_z="364 : 182 : 1"
|
<path id="path132" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 271.04211,180.46329 c 0,-0.086 -0.686,-0.172 -2.143,-0.429 -2.743,-0.086 -5.228,0.857 -7.371,2.828 -0.857,0.772 -1.543,1.886 -2.057,3.343 -0.343,1.371 -0.515,2.829 -0.6,4.457 0,4.543 0,11.399 0,20.399 -1.286,0 -3.943,0 -7.971,0 0,-6.257 0,-18.856 -0.086,-37.627 1.286,0 3.943,0 7.8,0 0.085,0.772 0.085,2.4 0.085,4.8 0,0.514 0,1.543 -0.085,3.171 1.028,-4.199 3.085,-6.856 6.085,-7.971 1.2,-0.343 2.4,-0.514 3.686,-0.514 0.857,-0.086 1.714,0 2.657,0.171 0,1.629 0,4.115 0,7.372 z"/>
|
||||||
inkscape:persp3d-origin="182 : 121.33333 : 1"
|
<path id="path134" style="clip-rule:evenodd;fill:#005184;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 277.47011,163.23529 c 0,-1.372 0.514,-2.4 1.457,-3.171 0.943,-0.772 1.971,-1.2 3.085,-1.2 0.086,0 0.172,0 0.258,0 1.114,0 2.057,0.342 2.999,1.028 0.943,0.771 1.372,1.8 1.372,3.257 0,1.457 -0.429,2.571 -1.372,3.428 -0.942,0.858 -2.057,1.286 -3.257,1.286 -1.114,0 -2.142,-0.428 -3.085,-1.2 -0.943,-0.771 -1.457,-1.971 -1.457,-3.428 z"/>
|
||||||
id="perspective2147" />
|
<path style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41420996" id="path136" d="m 278.15611,173.34929 c 1.371,0 4.028,0 8.056,0 0,6.342 0,18.942 0,37.883 -1.285,0 -3.942,0 -7.885,0 0,-6.256 -0.086,-18.941 -0.171,-37.883 z"/>
|
||||||
</defs>
|
<path id="path138" style="clip-rule:evenodd;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 295.55511,146.26429 v 64.797 c 1.285,0 3.942,0 7.885,0 0,-10.799 0,-32.398 0,-64.797 -1.286,0 -3.943,0 -7.885,0 z"/>
|
||||||
<sodipodi:namedview
|
<path id="path144" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 79.90511,45.008286 c 0.902,0.305 0.903,0.306 1.74,0.76 0,0 2.36,1.6 3.541,2.399 16.192,11.056 46.905,36.807 46.905,36.807 l -0.62,0.933 c 0,0 -30.962,-17.269 -47.812,-25.837 -0.154,2.104 -0.309,4.208 -0.465,6.312 l -0.126,1.689 c -0.635,7.993 -1.295,15.97 -2,23.945 l -0.096,1.076 c -0.824,8.583004 -1.124,17.369004 -3.069,25.573004 -1.802,7.601 -10.27,13.477 -15.485,20.114 -10.856,13.816 -19.361,29.582 -21.64,47.603 -2.579,20.389 5.773,40.853 21.062,55.815 5.92,5.794 12.534,10.853 19.323,15.617 l -3.768,5.852 c -20.581,-12.139 -40.182,-28.618 -47.181,-51.981 -6.615,-22.081 -1.608,-47.917 10.144,-67.278 6.689,-11.02 14.834,-21.098 23.413,-30.201 0,0 0.585,-2.521 0.874,-4.27 3.14,-19.016004 5.383,-38.057004 7.92,-57.227004 l 0.274,-2.074 0.28,-1.686 c 0.307,-0.8 0.337,-1.033 0.841,-1.737 1.119,-1.562 2.062,-2.818 5.945,-2.204 z"/>
|
||||||
pagecolor="#ffffff"
|
<path id="path146" style="clip-rule:evenodd;fill:#005184;fill-rule:nonzero;stroke-linejoin:round;stroke-miterlimit:1.41420996" d="m 300.65411,44.858286 c 2.74,0.486 2.778,0.936 3.448,1.587 2.555,2.484 2.191,7.238 2.75,11.471 2.467,18.612 4.172,37.353 7.871,55.935004 0,0 3.607,4.013 6.264,7.099 11.064,12.849 21.019,26.411 26.284,43.975 6.27,20.92 3.585,41.82 -7.633,60.315 -9.349,15.414 -24.268,26.668 -39.964,35.962 l -0.593,-1.853 c 17.279,-12.08 34.133,-26.972 39.318,-48.24 3.677,-15.083 -0.809,-32.515 -6.571,-47.292 -5.094,-13.065 -14.589,-24.209 -23.233,-34.394 -1.789,-2.107 -3.603,-4.192 -5.472,-6.229 0,0 -2.204,-3.069 -2.806,-6.739 -2.582,-15.749 -3.416,-31.540004 -4.699,-47.326004 0,0 -0.34,-4.424 -0.589,-7.754 l -0.098,-1.322 -30.582,18.428 -15.221,9.11 -0.801,0.477 -3.955,-6.151 0.767,-0.531 14.605,-10.067 37.28,-25.534 c 0,0 1.172,-0.939 3.63,-0.927 z m 14.362,70.312004 c 0.178,0.639 -0.049,-0.186 0,0 z"/>
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1434"
|
|
||||||
inkscape:window-height="951"
|
|
||||||
id="namedview15"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="1.8338154"
|
|
||||||
inkscape:cx="225.17086"
|
|
||||||
inkscape:cy="243.79827"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="svg13" />
|
|
||||||
<title
|
|
||||||
id="title2">Converse</title>
|
|
||||||
<g
|
|
||||||
class="cls-1"
|
|
||||||
id="g904"
|
|
||||||
transform="matrix(0.2441072,0,0,0.2441072,12.20969,55.55023)">
|
|
||||||
<g
|
|
||||||
data-name="Layer 2"
|
|
||||||
id="g10">
|
|
||||||
<g
|
|
||||||
data-name="Layer 7"
|
|
||||||
id="g8">
|
|
||||||
<path
|
|
||||||
class="cls-3"
|
|
||||||
d="m 221.46,103.71 c 0,18.83 -29.36,18.83 -29.12,0 -0.24,-18.83 29.12,-18.83 29.12,0 z"
|
|
||||||
id="path4"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
class="cls-4"
|
|
||||||
d="M 179.9,4.15 C 108.92504,4.15 44.938239,46.904566 17.778836,112.4757 -9.3805118,178.0467 5.6365472,253.52014 55.823205,303.70679 106.00986,353.89345 181.4833,368.91051 247.0543,341.75116 312.62543,314.59176 355.38,250.60496 355.38,179.63 355.38,82.715072 276.81493,4.15 179.9,4.15 Z m -40.79,264.5 c -0.23,-17.82 27.58,-17.82 27.58,0 0,17.82 -27.81,17.83 -27.58,0 z M 218.6,168.24 c -4.29711,2.32859 -8.79944,4.25673 -13.45,5.76 -2.53177,0.85328 -12.23498,3.26952 -13.79313,5.4398 C 180.90809,189.252 165.08,221.2 165.08,221.2 v -35.8 c -0.003,-1.6153 -1.4729,-2.83052 -3.06,-2.53 -15.43,3 -30.23,7.7 -42.73,19.94 -38.8,38 -29.025098,103.71549 16.4849,131.18549 C 98.17801,323.32071 65.725789,295.74404 44.332966,263.03587 -3.4370336,176.59587 35.058475,51.159326 138.92848,29.569326 185.81848,19.819326 256.62,30.82 262.1,88.49 c 3.05,32.15 -15.54,64.4 -43.5,79.75 z"
|
|
||||||
id="path6"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
sodipodi:nodetypes="sssssscsccccccccccccc" />
|
|
||||||
</g>
|
</g>
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.63063431px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.10960984px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
x="110.04511"
|
|
||||||
y="98.826035"
|
|
||||||
id="text861"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan859"
|
|
||||||
x="110.04511"
|
|
||||||
y="98.826035"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.63063431px;font-family:Baumans;-inkscape-font-specification:'Baumans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:2.10960984px">converse<tspan
|
|
||||||
style="fill:#a2a2a2;fill-opacity:1;stroke-width:2.10960984px"
|
|
||||||
id="tspan867">.js</tspan></tspan></text>
|
|
||||||
<text
|
|
||||||
xml:space="preserve"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.49652481px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.77068853px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
|
||||||
x="124.58434"
|
|
||||||
y="128.44286"
|
|
||||||
id="text865"><tspan
|
|
||||||
sodipodi:role="line"
|
|
||||||
id="tspan863"
|
|
||||||
x="124.58434"
|
|
||||||
y="128.44286"
|
|
||||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.49652481px;font-family:Muli;-inkscape-font-specification:'Muli, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#484848;fill-opacity:1;stroke-width:0.77068853px">messaging freedom</tspan></text>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 9.0 KiB |
@ -2,7 +2,7 @@
|
|||||||
"short_name": "Converse",
|
"short_name": "Converse",
|
||||||
"name": "Converse Chat",
|
"name": "Converse Chat",
|
||||||
"description": "Messaging Freedom",
|
"description": "Messaging Freedom",
|
||||||
"version": "10.1.2",
|
"version": "10.1.6",
|
||||||
"categories": ["social"],
|
"categories": ["social"],
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
<script type="text/javascript" src="analytics.js"></script>
|
<script type="text/javascript" src="analytics.js"></script>
|
||||||
<!-- *********************************************************************** -->
|
<!-- *********************************************************************** -->
|
||||||
|
|
||||||
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.2/dist/converse.min.css" />
|
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.6/dist/converse.min.css" />
|
||||||
<script src="https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js"></script>
|
<script src="https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js"></script>
|
||||||
<script src="https://cdn.conversejs.org/10.1.2/dist/converse.min.js"></script>
|
<script src="https://cdn.conversejs.org/10.1.6/dist/converse.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body id="page-top" data-spy="scroll" class="converse-website">
|
<body id="page-top" data-spy="scroll" class="converse-website">
|
||||||
|
22314
package-lock.json
generated
22314
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
42
package.json
42
package.json
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "converse.js",
|
"name": "converse.js",
|
||||||
"version": "10.1.2",
|
"version": "10.1.6",
|
||||||
"description": "Browser based XMPP chat client",
|
"description": "Browser based XMPP chat client",
|
||||||
"browser": "dist/converse.js",
|
"browser": "dist/converse.js",
|
||||||
"module": "src/converse.js",
|
"module": "src/index.js",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"src/headless"
|
"src/headless"
|
||||||
],
|
],
|
||||||
@ -15,6 +15,7 @@
|
|||||||
"dist/",
|
"dist/",
|
||||||
"docs/**/*.md",
|
"docs/**/*.md",
|
||||||
"docs/**/*.rst",
|
"docs/**/*.rst",
|
||||||
|
"sass/**/*.scss",
|
||||||
"src/**/*.html",
|
"src/**/*.html",
|
||||||
"src/**/*.js",
|
"src/**/*.js",
|
||||||
"src/**/*.json",
|
"src/**/*.json",
|
||||||
@ -23,20 +24,23 @@
|
|||||||
"src/**/*.pot",
|
"src/**/*.pot",
|
||||||
"src/**/*.scss",
|
"src/**/*.scss",
|
||||||
"src/**/*.svg",
|
"src/**/*.svg",
|
||||||
"src/**/*.txt"
|
"src/**/*.txt",
|
||||||
|
"3rdparty/*.js"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack/webpack.build.js",
|
"build": "webpack --config webpack/webpack.build.js",
|
||||||
|
"lint": "eslint src/**/*.js",
|
||||||
|
"test": "karma start karma.conf",
|
||||||
"cdn": "ASSET_PATH=https://cdn.conversejs.org/dist/ npm run build",
|
"cdn": "ASSET_PATH=https://cdn.conversejs.org/dist/ npm run build",
|
||||||
"clean": "rm -rf node_modules dist *.zip src/headless/dist src/headless/node_modules",
|
"clean": "rm -rf node_modules dist *.zip src/headless/dist src/headless/node_modules",
|
||||||
"dev": "webpack --config webpack/webpack.build.js --mode=development",
|
"dev": "webpack --config webpack/webpack.build.js --mode=development",
|
||||||
"headless": "webpack --config webpack/webpack.headless.js",
|
"headless": "webpack --config webpack/webpack.headless.js",
|
||||||
"headless-dev": "webpack --config webpack/webpack.headless.js --mode=development",
|
"headless-dev": "webpack --config webpack/webpack.headless.js --mode=development",
|
||||||
"lerna": "lerna bootstrap --hoist --ignore-scripts",
|
|
||||||
"nodeps": "webpack --config webpack/webpack.nodeps.js",
|
"nodeps": "webpack --config webpack/webpack.nodeps.js",
|
||||||
"prepare": "npm run lerna && npm run build",
|
|
||||||
"serve": "webpack serve --config webpack/webpack.serve.js",
|
"serve": "webpack serve --config webpack/webpack.serve.js",
|
||||||
"watch": "webpack --watch --config webpack/webpack.build.js --mode=development"
|
"watch": "webpack --watch --config webpack/webpack.build.js --mode=development",
|
||||||
|
"types": "tsc --declaration --emitDeclarationOnly --allowJs",
|
||||||
|
"check:types": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -65,13 +69,13 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.17.10",
|
"@babel/cli": "^7.17.10",
|
||||||
"@babel/core": "^7.18.5",
|
"@babel/core": "^7.18.5",
|
||||||
"@babel/eslint-parser": "^7.18.9",
|
|
||||||
"@babel/preset-env": "^7.18.2",
|
"@babel/preset-env": "^7.18.2",
|
||||||
"@converse/headless": "file:src/headless",
|
"@converse/headless": "file:src/headless",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
||||||
"autoprefixer": "^10.4.5",
|
"autoprefixer": "^10.4.5",
|
||||||
"babel-loader": "^9.1.0",
|
"babel-loader": "^9.1.0",
|
||||||
"bootstrap.native-loader": "2.0.0",
|
"bootstrap.native-loader": "2.0.0",
|
||||||
"clean-css-cli": "^5.6.0",
|
"clean-css-cli": "^5.6.2",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"eslint": "^8.21.0",
|
"eslint": "^8.21.0",
|
||||||
@ -87,41 +91,43 @@
|
|||||||
"karma-jasmine": "^5.0.0",
|
"karma-jasmine": "^5.0.0",
|
||||||
"karma-jasmine-html-reporter": "^2.0.0",
|
"karma-jasmine-html-reporter": "^2.0.0",
|
||||||
"karma-webpack": "^5.0.0",
|
"karma-webpack": "^5.0.0",
|
||||||
"lerna": "^6.0.1",
|
|
||||||
"mini-css-extract-plugin": "^2.6.0",
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
"minimist": "^1.2.6",
|
"minimist": "^1.2.6",
|
||||||
"po-loader": "0.7.0",
|
"po-loader": "0.7.0",
|
||||||
"po2json": "^1.0.0-beta-3",
|
"po2json": "^1.0.0-beta-3",
|
||||||
"postcss": "^8.4.14",
|
"postcss": "^8.4.16",
|
||||||
"postcss-clean": "1.2.0",
|
|
||||||
"postcss-loader": "^7.0.1",
|
"postcss-loader": "^7.0.1",
|
||||||
"prettierx": "^0.19.0",
|
"prettierx": "^0.19.0",
|
||||||
"sass": "^1.51.0",
|
"sass": "^1.51.0",
|
||||||
"sass-loader": "^13.1.0",
|
"sass-loader": "^13.1.0",
|
||||||
"style-loader": "^3.1.0",
|
"style-loader": "^3.1.0",
|
||||||
"webpack": "^5.72.0",
|
"tsc": "^2.0.4",
|
||||||
"webpack-cli": "^4.7.2",
|
"typescript": "^4.9.5",
|
||||||
|
"typescript-eslint-parser": "^22.0.0",
|
||||||
|
"uglify-js": "^3.17.4",
|
||||||
|
"webpack": "^5.86.0",
|
||||||
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^4.8.1",
|
"webpack-dev-server": "^4.8.1",
|
||||||
"webpack-merge": "^5.8.0"
|
"webpack-merge": "^5.8.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@converse/openpromise": "^0.0.1",
|
"@converse/openpromise": "^0.0.1",
|
||||||
"@converse/skeletor": "0.0.8",
|
"@converse/skeletor": "^0.0.8",
|
||||||
"bootstrap": "^4.6.0",
|
"bootstrap": "^4.6.0",
|
||||||
"bootstrap.native": "^2.0.27",
|
"bootstrap.native": "^2.0.27",
|
||||||
"client-compress": "^2.2.2",
|
"client-compress": "^2.2.2",
|
||||||
"dayjs": "1.11.6",
|
"dayjs": "^1.11.8",
|
||||||
"dompurify": "^2.3.1",
|
"dompurify": "^2.3.1",
|
||||||
"favico.js-slevomat": "^0.3.11",
|
"favico.js-slevomat": "^0.3.11",
|
||||||
"filesize": "^7.0.0",
|
"gifuct-js": "^2.1.2",
|
||||||
"jed": "1.1.1",
|
"jed": "1.1.1",
|
||||||
"lit": "^2.4.0",
|
"lit": "^2.4.0",
|
||||||
"localforage-webextensionstorage-driver": "^3.0.0",
|
"localforage-webextensionstorage-driver": "^3.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"pluggable.js": "3.0.1",
|
"pluggable.js": "^3.0.1",
|
||||||
"sizzle": "^2.3.5",
|
"sizzle": "^2.3.5",
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"strophe.js": "1.6.0",
|
"strophe.js": "^1.6.2",
|
||||||
"urijs": "^1.19.10"
|
"urijs": "^1.19.10"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@ -2,6 +2,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
require('autoprefixer'),
|
require('autoprefixer'),
|
||||||
require('postcss-clean')
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ const converse = {
|
|||||||
*
|
*
|
||||||
* @memberOf converse
|
* @memberOf converse
|
||||||
* @method load
|
* @method load
|
||||||
* @param {object} settings A map of configuration-settings that are needed at load time.
|
* @param { object } settings A map of configuration-settings that are needed at load time.
|
||||||
* @example
|
* @example
|
||||||
* converse.load({assets_path: '/path/to/assets/'});
|
* converse.load({assets_path: '/path/to/assets/'});
|
||||||
*/
|
*/
|
||||||
@ -57,7 +57,7 @@ const converse = {
|
|||||||
if (settings.assets_path) {
|
if (settings.assets_path) {
|
||||||
__webpack_public_path__ = settings.assets_path; // eslint-disable-line no-undef
|
__webpack_public_path__ = settings.assets_path; // eslint-disable-line no-undef
|
||||||
}
|
}
|
||||||
require('./converse.js');
|
require('./index.js');
|
||||||
Object.keys(plugins).forEach(name => converse.plugins.add(name, plugins[name]));
|
Object.keys(plugins).forEach(name => converse.plugins.add(name, plugins[name]));
|
||||||
return converse;
|
return converse;
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,5 @@ It's also installable with NPM/Yarn as [@converse/headless](https://www.npmjs.co
|
|||||||
|
|
||||||
The main distribution of Converse relies on the headless build.
|
The main distribution of Converse relies on the headless build.
|
||||||
|
|
||||||
The file [src/headless/headless.js](https://github.com/jcbrand/converse.js/blob/master/src/headless/headless.js)
|
The file [src/headless/index.js](https://github.com/jcbrand/converse.js/blob/master/src/headless/index.js)
|
||||||
is used to determine which plugins are included in the build.
|
is used to determine which plugins are included in the build.
|
||||||
|
@ -2,684 +2,16 @@
|
|||||||
* @copyright The Converse.js contributors
|
* @copyright The Converse.js contributors
|
||||||
* @license Mozilla Public License (MPLv2)
|
* @license Mozilla Public License (MPLv2)
|
||||||
*/
|
*/
|
||||||
import URI from 'urijs';
|
import './shared/constants.js';
|
||||||
import _converse from './shared/_converse';
|
import _converse from './shared/_converse';
|
||||||
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
||||||
import connection_api from './shared/connection/api.js';
|
import api from './shared/api/index.js';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import i18n from './shared/i18n';
|
import i18n from './shared/i18n';
|
||||||
import invoke from 'lodash-es/invoke';
|
|
||||||
import isFunction from 'lodash-es/isFunction';
|
|
||||||
import log from './log.js';
|
|
||||||
import pluggable from 'pluggable.js/src/pluggable.js';
|
|
||||||
import sizzle from 'sizzle';
|
|
||||||
import u, { setUnloadEvent, replacePromise } from './utils/core.js';
|
|
||||||
import { CHAT_STATES, KEYCODES } from './shared/constants.js';
|
|
||||||
import { Collection } from "@converse/skeletor/src/collection";
|
|
||||||
import { Events } from '@converse/skeletor/src/events.js';
|
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
|
||||||
import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
|
|
||||||
import { TimeoutError } from './shared/errors';
|
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
|
||||||
import { html } from 'lit';
|
|
||||||
import { initAppSettings } from './shared/settings/utils.js';
|
|
||||||
import { settings_api, user_settings_api } from './shared/settings/api.js';
|
|
||||||
import { sprintf } from 'sprintf-js';
|
|
||||||
|
|
||||||
|
export { converse } from './shared/api/public.js';
|
||||||
export { _converse };
|
export { _converse };
|
||||||
export { i18n };
|
export { i18n };
|
||||||
|
export { api };
|
||||||
import {
|
|
||||||
attemptNonPreboundSession,
|
|
||||||
cleanup,
|
|
||||||
initClientConfig,
|
|
||||||
initConnection,
|
|
||||||
initPlugins,
|
|
||||||
initSessionStorage,
|
|
||||||
registerGlobalEventHandlers,
|
|
||||||
setUserJID,
|
|
||||||
} from './utils/init.js';
|
|
||||||
|
|
||||||
dayjs.extend(advancedFormat);
|
dayjs.extend(advancedFormat);
|
||||||
|
|
||||||
// Add Strophe Namespaces
|
|
||||||
Strophe.addNamespace('ACTIVITY', 'http://jabber.org/protocol/activity');
|
|
||||||
Strophe.addNamespace('CARBONS', 'urn:xmpp:carbons:2');
|
|
||||||
Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
|
|
||||||
Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
|
|
||||||
Strophe.addNamespace('DELAY', 'urn:xmpp:delay');
|
|
||||||
Strophe.addNamespace('EME', 'urn:xmpp:eme:0');
|
|
||||||
Strophe.addNamespace('FASTEN', 'urn:xmpp:fasten:0');
|
|
||||||
Strophe.addNamespace('FORWARD', 'urn:xmpp:forward:0');
|
|
||||||
Strophe.addNamespace('HINTS', 'urn:xmpp:hints');
|
|
||||||
Strophe.addNamespace('HTTPUPLOAD', 'urn:xmpp:http:upload:0');
|
|
||||||
Strophe.addNamespace('MAM', 'urn:xmpp:mam:2');
|
|
||||||
Strophe.addNamespace('MARKERS', 'urn:xmpp:chat-markers:0');
|
|
||||||
Strophe.addNamespace('MENTIONS', 'urn:xmpp:mmn:0');
|
|
||||||
Strophe.addNamespace('MESSAGE_CORRECT', 'urn:xmpp:message-correct:0');
|
|
||||||
Strophe.addNamespace('MODERATE', 'urn:xmpp:message-moderate:0');
|
|
||||||
Strophe.addNamespace('NICK', 'http://jabber.org/protocol/nick');
|
|
||||||
Strophe.addNamespace('OCCUPANTID', 'urn:xmpp:occupant-id:0');
|
|
||||||
Strophe.addNamespace('OMEMO', 'eu.siacs.conversations.axolotl');
|
|
||||||
Strophe.addNamespace('OUTOFBAND', 'jabber:x:oob');
|
|
||||||
Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
|
|
||||||
Strophe.addNamespace('RAI', 'urn:xmpp:rai:0');
|
|
||||||
Strophe.addNamespace('RECEIPTS', 'urn:xmpp:receipts');
|
|
||||||
Strophe.addNamespace('REFERENCE', 'urn:xmpp:reference:0');
|
|
||||||
Strophe.addNamespace('REGISTER', 'jabber:iq:register');
|
|
||||||
Strophe.addNamespace('RETRACT', 'urn:xmpp:message-retract:0');
|
|
||||||
Strophe.addNamespace('ROSTERX', 'http://jabber.org/protocol/rosterx');
|
|
||||||
Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
|
||||||
Strophe.addNamespace('SID', 'urn:xmpp:sid:0');
|
|
||||||
Strophe.addNamespace('SPOILER', 'urn:xmpp:spoiler:0');
|
|
||||||
Strophe.addNamespace('STANZAS', 'urn:ietf:params:xml:ns:xmpp-stanzas');
|
|
||||||
Strophe.addNamespace('STYLING', 'urn:xmpp:styling:0');
|
|
||||||
Strophe.addNamespace('VCARD', 'vcard-temp');
|
|
||||||
Strophe.addNamespace('VCARDUPDATE', 'vcard-temp:x:update');
|
|
||||||
Strophe.addNamespace('XFORM', 'jabber:x:data');
|
|
||||||
Strophe.addNamespace('XHTML', 'http://www.w3.org/1999/xhtml');
|
|
||||||
|
|
||||||
_converse.VERSION_NAME = "v10.1.2";
|
|
||||||
|
|
||||||
Object.assign(_converse, Events);
|
|
||||||
|
|
||||||
// Make converse pluggable
|
|
||||||
pluggable.enable(_converse, '_converse', 'pluggable');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ### The private API
|
|
||||||
*
|
|
||||||
* The private API methods are only accessible via the closured {@link _converse}
|
|
||||||
* object, which is only available to plugins.
|
|
||||||
*
|
|
||||||
* These methods are kept private (i.e. not global) because they may return
|
|
||||||
* sensitive data which should be kept off-limits to other 3rd-party scripts
|
|
||||||
* that might be running in the page.
|
|
||||||
*
|
|
||||||
* @namespace _converse.api
|
|
||||||
* @memberOf _converse
|
|
||||||
*/
|
|
||||||
export const api = _converse.api = {
|
|
||||||
|
|
||||||
connection: connection_api,
|
|
||||||
settings: settings_api,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lets you trigger events, which can be listened to via
|
|
||||||
* {@link _converse.api.listen.on} or {@link _converse.api.listen.once}
|
|
||||||
* (see [_converse.api.listen](http://localhost:8000/docs/html/api/-_converse.api.listen.html)).
|
|
||||||
*
|
|
||||||
* Some events also double as promises and can be waited on via {@link _converse.api.waitUntil}.
|
|
||||||
*
|
|
||||||
* @method _converse.api.trigger
|
|
||||||
* @param {string} name - The event name
|
|
||||||
* @param {...any} [argument] - Argument to be passed to the event handler
|
|
||||||
* @param {object} [options]
|
|
||||||
* @param {boolean} [options.synchronous] - Whether the event is synchronous or not.
|
|
||||||
* When a synchronous event is fired, a promise will be returned
|
|
||||||
* by {@link _converse.api.trigger} which resolves once all the
|
|
||||||
* event handlers' promises have been resolved.
|
|
||||||
*/
|
|
||||||
async trigger (name) {
|
|
||||||
if (!_converse._events) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const args = Array.from(arguments);
|
|
||||||
const options = args.pop();
|
|
||||||
if (options && options.synchronous) {
|
|
||||||
const events = _converse._events[name] || [];
|
|
||||||
const event_args = args.splice(1);
|
|
||||||
await Promise.all(events.map(e => e.callback.apply(e.ctx, event_args)));
|
|
||||||
} else {
|
|
||||||
_converse.trigger.apply(_converse, arguments);
|
|
||||||
}
|
|
||||||
const promise = _converse.promises[name];
|
|
||||||
if (promise !== undefined) {
|
|
||||||
promise.resolve();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers a hook which can be intercepted by registered listeners via
|
|
||||||
* {@link _converse.api.listen.on} or {@link _converse.api.listen.once}.
|
|
||||||
* (see [_converse.api.listen](http://localhost:8000/docs/html/api/-_converse.api.listen.html)).
|
|
||||||
* A hook is a special kind of event which allows you to intercept a data
|
|
||||||
* structure in order to modify it, before passing it back.
|
|
||||||
* @async
|
|
||||||
* @param {string} name - The hook name
|
|
||||||
* @param {...any} context - The context to which the hook applies (could be for example, a {@link _converse.ChatBox)).
|
|
||||||
* @param {...any} data - The data structure to be intercepted and modified by the hook listeners.
|
|
||||||
* @returns {Promise<any>} - A promise that resolves with the modified data structure.
|
|
||||||
*/
|
|
||||||
hook (name, context, data) {
|
|
||||||
const events = _converse._events[name] || [];
|
|
||||||
if (events.length) {
|
|
||||||
// Create a chain of promises, with each one feeding its output to
|
|
||||||
// the next. The first input is a promise with the original data
|
|
||||||
// sent to this hook.
|
|
||||||
return events.reduce((o, e) => o.then(d => e.callback(context, d)), Promise.resolve(data));
|
|
||||||
} else {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This grouping collects API functions related to the current logged in user.
|
|
||||||
*
|
|
||||||
* @namespace _converse.api.user
|
|
||||||
* @memberOf _converse.api
|
|
||||||
*/
|
|
||||||
user: {
|
|
||||||
settings: user_settings_api,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @method _converse.api.user.jid
|
|
||||||
* @returns {string} The current user's full JID (Jabber ID)
|
|
||||||
* @example _converse.api.user.jid())
|
|
||||||
*/
|
|
||||||
jid () {
|
|
||||||
return _converse.connection.jid;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the user in.
|
|
||||||
*
|
|
||||||
* If called without any parameters, Converse will try
|
|
||||||
* to log the user in by calling the `prebind_url` or `credentials_url` depending
|
|
||||||
* on whether prebinding is used or not.
|
|
||||||
*
|
|
||||||
* @method _converse.api.user.login
|
|
||||||
* @param {string} [jid]
|
|
||||||
* @param {string} [password]
|
|
||||||
* @param {boolean} [automatic=false] - An internally used flag that indicates whether
|
|
||||||
* this method was called automatically once the connection has been
|
|
||||||
* initialized. It's used together with the `auto_login` configuration flag
|
|
||||||
* to determine whether Converse should try to log the user in if it
|
|
||||||
* fails to restore a previous auth'd session.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
async login (jid, password, automatic=false) {
|
|
||||||
jid = jid || api.settings.get('jid');
|
|
||||||
if (!_converse.connection?.jid || (jid && !u.isSameDomain(_converse.connection.jid, jid))) {
|
|
||||||
initConnection();
|
|
||||||
}
|
|
||||||
if (api.settings.get("connection_options")?.worker && (await _converse.connection.restoreWorkerSession())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (jid) {
|
|
||||||
jid = await setUserJID(jid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See whether there is a BOSH session to re-attach to
|
|
||||||
const bosh_plugin = _converse.pluggable.plugins['converse-bosh'];
|
|
||||||
if (bosh_plugin?.enabled()) {
|
|
||||||
if (await _converse.restoreBOSHSession()) {
|
|
||||||
return;
|
|
||||||
} else if (api.settings.get("authentication") === _converse.PREBIND && (!automatic || api.settings.get("auto_login"))) {
|
|
||||||
return _converse.startNewPreboundBOSHSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
password = password || api.settings.get("password");
|
|
||||||
const credentials = (jid && password) ? { jid, password } : null;
|
|
||||||
attemptNonPreboundSession(credentials, automatic);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the user out of the current XMPP session.
|
|
||||||
* @method _converse.api.user.logout
|
|
||||||
* @example _converse.api.user.logout();
|
|
||||||
*/
|
|
||||||
async logout () {
|
|
||||||
/**
|
|
||||||
* Triggered before the user is logged out
|
|
||||||
* @event _converse#beforeLogout
|
|
||||||
*/
|
|
||||||
await api.trigger('beforeLogout', {'synchronous': true});
|
|
||||||
|
|
||||||
const promise = getOpenPromise();
|
|
||||||
const complete = () => {
|
|
||||||
// Recreate all the promises
|
|
||||||
Object.keys(_converse.promises).forEach(replacePromise);
|
|
||||||
delete _converse.jid
|
|
||||||
|
|
||||||
// Remove the session JID, otherwise the user would just be logged
|
|
||||||
// in again upon reload. See #2759
|
|
||||||
localStorage.removeItem('conversejs-session-jid');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggered once the user has logged out.
|
|
||||||
* @event _converse#logout
|
|
||||||
*/
|
|
||||||
api.trigger('logout');
|
|
||||||
promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
_converse.connection.setDisconnectionCause(_converse.LOGOUT, undefined, true);
|
|
||||||
if (_converse.connection !== undefined) {
|
|
||||||
api.listen.once('disconnected', () => complete());
|
|
||||||
_converse.connection.disconnect();
|
|
||||||
} else {
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converse and its plugins trigger various events which you can listen to via the
|
|
||||||
* {@link _converse.api.listen} namespace.
|
|
||||||
*
|
|
||||||
* Some of these events are also available as [ES2015 Promises](http://es6-features.org/#PromiseUsage)
|
|
||||||
* although not all of them could logically act as promises, since some events
|
|
||||||
* might be fired multpile times whereas promises are to be resolved (or
|
|
||||||
* rejected) only once.
|
|
||||||
*
|
|
||||||
* Events which are also promises include:
|
|
||||||
*
|
|
||||||
* * [cachedRoster](/docs/html/events.html#cachedroster)
|
|
||||||
* * [chatBoxesFetched](/docs/html/events.html#chatBoxesFetched)
|
|
||||||
* * [pluginsInitialized](/docs/html/events.html#pluginsInitialized)
|
|
||||||
* * [roster](/docs/html/events.html#roster)
|
|
||||||
* * [rosterContactsFetched](/docs/html/events.html#rosterContactsFetched)
|
|
||||||
* * [rosterGroupsFetched](/docs/html/events.html#rosterGroupsFetched)
|
|
||||||
* * [rosterInitialized](/docs/html/events.html#rosterInitialized)
|
|
||||||
*
|
|
||||||
* The various plugins might also provide promises, and they do this by using the
|
|
||||||
* `promises.add` api method.
|
|
||||||
*
|
|
||||||
* @namespace _converse.api.promises
|
|
||||||
* @memberOf _converse.api
|
|
||||||
*/
|
|
||||||
promises: {
|
|
||||||
/**
|
|
||||||
* By calling `promises.add`, a new [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
|
||||||
* is made available for other code or plugins to depend on via the
|
|
||||||
* {@link _converse.api.waitUntil} method.
|
|
||||||
*
|
|
||||||
* Generally, it's the responsibility of the plugin which adds the promise to
|
|
||||||
* also resolve it.
|
|
||||||
*
|
|
||||||
* This is done by calling {@link _converse.api.trigger}, which not only resolves the
|
|
||||||
* promise, but also emits an event with the same name (which can be listened to
|
|
||||||
* via {@link _converse.api.listen}).
|
|
||||||
*
|
|
||||||
* @method _converse.api.promises.add
|
|
||||||
* @param {string|array} [name|names] The name or an array of names for the promise(s) to be added
|
|
||||||
* @param {boolean} [replace=true] Whether this promise should be replaced with a new one when the user logs out.
|
|
||||||
* @example _converse.api.promises.add('foo-completed');
|
|
||||||
*/
|
|
||||||
add (promises, replace=true) {
|
|
||||||
promises = Array.isArray(promises) ? promises : [promises];
|
|
||||||
promises.forEach(name => {
|
|
||||||
const promise = getOpenPromise();
|
|
||||||
promise.replace = replace;
|
|
||||||
_converse.promises[name] = promise;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converse emits events to which you can subscribe to.
|
|
||||||
*
|
|
||||||
* The `listen` namespace exposes methods for creating event listeners
|
|
||||||
* (aka handlers) for these events.
|
|
||||||
*
|
|
||||||
* @namespace _converse.api.listen
|
|
||||||
* @memberOf _converse
|
|
||||||
*/
|
|
||||||
listen: {
|
|
||||||
/**
|
|
||||||
* Lets you listen to an event exactly once.
|
|
||||||
* @method _converse.api.listen.once
|
|
||||||
* @param {string} name The event's name
|
|
||||||
* @param {function} callback The callback method to be called when the event is emitted.
|
|
||||||
* @param {object} [context] The value of the `this` parameter for the callback.
|
|
||||||
* @example _converse.api.listen.once('message', function (messageXML) { ... });
|
|
||||||
*/
|
|
||||||
once: _converse.once.bind(_converse),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lets you subscribe to an event.
|
|
||||||
* Every time the event fires, the callback method specified by `callback` will be called.
|
|
||||||
* @method _converse.api.listen.on
|
|
||||||
* @param {string} name The event's name
|
|
||||||
* @param {function} callback The callback method to be called when the event is emitted.
|
|
||||||
* @param {object} [context] The value of the `this` parameter for the callback.
|
|
||||||
* @example _converse.api.listen.on('message', function (messageXML) { ... });
|
|
||||||
*/
|
|
||||||
on: _converse.on.bind(_converse),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To stop listening to an event, you can use the `not` method.
|
|
||||||
* @method _converse.api.listen.not
|
|
||||||
* @param {string} name The event's name
|
|
||||||
* @param {function} callback The callback method that is to no longer be called when the event fires
|
|
||||||
* @example _converse.api.listen.not('message', function (messageXML);
|
|
||||||
*/
|
|
||||||
not: _converse.off.bind(_converse),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribe to an incoming stanza
|
|
||||||
* Every a matched stanza is received, the callback method specified by
|
|
||||||
* `callback` will be called.
|
|
||||||
* @method _converse.api.listen.stanza
|
|
||||||
* @param {string} name The stanza's name
|
|
||||||
* @param {object} options Matching options (e.g. 'ns' for namespace, 'type' for stanza type, also 'id' and 'from');
|
|
||||||
* @param {function} handler The callback method to be called when the stanza appears
|
|
||||||
*/
|
|
||||||
stanza (name, options, handler) {
|
|
||||||
if (isFunction(options)) {
|
|
||||||
handler = options;
|
|
||||||
options = {};
|
|
||||||
} else {
|
|
||||||
options = options || {};
|
|
||||||
}
|
|
||||||
_converse.connection.addHandler(
|
|
||||||
handler,
|
|
||||||
options.ns,
|
|
||||||
name,
|
|
||||||
options.type,
|
|
||||||
options.id,
|
|
||||||
options.from,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait until a promise is resolved or until the passed in function returns
|
|
||||||
* a truthy value.
|
|
||||||
* @method _converse.api.waitUntil
|
|
||||||
* @param {string|function} condition - The name of the promise to wait for,
|
|
||||||
* or a function which should eventually return a truthy value.
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
waitUntil (condition) {
|
|
||||||
if (isFunction(condition)) {
|
|
||||||
return u.waitUntil(condition);
|
|
||||||
} else {
|
|
||||||
const promise = _converse.promises[condition];
|
|
||||||
if (promise === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows you to send XML stanzas.
|
|
||||||
* @method _converse.api.send
|
|
||||||
* @param {XMLElement} stanza
|
|
||||||
* @return {void}
|
|
||||||
* @example
|
|
||||||
* const msg = converse.env.$msg({
|
|
||||||
* 'from': 'juliet@example.com/balcony',
|
|
||||||
* 'to': 'romeo@example.net',
|
|
||||||
* 'type':'chat'
|
|
||||||
* });
|
|
||||||
* _converse.api.send(msg);
|
|
||||||
*/
|
|
||||||
send (stanza) {
|
|
||||||
if (!api.connection.connected()) {
|
|
||||||
log.warn("Not sending stanza because we're not connected!");
|
|
||||||
log.warn(Strophe.serialize(stanza));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (typeof stanza === 'string') {
|
|
||||||
stanza = u.toStanza(stanza);
|
|
||||||
} else if (stanza?.tree) {
|
|
||||||
stanza = stanza.tree();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stanza.tagName === 'iq') {
|
|
||||||
return api.sendIQ(stanza);
|
|
||||||
} else {
|
|
||||||
_converse.connection.send(stanza);
|
|
||||||
api.trigger('send', stanza);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an IQ stanza
|
|
||||||
* @method _converse.api.sendIQ
|
|
||||||
* @param {XMLElement} stanza
|
|
||||||
* @param {Integer} [timeout=_converse.STANZA_TIMEOUT]
|
|
||||||
* @param {Boolean} [reject=true] - Whether an error IQ should cause the promise
|
|
||||||
* to be rejected. If `false`, the promise will resolve instead of being rejected.
|
|
||||||
* @returns {Promise} A promise which resolves (or potentially rejected) once we
|
|
||||||
* receive a `result` or `error` stanza or once a timeout is reached.
|
|
||||||
* If the IQ stanza being sent is of type `result` or `error`, there's
|
|
||||||
* nothing to wait for, so an already resolved promise is returned.
|
|
||||||
*/
|
|
||||||
sendIQ (stanza, timeout=_converse.STANZA_TIMEOUT, reject=true) {
|
|
||||||
|
|
||||||
const { connection } = _converse;
|
|
||||||
|
|
||||||
let promise;
|
|
||||||
stanza = stanza.tree?.() ?? stanza;
|
|
||||||
if (['get', 'set'].includes(stanza.getAttribute('type'))) {
|
|
||||||
timeout = timeout || _converse.STANZA_TIMEOUT;
|
|
||||||
if (reject) {
|
|
||||||
promise = new Promise((resolve, reject) => connection.sendIQ(stanza, resolve, reject, timeout));
|
|
||||||
promise.catch((e) => {
|
|
||||||
if (e === null) {
|
|
||||||
throw new TimeoutError(
|
|
||||||
`Timeout error after ${timeout}ms for the following IQ stanza: ${Strophe.serialize(stanza)}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
promise = new Promise((resolve) => connection.sendIQ(stanza, resolve, resolve, timeout));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_converse.connection.sendIQ(stanza);
|
|
||||||
promise = Promise.resolve();
|
|
||||||
}
|
|
||||||
api.trigger('send', stanza);
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
_converse.shouldClearCache = () => (
|
|
||||||
!_converse.config.get('trusted') ||
|
|
||||||
api.settings.get('clear_cache_on_logout') ||
|
|
||||||
_converse.isTestEnv()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
_converse.ConnectionFeedback = Model.extend({
|
|
||||||
defaults: {
|
|
||||||
'connection_status': Strophe.Status.DISCONNECTED,
|
|
||||||
'message': ''
|
|
||||||
},
|
|
||||||
initialize () {
|
|
||||||
this.on('change', () => api.trigger('connfeedback', _converse.connfeedback));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
export const converse = window.converse || {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ### The Public API
|
|
||||||
*
|
|
||||||
* This namespace contains public API methods which are are
|
|
||||||
* accessible on the global `converse` object.
|
|
||||||
* They are public, because any JavaScript in the
|
|
||||||
* page can call them. Public methods therefore don’t expose any sensitive
|
|
||||||
* or closured data. To do that, you’ll need to create a plugin, which has
|
|
||||||
* access to the private API method.
|
|
||||||
*
|
|
||||||
* @global
|
|
||||||
* @namespace converse
|
|
||||||
*/
|
|
||||||
Object.assign(converse, {
|
|
||||||
|
|
||||||
CHAT_STATES,
|
|
||||||
|
|
||||||
keycodes: KEYCODES,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public API method which initializes Converse.
|
|
||||||
* This method must always be called when using Converse.
|
|
||||||
* @async
|
|
||||||
* @memberOf converse
|
|
||||||
* @method initialize
|
|
||||||
* @param {object} config A map of [configuration-settings](https://conversejs.org/docs/html/configuration.html#configuration-settings).
|
|
||||||
* @example
|
|
||||||
* converse.initialize({
|
|
||||||
* auto_list_rooms: false,
|
|
||||||
* auto_subscribe: false,
|
|
||||||
* bosh_service_url: 'https://bind.example.com',
|
|
||||||
* hide_muc_server: false,
|
|
||||||
* i18n: 'en',
|
|
||||||
* play_sounds: true,
|
|
||||||
* show_controlbox_by_default: true,
|
|
||||||
* debug: false,
|
|
||||||
* roster_groups: true
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
async initialize (settings) {
|
|
||||||
await cleanup(_converse);
|
|
||||||
|
|
||||||
setUnloadEvent();
|
|
||||||
initAppSettings(settings);
|
|
||||||
_converse.strict_plugin_dependencies = settings.strict_plugin_dependencies; // Needed by pluggable.js
|
|
||||||
log.setLogLevel(api.settings.get("loglevel"));
|
|
||||||
|
|
||||||
if (api.settings.get("authentication") === _converse.ANONYMOUS) {
|
|
||||||
if (api.settings.get("auto_login") && !api.settings.get('jid')) {
|
|
||||||
throw new Error("Config Error: you need to provide the server's " +
|
|
||||||
"domain via the 'jid' option when using anonymous " +
|
|
||||||
"authentication with auto_login.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_converse.router.route(
|
|
||||||
/^converse\?loglevel=(debug|info|warn|error|fatal)$/, 'loglevel',
|
|
||||||
l => log.setLogLevel(l)
|
|
||||||
);
|
|
||||||
_converse.connfeedback = new _converse.ConnectionFeedback();
|
|
||||||
|
|
||||||
/* When reloading the page:
|
|
||||||
* For new sessions, we need to send out a presence stanza to notify
|
|
||||||
* the server/network that we're online.
|
|
||||||
* When re-attaching to an existing session we don't need to again send out a presence stanza,
|
|
||||||
* because it's as if "we never left" (see onConnectStatusChanged).
|
|
||||||
* https://github.com/conversejs/converse.js/issues/521
|
|
||||||
*/
|
|
||||||
_converse.send_initial_presence = true;
|
|
||||||
|
|
||||||
await initSessionStorage(_converse);
|
|
||||||
await initClientConfig(_converse);
|
|
||||||
await i18n.initialize();
|
|
||||||
initPlugins(_converse);
|
|
||||||
|
|
||||||
// Register all custom elements
|
|
||||||
// XXX: api.elements is defined in the UI part of Converse, outside of @converse/headless.
|
|
||||||
// This line should probably be moved to the UI code as part of a larger refactoring.
|
|
||||||
api.elements?.register();
|
|
||||||
|
|
||||||
registerGlobalEventHandlers(_converse);
|
|
||||||
|
|
||||||
try {
|
|
||||||
!History.started && _converse.router.history.start();
|
|
||||||
} catch (e) {
|
|
||||||
log.error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
const plugins = _converse.pluggable.plugins
|
|
||||||
if (api.settings.get("auto_login") || api.settings.get("keepalive") && invoke(plugins['converse-bosh'], 'enabled')) {
|
|
||||||
await api.user.login(null, null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggered once converse.initialize has finished.
|
|
||||||
* @event _converse#initialized
|
|
||||||
*/
|
|
||||||
api.trigger('initialized');
|
|
||||||
|
|
||||||
if (_converse.isTestEnv()) {
|
|
||||||
return _converse;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes methods for adding and removing plugins. You'll need to write a plugin
|
|
||||||
* if you want to have access to the private API methods defined further down below.
|
|
||||||
*
|
|
||||||
* For more information on plugins, read the documentation on [writing a plugin](/docs/html/plugin_development.html).
|
|
||||||
* @namespace plugins
|
|
||||||
* @memberOf converse
|
|
||||||
*/
|
|
||||||
plugins: {
|
|
||||||
/**
|
|
||||||
* Registers a new plugin.
|
|
||||||
* @method converse.plugins.add
|
|
||||||
* @param {string} name The name of the plugin
|
|
||||||
* @param {object} plugin The plugin object
|
|
||||||
* @example
|
|
||||||
* const plugin = {
|
|
||||||
* initialize: function () {
|
|
||||||
* // Gets called as soon as the plugin has been loaded.
|
|
||||||
*
|
|
||||||
* // Inside this method, you have access to the private
|
|
||||||
* // API via `_covnerse.api`.
|
|
||||||
*
|
|
||||||
* // The private _converse object contains the core logic
|
|
||||||
* // and data-structures of Converse.
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* converse.plugins.add('myplugin', plugin);
|
|
||||||
*/
|
|
||||||
add (name, plugin) {
|
|
||||||
plugin.__name__ = name;
|
|
||||||
if (_converse.pluggable.plugins[name] !== undefined) {
|
|
||||||
throw new TypeError(
|
|
||||||
`Error: plugin with name "${name}" has already been ` + 'registered!'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_converse.pluggable.plugins[name] = plugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Utility methods and globals from bundled 3rd party libraries.
|
|
||||||
* @typedef ConverseEnv
|
|
||||||
* @property {function} converse.env.$build - Creates a Strophe.Builder, for creating stanza objects.
|
|
||||||
* @property {function} converse.env.$iq - Creates a Strophe.Builder with an <iq/> element as the root.
|
|
||||||
* @property {function} converse.env.$msg - Creates a Strophe.Builder with an <message/> element as the root.
|
|
||||||
* @property {function} converse.env.$pres - Creates a Strophe.Builder with an <presence/> element as the root.
|
|
||||||
* @property {function} converse.env.Promise - The Promise implementation used by Converse.
|
|
||||||
* @property {function} converse.env.Strophe - The [Strophe](http://strophe.im/strophejs) XMPP library used by Converse.
|
|
||||||
* @property {function} converse.env.f - And instance of Lodash with its methods wrapped to produce immutable auto-curried iteratee-first data-last methods.
|
|
||||||
* @property {function} converse.env.sizzle - [Sizzle](https://sizzlejs.com) CSS selector engine.
|
|
||||||
* @property {function} converse.env.sprintf
|
|
||||||
* @property {object} converse.env._ - The instance of [lodash-es](http://lodash.com) used by Converse.
|
|
||||||
* @property {object} converse.env.dayjs - [DayJS](https://github.com/iamkun/dayjs) date manipulation library.
|
|
||||||
* @property {object} converse.env.utils - Module containing common utility methods used by Converse.
|
|
||||||
* @memberOf converse
|
|
||||||
*/
|
|
||||||
'env': {
|
|
||||||
$build,
|
|
||||||
$iq,
|
|
||||||
$msg,
|
|
||||||
$pres,
|
|
||||||
'utils': u,
|
|
||||||
Collection,
|
|
||||||
Model,
|
|
||||||
Promise,
|
|
||||||
Strophe,
|
|
||||||
URI,
|
|
||||||
dayjs,
|
|
||||||
html,
|
|
||||||
log,
|
|
||||||
sizzle,
|
|
||||||
sprintf,
|
|
||||||
stx: u.stx,
|
|
||||||
u,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
@ -8,24 +8,26 @@ const LEVELS = {
|
|||||||
'fatal': 4
|
'fatal': 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||||
const logger = Object.assign({
|
const logger = Object.assign({
|
||||||
'debug': console?.log ? console.log.bind(console) : function noop () {},
|
'debug': console?.log ? console.log.bind(console) : function noop () {},
|
||||||
'error': console?.log ? console.log.bind(console) : function noop () {},
|
'error': console?.log ? console.log.bind(console) : function noop () {},
|
||||||
'info': console?.log ? console.log.bind(console) : function noop () {},
|
'info': console?.log ? console.log.bind(console) : function noop () {},
|
||||||
'warn': console?.log ? console.log.bind(console) : function noop () {}
|
'warn': console?.log ? console.log.bind(console) : function noop () {}
|
||||||
}, console);
|
}, console);
|
||||||
|
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The log namespace
|
* The log namespace
|
||||||
* @namespace log
|
* @namespace log
|
||||||
*/
|
*/
|
||||||
const log = {
|
export default {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The the log-level, which determines how verbose the logging is.
|
* The the log-level, which determines how verbose the logging is.
|
||||||
* @method log#setLogLevel
|
* @method log#setLogLevel
|
||||||
* @param { integer } level - The loglevel which allows for filtering of log messages
|
* @param { number } level - The loglevel which allows for filtering of log messages
|
||||||
*/
|
*/
|
||||||
setLogLevel (level) {
|
setLogLevel (level) {
|
||||||
if (!['debug', 'info', 'warn', 'error', 'fatal'].includes(level)) {
|
if (!['debug', 'info', 'warn', 'error', 'fatal'].includes(level)) {
|
||||||
@ -42,7 +44,7 @@ const log = {
|
|||||||
* logged as well.
|
* logged as well.
|
||||||
* @method log#log
|
* @method log#log
|
||||||
* @param { string | Error } message - The message to be logged
|
* @param { string | Error } message - The message to be logged
|
||||||
* @param { integer } level - The loglevel which allows for filtering of log messages
|
* @param { number } level - The loglevel which allows for filtering of log messages
|
||||||
*/
|
*/
|
||||||
log (message, level, style='') {
|
log (message, level, style='') {
|
||||||
if (LEVELS[level] < LEVELS[this.loglevel]) {
|
if (LEVELS[level] < LEVELS[this.loglevel]) {
|
||||||
@ -93,5 +95,3 @@ const log = {
|
|||||||
this.log(message, 'fatal', style);
|
this.log(message, 'fatal', style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default log;
|
|
||||||
|
2
src/headless/package-lock.json
generated
2
src/headless/package-lock.json
generated
@ -11,7 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@converse/openpromise": "^0.0.1",
|
"@converse/openpromise": "^0.0.1",
|
||||||
"@converse/skeletor": "0.0.8",
|
"@converse/skeletor": "0.0.8",
|
||||||
"dayjs": "1.11.6",
|
"dayjs": "1.11.8",
|
||||||
"dompurify": "^2.3.1",
|
"dompurify": "^2.3.1",
|
||||||
"filesize": "^7.0.0",
|
"filesize": "^7.0.0",
|
||||||
"localforage-webextensionstorage-driver": "^3.0.0",
|
"localforage-webextensionstorage-driver": "^3.0.0",
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@converse/headless",
|
"name": "@converse/headless",
|
||||||
"version": "10.1.2",
|
"version": "10.1.6",
|
||||||
"description": "Converse.js Headless build",
|
"description": "Converse.js Headless build",
|
||||||
"author": {
|
"author": "JC Brand <jc@opkode.com>",
|
||||||
"name": "JC Brand",
|
"contributors": [
|
||||||
"email": "jc@opkode.com"
|
"cmrd Senya <senya@riseup.net>"
|
||||||
},
|
],
|
||||||
"contributors": ["cmrd Senya <senya@riseup.net>"],
|
|
||||||
"homepage": "https://conversejs.org",
|
"homepage": "https://conversejs.org",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"main": "dist/converse-headless.js",
|
"main": "dist/converse-headless.js",
|
||||||
"module": "headless.js",
|
"module": "index.js",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"converse.js",
|
"converse.js",
|
||||||
"XMPP",
|
"XMPP",
|
||||||
@ -31,19 +30,19 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/conversejs/converse.js/issues"
|
"url": "https://github.com/conversejs/converse.js/issues"
|
||||||
},
|
},
|
||||||
"gitHead": "9641dcdc820e029b05930479c242d2b707bbe8e2",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@converse/openpromise": "^0.0.1",
|
"@converse/openpromise": "^0.0.1",
|
||||||
"@converse/skeletor": "0.0.8",
|
"@converse/skeletor": "^0.0.8",
|
||||||
"dayjs": "1.11.6",
|
"dayjs": "^1.11.8",
|
||||||
"dompurify": "^2.3.1",
|
"dompurify": "^2.3.1",
|
||||||
"filesize": "^7.0.0",
|
"filesize": "^10.0.7",
|
||||||
"localforage-webextensionstorage-driver": "^3.0.0",
|
"localforage-webextensionstorage-driver": "^3.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"pluggable.js": "3.0.1",
|
"pluggable.js": "3.0.1",
|
||||||
"sizzle": "^2.3.5",
|
"sizzle": "^2.3.5",
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"strophe.js": "1.6.0",
|
"strophe.js": "^1.6.2",
|
||||||
"urijs": "^1.19.10"
|
"urijs": "^1.19.10"
|
||||||
}
|
},
|
||||||
|
"devDependencies": {}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ converse.plugins.add('converse-bosh', {
|
|||||||
tokens: {
|
tokens: {
|
||||||
/**
|
/**
|
||||||
* @method api.tokens.get
|
* @method api.tokens.get
|
||||||
* @param {string} [id] The type of token to return ('rid' or 'sid').
|
* @param { string } [id] The type of token to return ('rid' or 'sid').
|
||||||
* @returns 'string' A token, either the RID or SID token depending on what's asked for.
|
* @returns 'string' A token, either the RID or SID token depending on what's asked for.
|
||||||
* @example _converse.api.tokens.get('rid');
|
* @example _converse.api.tokens.get('rid');
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,7 @@ async function createCapsNode () {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a stanza, adds a XEP-0115 CAPS element
|
* Given a stanza, adds a XEP-0115 CAPS element
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
export async function addCapsNode (stanza) {
|
export async function addCapsNode (stanza) {
|
||||||
const caps_el = await createCapsNode();
|
const caps_el = await createCapsNode();
|
||||||
|
@ -13,7 +13,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* @method api.chats.create
|
* @method api.chats.create
|
||||||
* @param {string|string[]} jid|jids An jid or array of jids
|
* @param {string|string[]} jid|jids An jid or array of jids
|
||||||
* @param {object} [attrs] An object containing configuration attributes.
|
* @param { object } [attrs] An object containing configuration attributes.
|
||||||
*/
|
*/
|
||||||
async create (jids, attrs) {
|
async create (jids, attrs) {
|
||||||
if (typeof jids === 'string') {
|
if (typeof jids === 'string') {
|
||||||
@ -44,9 +44,9 @@ export default {
|
|||||||
*
|
*
|
||||||
* @method api.chats.open
|
* @method api.chats.open
|
||||||
* @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
* @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||||
* @param {Object} [attrs] - Attributes to be set on the _converse.ChatBox model.
|
* @param { Object } [attrs] - Attributes to be set on the _converse.ChatBox model.
|
||||||
* @param {Boolean} [attrs.minimized] - Should the chat be created in minimized state.
|
* @param { Boolean } [attrs.minimized] - Should the chat be created in minimized state.
|
||||||
* @param {Boolean} [force=false] - By default, a minimized
|
* @param { Boolean } [force=false] - By default, a minimized
|
||||||
* chat won't be maximized (in `overlayed` view mode) and in
|
* chat won't be maximized (in `overlayed` view mode) and in
|
||||||
* `fullscreen` view mode a newly opened chat won't replace
|
* `fullscreen` view mode a newly opened chat won't replace
|
||||||
* another chat already in the foreground.
|
* another chat already in the foreground.
|
||||||
@ -102,8 +102,8 @@ export default {
|
|||||||
*
|
*
|
||||||
* @method api.chats.get
|
* @method api.chats.get
|
||||||
* @param {String|string[]} jids - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
* @param {String|string[]} jids - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||||
* @param {Object} [attrs] - Attributes to be set on the _converse.ChatBox model.
|
* @param { Object } [attrs] - Attributes to be set on the _converse.ChatBox model.
|
||||||
* @param {Boolean} [create=false] - Whether the chat should be created if it's not found.
|
* @param { Boolean } [create=false] - Whether the chat should be created if it's not found.
|
||||||
* @returns { Promise<_converse.ChatBox> }
|
* @returns { Promise<_converse.ChatBox> }
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import ModelWithContact from './model-with-contact.js';
|
import ModelWithContact from './model-with-contact.js';
|
||||||
import filesize from "filesize";
|
|
||||||
import isMatch from "lodash-es/isMatch";
|
import isMatch from "lodash-es/isMatch";
|
||||||
import isObject from "lodash-es/isObject";
|
import isObject from "lodash-es/isObject";
|
||||||
import log from '@converse/headless/log';
|
import log from '@converse/headless/log';
|
||||||
import pick from "lodash-es/pick";
|
import pick from "lodash-es/pick";
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
|
import { TimeoutError } from '../../shared/errors.js';
|
||||||
import { _converse, api, converse } from "../../core.js";
|
import { _converse, api, converse } from "../../core.js";
|
||||||
import { debouncedPruneHistory, handleCorrection } from '@converse/headless/shared/chat/utils.js';
|
import { debouncedPruneHistory, handleCorrection } from '@converse/headless/shared/chat/utils.js';
|
||||||
|
import { filesize } from "filesize";
|
||||||
import { getMediaURLsMetadata } from '@converse/headless/shared/parsers.js';
|
import { getMediaURLsMetadata } from '@converse/headless/shared/parsers.js';
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
import { initStorage } from '@converse/headless/utils/storage.js';
|
import { initStorage } from '@converse/headless/utils/storage.js';
|
||||||
@ -368,7 +369,7 @@ const ChatBox = ModelWithContact.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async createMessageFromError (error) {
|
async createMessageFromError (error) {
|
||||||
if (error instanceof _converse.TimeoutError) {
|
if (error instanceof TimeoutError) {
|
||||||
const msg = await this.createMessage({
|
const msg = await this.createMessage({
|
||||||
'type': 'error',
|
'type': 'error',
|
||||||
'message': error.message,
|
'message': error.message,
|
||||||
|
@ -32,7 +32,7 @@ const { Strophe, sizzle } = converse.env;
|
|||||||
/**
|
/**
|
||||||
* Parses a passed in message stanza and returns an object of attributes.
|
* Parses a passed in message stanza and returns an object of attributes.
|
||||||
* @method st#parseMessage
|
* @method st#parseMessage
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @param { _converse } _converse
|
* @param { _converse } _converse
|
||||||
* @returns { (MessageAttributes|Error) }
|
* @returns { (MessageAttributes|Error) }
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
import log from '@converse/headless/log.js';
|
||||||
import { _converse, api, converse } from '@converse/headless/core.js';
|
import { _converse, api, converse } from '@converse/headless/core.js';
|
||||||
import { isArchived, isHeadline, isServerMessage, } from '@converse/headless/shared/parsers';
|
import { isArchived, isHeadline, isServerMessage, } from '@converse/headless/shared/parsers';
|
||||||
import { parseMessage } from './parsers.js';
|
import { parseMessage } from './parsers.js';
|
||||||
import log from '@converse/headless/log.js';
|
import { shouldClearCache } from '@converse/headless/utils/core.js';
|
||||||
|
|
||||||
const { Strophe, u } = converse.env;
|
const { Strophe, u } = converse.env;
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ export function openChat (jid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function onClearSession () {
|
export async function onClearSession () {
|
||||||
if (_converse.shouldClearCache()) {
|
if (shouldClearCache()) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
_converse.chatboxes.map(c => c.messages && c.messages.clearStore({ 'silent': true }))
|
_converse.chatboxes.map(c => c.messages && c.messages.clearStore({ 'silent': true }))
|
||||||
);
|
);
|
||||||
@ -113,7 +114,7 @@ export async function handleMessageStanza (stanza) {
|
|||||||
* @typedef { Object } MessageData
|
* @typedef { Object } MessageData
|
||||||
* An object containing the original message stanza, as well as the
|
* An object containing the original message stanza, as well as the
|
||||||
* parsed attributes.
|
* parsed attributes.
|
||||||
* @property { XMLElement } stanza
|
* @property { Element } stanza
|
||||||
* @property { MessageAttributes } stanza
|
* @property { MessageAttributes } stanza
|
||||||
* @property { ChatBox } chatbox
|
* @property { ChatBox } chatbox
|
||||||
*/
|
*/
|
||||||
|
@ -16,7 +16,7 @@ const ChatBoxes = Collection.extend({
|
|||||||
* @event _converse#chatBoxesFetched
|
* @event _converse#chatBoxesFetched
|
||||||
* @type { object }
|
* @type { object }
|
||||||
* @property { _converse.ChatBox | _converse.ChatRoom } chatbox
|
* @property { _converse.ChatBox | _converse.ChatRoom } chatbox
|
||||||
* @property { XMLElement } stanza
|
* @property { Element } stanza
|
||||||
* @example _converse.api.listen.on('chatBoxesFetched', obj => { ... });
|
* @example _converse.api.listen.on('chatBoxesFetched', obj => { ... });
|
||||||
* @example _converse.api.waitUntil('chatBoxesFetched').then(() => { ... });
|
* @example _converse.api.waitUntil('chatBoxesFetched').then(() => { ... });
|
||||||
*/
|
*/
|
||||||
|
@ -24,8 +24,8 @@ export default {
|
|||||||
stream: {
|
stream: {
|
||||||
/**
|
/**
|
||||||
* @method api.disco.stream.getFeature
|
* @method api.disco.stream.getFeature
|
||||||
* @param {String} name The feature name
|
* @param { String } name The feature name
|
||||||
* @param {String} xmlns The XML namespace
|
* @param { String } xmlns The XML namespace
|
||||||
* @example _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver')
|
* @example _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver')
|
||||||
*/
|
*/
|
||||||
async getFeature (name, xmlns) {
|
async getFeature (name, xmlns) {
|
||||||
@ -57,10 +57,10 @@ export default {
|
|||||||
* Lets you add new identities for this client (i.e. instance of Converse)
|
* Lets you add new identities for this client (i.e. instance of Converse)
|
||||||
* @method api.disco.own.identities.add
|
* @method api.disco.own.identities.add
|
||||||
*
|
*
|
||||||
* @param {String} category - server, client, gateway, directory, etc.
|
* @param { String } category - server, client, gateway, directory, etc.
|
||||||
* @param {String} type - phone, pc, web, etc.
|
* @param { String } type - phone, pc, web, etc.
|
||||||
* @param {String} name - "Converse"
|
* @param { String } name - "Converse"
|
||||||
* @param {String} lang - en, el, de, etc.
|
* @param { String } lang - en, el, de, etc.
|
||||||
*
|
*
|
||||||
* @example _converse.api.disco.own.identities.clear();
|
* @example _converse.api.disco.own.identities.clear();
|
||||||
*/
|
*/
|
||||||
@ -102,7 +102,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Lets you register new disco features for this client (i.e. instance of Converse)
|
* Lets you register new disco features for this client (i.e. instance of Converse)
|
||||||
* @method api.disco.own.features.add
|
* @method api.disco.own.features.add
|
||||||
* @param {String} name - e.g. http://jabber.org/protocol/caps
|
* @param { String } name - e.g. http://jabber.org/protocol/caps
|
||||||
* @example _converse.api.disco.own.features.add("http://jabber.org/protocol/caps");
|
* @example _converse.api.disco.own.features.add("http://jabber.org/protocol/caps");
|
||||||
*/
|
*/
|
||||||
add (name) {
|
add (name) {
|
||||||
@ -134,8 +134,8 @@ export default {
|
|||||||
* Query for information about an XMPP entity
|
* Query for information about an XMPP entity
|
||||||
*
|
*
|
||||||
* @method api.disco.info
|
* @method api.disco.info
|
||||||
* @param {string} jid The Jabber ID of the entity to query
|
* @param { string } jid The Jabber ID of the entity to query
|
||||||
* @param {string} [node] A specific node identifier associated with the JID
|
* @param { string } [node] A specific node identifier associated with the JID
|
||||||
* @returns {promise} Promise which resolves once we have a result from the server.
|
* @returns {promise} Promise which resolves once we have a result from the server.
|
||||||
*/
|
*/
|
||||||
info (jid, node) {
|
info (jid, node) {
|
||||||
@ -155,8 +155,8 @@ export default {
|
|||||||
* Query for items associated with an XMPP entity
|
* Query for items associated with an XMPP entity
|
||||||
*
|
*
|
||||||
* @method api.disco.items
|
* @method api.disco.items
|
||||||
* @param {string} jid The Jabber ID of the entity to query for items
|
* @param { string } jid The Jabber ID of the entity to query for items
|
||||||
* @param {string} [node] A specific node identifier associated with the JID
|
* @param { string } [node] A specific node identifier associated with the JID
|
||||||
* @returns {promise} Promise which resolves once we have a result from the server.
|
* @returns {promise} Promise which resolves once we have a result from the server.
|
||||||
*/
|
*/
|
||||||
items (jid, node) {
|
items (jid, node) {
|
||||||
@ -184,8 +184,8 @@ export default {
|
|||||||
* Get the corresponding `DiscoEntity` instance.
|
* Get the corresponding `DiscoEntity` instance.
|
||||||
*
|
*
|
||||||
* @method api.disco.entities.get
|
* @method api.disco.entities.get
|
||||||
* @param {string} jid The Jabber ID of the entity
|
* @param { string } jid The Jabber ID of the entity
|
||||||
* @param {boolean} [create] Whether the entity should be created if it doesn't exist.
|
* @param { boolean } [create] Whether the entity should be created if it doesn't exist.
|
||||||
* @example _converse.api.disco.entities.get(jid);
|
* @example _converse.api.disco.entities.get(jid);
|
||||||
*/
|
*/
|
||||||
async get (jid, create=false) {
|
async get (jid, create=false) {
|
||||||
@ -209,7 +209,7 @@ export default {
|
|||||||
* Return any disco items advertised on this entity
|
* Return any disco items advertised on this entity
|
||||||
*
|
*
|
||||||
* @method api.disco.entities.items
|
* @method api.disco.entities.items
|
||||||
* @param {string} jid The Jabber ID of the entity for which we want to fetch items
|
* @param { string } jid The Jabber ID of the entity for which we want to fetch items
|
||||||
* @example api.disco.entities.items(jid);
|
* @example api.disco.entities.items(jid);
|
||||||
*/
|
*/
|
||||||
items (jid) {
|
items (jid) {
|
||||||
@ -225,12 +225,12 @@ export default {
|
|||||||
* `ignore_cache: true` in the options parameter.
|
* `ignore_cache: true` in the options parameter.
|
||||||
*
|
*
|
||||||
* @method api.disco.entities.create
|
* @method api.disco.entities.create
|
||||||
* @param {object} data
|
* @param { object } data
|
||||||
* @param {string} data.jid - The Jabber ID of the entity
|
* @param { string } data.jid - The Jabber ID of the entity
|
||||||
* @param {string} data.parent_jid - The Jabber ID of the parent entity
|
* @param { string } data.parent_jid - The Jabber ID of the parent entity
|
||||||
* @param {string} data.name
|
* @param { string } data.name
|
||||||
* @param {object} [options] - Additional options
|
* @param { object } [options] - Additional options
|
||||||
* @param {boolean} [options.ignore_cache]
|
* @param { boolean } [options.ignore_cache]
|
||||||
* If true, fetch all features from the XMPP server instead of restoring them from cache
|
* If true, fetch all features from the XMPP server instead of restoring them from cache
|
||||||
* @example _converse.api.disco.entities.create({ jid }, {'ignore_cache': true});
|
* @example _converse.api.disco.entities.create({ jid }, {'ignore_cache': true});
|
||||||
*/
|
*/
|
||||||
@ -248,11 +248,11 @@ export default {
|
|||||||
* Return a given feature of a disco entity
|
* Return a given feature of a disco entity
|
||||||
*
|
*
|
||||||
* @method api.disco.features.get
|
* @method api.disco.features.get
|
||||||
* @param {string} feature The feature that might be
|
* @param { string } feature The feature that might be
|
||||||
* supported. In the XML stanza, this is the `var`
|
* supported. In the XML stanza, this is the `var`
|
||||||
* attribute of the `<feature>` element. For
|
* attribute of the `<feature>` element. For
|
||||||
* example: `http://jabber.org/protocol/muc`
|
* example: `http://jabber.org/protocol/muc`
|
||||||
* @param {string} jid The JID of the entity
|
* @param { string } jid The JID of the entity
|
||||||
* (and its associated items) which should be queried
|
* (and its associated items) which should be queried
|
||||||
* @returns {promise} A promise which resolves with a list containing
|
* @returns {promise} A promise which resolves with a list containing
|
||||||
* _converse.Entity instances representing the entity
|
* _converse.Entity instances representing the entity
|
||||||
@ -285,11 +285,11 @@ export default {
|
|||||||
* associated items, supports a given feature.
|
* associated items, supports a given feature.
|
||||||
*
|
*
|
||||||
* @method api.disco.features.has
|
* @method api.disco.features.has
|
||||||
* @param {string} feature The feature that might be
|
* @param { string } feature The feature that might be
|
||||||
* supported. In the XML stanza, this is the `var`
|
* supported. In the XML stanza, this is the `var`
|
||||||
* attribute of the `<feature>` element. For
|
* attribute of the `<feature>` element. For
|
||||||
* example: `http://jabber.org/protocol/muc`
|
* example: `http://jabber.org/protocol/muc`
|
||||||
* @param {string} jid The JID of the entity
|
* @param { string } jid The JID of the entity
|
||||||
* (and its associated items) which should be queried
|
* (and its associated items) which should be queried
|
||||||
* @returns {Promise} A promise which resolves with a boolean
|
* @returns {Promise} A promise which resolves with a boolean
|
||||||
* @example
|
* @example
|
||||||
@ -319,11 +319,11 @@ export default {
|
|||||||
* Used to determine whether an entity supports a given feature.
|
* Used to determine whether an entity supports a given feature.
|
||||||
*
|
*
|
||||||
* @method api.disco.supports
|
* @method api.disco.supports
|
||||||
* @param {string} feature The feature that might be
|
* @param { string } feature The feature that might be
|
||||||
* supported. In the XML stanza, this is the `var`
|
* supported. In the XML stanza, this is the `var`
|
||||||
* attribute of the `<feature>` element. For
|
* attribute of the `<feature>` element. For
|
||||||
* example: `http://jabber.org/protocol/muc`
|
* example: `http://jabber.org/protocol/muc`
|
||||||
* @param {string} jid The JID of the entity
|
* @param { string } jid The JID of the entity
|
||||||
* (and its associated items) which should be queried
|
* (and its associated items) which should be queried
|
||||||
* @returns {promise} A promise which resolves with `true` or `false`.
|
* @returns {promise} A promise which resolves with `true` or `false`.
|
||||||
* @example
|
* @example
|
||||||
@ -341,7 +341,7 @@ export default {
|
|||||||
* Refresh the features, fields and identities associated with a
|
* Refresh the features, fields and identities associated with a
|
||||||
* disco entity by refetching them from the server
|
* disco entity by refetching them from the server
|
||||||
* @method api.disco.refresh
|
* @method api.disco.refresh
|
||||||
* @param {string} jid The JID of the entity whose features are refreshed.
|
* @param { string } jid The JID of the entity whose features are refreshed.
|
||||||
* @returns {promise} A promise which resolves once the features have been refreshed
|
* @returns {promise} A promise which resolves once the features have been refreshed
|
||||||
* @example
|
* @example
|
||||||
* await api.disco.refresh('room@conference.example.org');
|
* await api.disco.refresh('room@conference.example.org');
|
||||||
@ -379,7 +379,7 @@ export default {
|
|||||||
* Return all the features associated with a disco entity
|
* Return all the features associated with a disco entity
|
||||||
*
|
*
|
||||||
* @method api.disco.getFeatures
|
* @method api.disco.getFeatures
|
||||||
* @param {string} jid The JID of the entity whose features are returned.
|
* @param { string } jid The JID of the entity whose features are returned.
|
||||||
* @returns {promise} A promise which resolves with the returned features
|
* @returns {promise} A promise which resolves with the returned features
|
||||||
* @example
|
* @example
|
||||||
* const features = await api.disco.getFeatures('room@conference.example.org');
|
* const features = await api.disco.getFeatures('room@conference.example.org');
|
||||||
@ -401,7 +401,7 @@ export default {
|
|||||||
* See [XEP-0129: Service Discovery Extensions](https://xmpp.org/extensions/xep-0128.html)
|
* See [XEP-0129: Service Discovery Extensions](https://xmpp.org/extensions/xep-0128.html)
|
||||||
*
|
*
|
||||||
* @method api.disco.getFields
|
* @method api.disco.getFields
|
||||||
* @param {string} jid The JID of the entity whose fields are returned.
|
* @param { string } jid The JID of the entity whose fields are returned.
|
||||||
* @example
|
* @example
|
||||||
* const fields = await api.disco.getFields('room@conference.example.org');
|
* const fields = await api.disco.getFields('room@conference.example.org');
|
||||||
*/
|
*/
|
||||||
@ -424,15 +424,15 @@ export default {
|
|||||||
* XEP-0163: https://xmpp.org/extensions/xep-0163.html#support
|
* XEP-0163: https://xmpp.org/extensions/xep-0163.html#support
|
||||||
*
|
*
|
||||||
* @method api.disco.getIdentity
|
* @method api.disco.getIdentity
|
||||||
* @param {string} The identity category.
|
* @param { string } The identity category.
|
||||||
* In the XML stanza, this is the `category`
|
* In the XML stanza, this is the `category`
|
||||||
* attribute of the `<identity>` element.
|
* attribute of the `<identity>` element.
|
||||||
* For example: 'pubsub'
|
* For example: 'pubsub'
|
||||||
* @param {string} type The identity type.
|
* @param { string } type The identity type.
|
||||||
* In the XML stanza, this is the `type`
|
* In the XML stanza, this is the `type`
|
||||||
* attribute of the `<identity>` element.
|
* attribute of the `<identity>` element.
|
||||||
* For example: 'pep'
|
* For example: 'pep'
|
||||||
* @param {string} jid The JID of the entity which might have the identity
|
* @param { string } jid The JID of the entity which might have the identity
|
||||||
* @returns {promise} A promise which resolves with a map indicating
|
* @returns {promise} A promise which resolves with a map indicating
|
||||||
* whether an identity with a given type is provided by the entity.
|
* whether an identity with a given type is provided by the entity.
|
||||||
* @example
|
* @example
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* @copyright 2022, the Converse.js contributors
|
* @copyright 2022, the Converse.js contributors
|
||||||
* @license Mozilla Public License (MPLv2)
|
* @license Mozilla Public License (MPLv2)
|
||||||
*/
|
*/
|
||||||
|
import './utils.js';
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { _converse, api, converse } from "../../core.js";
|
import { _converse, api, converse } from "../../core.js";
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
@ -85,8 +86,8 @@ converse.plugins.add('converse-emoji', {
|
|||||||
async initialize () {
|
async initialize () {
|
||||||
if (!converse.emojis.initialized) {
|
if (!converse.emojis.initialized) {
|
||||||
converse.emojis.initialized = true;
|
converse.emojis.initialized = true;
|
||||||
const { default: json } = await import(/*webpackChunkName: "emojis" */ './emoji.json');
|
const module = await import(/*webpackChunkName: "emojis" */ './emoji.json');
|
||||||
converse.emojis.json = json;
|
const json = converse.emojis.json = module.default;
|
||||||
converse.emojis.by_sn = Object.keys(json).reduce((result, cat) => Object.assign(result, json[cat]), {});
|
converse.emojis.by_sn = Object.keys(json).reduce((result, cat) => Object.assign(result, json[cat]), {});
|
||||||
converse.emojis.list = Object.values(converse.emojis.by_sn);
|
converse.emojis.list = Object.values(converse.emojis.by_sn);
|
||||||
converse.emojis.list.sort((a, b) => a.sn < b.sn ? -1 : (a.sn > b.sn ? 1 : 0));
|
converse.emojis.list.sort((a, b) => a.sn < b.sn ? -1 : (a.sn > b.sn ? 1 : 0));
|
||||||
|
@ -163,7 +163,7 @@ function shortnamesToUnicode (str) {
|
|||||||
* Determines whether the passed in string is just a single emoji shortname;
|
* Determines whether the passed in string is just a single emoji shortname;
|
||||||
* @namespace u
|
* @namespace u
|
||||||
* @method u.isOnlyEmojis
|
* @method u.isOnlyEmojis
|
||||||
* @param { String } shortname - A string which migh be just an emoji shortname
|
* @param { String } text - A string which migh be just an emoji shortname
|
||||||
* @returns { Boolean }
|
* @returns { Boolean }
|
||||||
*/
|
*/
|
||||||
function isOnlyEmojis (text) {
|
function isOnlyEmojis (text) {
|
||||||
|
@ -15,8 +15,8 @@ export default {
|
|||||||
*
|
*
|
||||||
* @method api.headlines.get
|
* @method api.headlines.get
|
||||||
* @param {String|String[]} jids - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
* @param {String|String[]} jids - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
|
||||||
* @param {Object} [attrs] - Attributes to be set on the _converse.ChatBox model.
|
* @param { Object } [attrs] - Attributes to be set on the _converse.ChatBox model.
|
||||||
* @param {Boolean} [create=false] - Whether the chat should be created if it's not found.
|
* @param { Boolean } [create=false] - Whether the chat should be created if it's not found.
|
||||||
* @returns { Promise<_converse.HeadlinesFeed> }
|
* @returns { Promise<_converse.HeadlinesFeed> }
|
||||||
*/
|
*/
|
||||||
async get (jids, attrs={}, create=false) {
|
async get (jids, attrs={}, create=false) {
|
||||||
|
@ -4,7 +4,7 @@ import { parseMessage } from '@converse/headless/plugins/chat/parsers';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler method for all incoming messages of type "headline".
|
* Handler method for all incoming messages of type "headline".
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
export async function onHeadlineMessage (stanza) {
|
export async function onHeadlineMessage (stanza) {
|
||||||
if (isHeadline(stanza) || isServerMessage(stanza)) {
|
if (isHeadline(stanza) || isServerMessage(stanza)) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { RSM } from '@converse/headless/shared/rsm';
|
|
||||||
import log from '@converse/headless/log';
|
import log from '@converse/headless/log';
|
||||||
import sizzle from "sizzle";
|
import sizzle from "sizzle";
|
||||||
|
import { RSM } from '@converse/headless/shared/rsm';
|
||||||
|
import { TimeoutError } from '../../shared/errors.js';
|
||||||
import { _converse, api, converse } from "@converse/headless/core";
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
|
|
||||||
const { Strophe, $iq, dayjs } = converse.env;
|
const { Strophe, $iq, dayjs } = converse.env;
|
||||||
@ -270,7 +271,7 @@ export default {
|
|||||||
const { __ } = _converse;
|
const { __ } = _converse;
|
||||||
const err_msg = __("Timeout while trying to fetch archived messages.");
|
const err_msg = __("Timeout while trying to fetch archived messages.");
|
||||||
log.error(err_msg);
|
log.error(err_msg);
|
||||||
error = new _converse.TimeoutError(err_msg);
|
error = new TimeoutError(err_msg);
|
||||||
return { messages, error };
|
return { messages, error };
|
||||||
|
|
||||||
} else if (u.isErrorStanza(iq_result)) {
|
} else if (u.isErrorStanza(iq_result)) {
|
||||||
|
@ -100,7 +100,7 @@ export async function handleMAMResult (model, result, query, options, should_pag
|
|||||||
/**
|
/**
|
||||||
* @typedef { Object } MAMOptions
|
* @typedef { Object } MAMOptions
|
||||||
* A map of MAM related options that may be passed to fetchArchivedMessages
|
* A map of MAM related options that may be passed to fetchArchivedMessages
|
||||||
* @param { integer } [options.max] - The maximum number of items to return.
|
* @param { number } [options.max] - The maximum number of items to return.
|
||||||
* Defaults to "archived_messages_page_size"
|
* Defaults to "archived_messages_page_size"
|
||||||
* @param { string } [options.after] - The XEP-0359 stanza ID of a message
|
* @param { string } [options.after] - The XEP-0359 stanza ID of a message
|
||||||
* after which messages should be returned. Implies forward paging.
|
* after which messages should be returned. Implies forward paging.
|
||||||
@ -117,7 +117,7 @@ export async function handleMAMResult (model, result, query, options, should_pag
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch XEP-0313 archived messages based on the passed in criteria.
|
* Fetch XEP-0313 archived messages based on the passed in criteria.
|
||||||
* @param { _converse.ChatBox | _converse.ChatRoom } model
|
* @param { ChatBox | ChatRoom } model
|
||||||
* @param { MAMOptions } [options]
|
* @param { MAMOptions } [options]
|
||||||
* @param { ('forwards'|'backwards'|null)} [should_page=null] - Determines whether
|
* @param { ('forwards'|'backwards'|null)} [should_page=null] - Determines whether
|
||||||
* this function should recursively page through the entire result set if a limited
|
* this function should recursively page through the entire result set if a limited
|
||||||
|
@ -45,7 +45,7 @@ export async function getAffiliationList (affiliation, muc_jid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an occupant model, see which affiliations may be assigned to that user.
|
* Given an occupant model, see which affiliations may be assigned by that user
|
||||||
* @param { Model } occupant
|
* @param { Model } occupant
|
||||||
* @returns { Array<('owner'|'admin'|'member'|'outcast'|'none')> } - An array of assignable affiliations
|
* @returns { Array<('owner'|'admin'|'member'|'outcast'|'none')> } - An array of assignable affiliations
|
||||||
*/
|
*/
|
||||||
@ -54,9 +54,9 @@ export function getAssignableAffiliations (occupant) {
|
|||||||
if (!Array.isArray(disabled)) {
|
if (!Array.isArray(disabled)) {
|
||||||
disabled = disabled ? AFFILIATIONS : [];
|
disabled = disabled ? AFFILIATIONS : [];
|
||||||
}
|
}
|
||||||
if (occupant.get('affiliation') === 'owner') {
|
if (occupant?.get('affiliation') === 'owner') {
|
||||||
return AFFILIATIONS.filter(a => !disabled.includes(a));
|
return AFFILIATIONS.filter(a => !disabled.includes(a));
|
||||||
} else if (occupant.get('affiliation') === 'admin') {
|
} else if (occupant?.get('affiliation') === 'admin') {
|
||||||
return AFFILIATIONS.filter(a => !['owner', 'admin', ...disabled].includes(a));
|
return AFFILIATIONS.filter(a => !['owner', 'admin', ...disabled].includes(a));
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
|
@ -23,7 +23,7 @@ export default {
|
|||||||
* @method api.rooms.create
|
* @method api.rooms.create
|
||||||
* @param {(string[]|string)} jid|jids The JID or array of
|
* @param {(string[]|string)} jid|jids The JID or array of
|
||||||
* JIDs of the chatroom(s) to create
|
* JIDs of the chatroom(s) to create
|
||||||
* @param {object} [attrs] attrs The room attributes
|
* @param { object } [attrs] attrs The room attributes
|
||||||
* @returns {Promise} Promise which resolves with the Model representing the chat.
|
* @returns {Promise} Promise which resolves with the Model representing the chat.
|
||||||
*/
|
*/
|
||||||
create (jids, attrs = {}) {
|
create (jids, attrs = {}) {
|
||||||
@ -45,24 +45,24 @@ export default {
|
|||||||
* Similar to {@link api.chats.open}, but for groupchats.
|
* Similar to {@link api.chats.open}, but for groupchats.
|
||||||
*
|
*
|
||||||
* @method api.rooms.open
|
* @method api.rooms.open
|
||||||
* @param {string} jid The room JID or JIDs (if not specified, all
|
* @param { string } jid The room JID or JIDs (if not specified, all
|
||||||
* currently open rooms will be returned).
|
* currently open rooms will be returned).
|
||||||
* @param {string} attrs A map containing any extra room attributes.
|
* @param { string } attrs A map containing any extra room attributes.
|
||||||
* @param {string} [attrs.nick] The current user's nickname for the MUC
|
* @param { string } [attrs.nick] The current user's nickname for the MUC
|
||||||
* @param {boolean} [attrs.auto_configure] A boolean, indicating
|
* @param { boolean } [attrs.auto_configure] A boolean, indicating
|
||||||
* whether the room should be configured automatically or not.
|
* whether the room should be configured automatically or not.
|
||||||
* If set to `true`, then it makes sense to pass in configuration settings.
|
* If set to `true`, then it makes sense to pass in configuration settings.
|
||||||
* @param {object} [attrs.roomconfig] A map of configuration settings to be used when the room gets
|
* @param { object } [attrs.roomconfig] A map of configuration settings to be used when the room gets
|
||||||
* configured automatically. Currently it doesn't make sense to specify
|
* configured automatically. Currently it doesn't make sense to specify
|
||||||
* `roomconfig` values if `auto_configure` is set to `false`.
|
* `roomconfig` values if `auto_configure` is set to `false`.
|
||||||
* For a list of configuration values that can be passed in, refer to these values
|
* For a list of configuration values that can be passed in, refer to these values
|
||||||
* in the [XEP-0045 MUC specification](https://xmpp.org/extensions/xep-0045.html#registrar-formtype-owner).
|
* in the [XEP-0045 MUC specification](https://xmpp.org/extensions/xep-0045.html#registrar-formtype-owner).
|
||||||
* The values should be named without the `muc#roomconfig_` prefix.
|
* The values should be named without the `muc#roomconfig_` prefix.
|
||||||
* @param {boolean} [attrs.minimized] A boolean, indicating whether the room should be opened minimized or not.
|
* @param { boolean } [attrs.minimized] A boolean, indicating whether the room should be opened minimized or not.
|
||||||
* @param {boolean} [attrs.bring_to_foreground] A boolean indicating whether the room should be
|
* @param { boolean } [attrs.bring_to_foreground] A boolean indicating whether the room should be
|
||||||
* brought to the foreground and therefore replace the currently shown chat.
|
* brought to the foreground and therefore replace the currently shown chat.
|
||||||
* If there is no chat currently open, then this option is ineffective.
|
* If there is no chat currently open, then this option is ineffective.
|
||||||
* @param {Boolean} [force=false] - By default, a minimized
|
* @param { Boolean } [force=false] - By default, a minimized
|
||||||
* room won't be maximized (in `overlayed` view mode) and in
|
* room won't be maximized (in `overlayed` view mode) and in
|
||||||
* `fullscreen` view mode a newly opened room won't replace
|
* `fullscreen` view mode a newly opened room won't replace
|
||||||
* another chat already in the foreground.
|
* another chat already in the foreground.
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import log from '../../log';
|
|
||||||
import { Strophe } from 'strophe.js/src/strophe';
|
import { Strophe } from 'strophe.js/src/strophe';
|
||||||
import { _converse, api } from '../../core.js';
|
import { _converse, api } from '../../core.js';
|
||||||
|
|
||||||
@ -20,6 +19,7 @@ const ChatRoomMessageMixin = {
|
|||||||
this.on('change:type', () => this.setOccupant());
|
this.on('change:type', () => this.setOccupant());
|
||||||
this.on('change:is_ephemeral', () => this.setTimerForEphemeralMessage());
|
this.on('change:is_ephemeral', () => this.setTimerForEphemeralMessage());
|
||||||
|
|
||||||
|
this.chatbox = this.collection?.chatbox;
|
||||||
this.setTimerForEphemeralMessage();
|
this.setTimerForEphemeralMessage();
|
||||||
this.setOccupant();
|
this.setOccupant();
|
||||||
/**
|
/**
|
||||||
@ -53,24 +53,20 @@ const ChatRoomMessageMixin = {
|
|||||||
return (
|
return (
|
||||||
['all', 'moderator'].includes(api.settings.get('allow_message_retraction')) &&
|
['all', 'moderator'].includes(api.settings.get('allow_message_retraction')) &&
|
||||||
this.get(`stanza_id ${this.get('from_muc')}`) &&
|
this.get(`stanza_id ${this.get('from_muc')}`) &&
|
||||||
this.collection.chatbox.canModerateMessages()
|
this.chatbox.canModerateMessages()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
checkValidity () {
|
checkValidity () {
|
||||||
const result = _converse.Message.prototype.checkValidity.call(this);
|
const result = _converse.Message.prototype.checkValidity.call(this);
|
||||||
!result && this.collection.chatbox.debouncedRejoin();
|
!result && this.chatbox.debouncedRejoin();
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
onOccupantRemoved () {
|
onOccupantRemoved () {
|
||||||
this.stopListening(this.occupant);
|
this.stopListening(this.occupant);
|
||||||
delete this.occupant;
|
delete this.occupant;
|
||||||
const chatbox = this?.collection?.chatbox;
|
this.listenTo(this.chatbox.occupants, 'add', this.onOccupantAdded);
|
||||||
if (!chatbox) {
|
|
||||||
return log.error(`Could not get collection.chatbox for message: ${JSON.stringify(this.toJSON())}`);
|
|
||||||
}
|
|
||||||
this.listenTo(chatbox.occupants, 'add', this.onOccupantAdded);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onOccupantAdded (occupant) {
|
onOccupantAdded (occupant) {
|
||||||
@ -81,10 +77,6 @@ const ChatRoomMessageMixin = {
|
|||||||
} else if (occupant.get('nick') !== Strophe.getResourceFromJid(this.get('from'))) {
|
} else if (occupant.get('nick') !== Strophe.getResourceFromJid(this.get('from'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const chatbox = this?.collection?.chatbox;
|
|
||||||
if (!chatbox) {
|
|
||||||
return log.error(`Could not get collection.chatbox for message: ${JSON.stringify(this.toJSON())}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.occupant = occupant;
|
this.occupant = occupant;
|
||||||
if (occupant.get('jid')) {
|
if (occupant.get('jid')) {
|
||||||
@ -93,32 +85,40 @@ const ChatRoomMessageMixin = {
|
|||||||
|
|
||||||
this.trigger('occupantAdded');
|
this.trigger('occupantAdded');
|
||||||
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
|
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
|
||||||
this.stopListening(chatbox.occupants, 'add', this.onOccupantAdded);
|
this.stopListening(this.chatbox.occupants, 'add', this.onOccupantAdded);
|
||||||
|
},
|
||||||
|
|
||||||
|
getOccupant() {
|
||||||
|
if (this.occupant) return this.occupant;
|
||||||
|
|
||||||
|
this.setOccupant();
|
||||||
|
return this.occupant;
|
||||||
},
|
},
|
||||||
|
|
||||||
setOccupant () {
|
setOccupant () {
|
||||||
if (this.get('type') !== 'groupchat' || this.isEphemeral() || this.occupant) {
|
if (this.get('type') !== 'groupchat' || this.isEphemeral() || this.occupant) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const chatbox = this?.collection?.chatbox;
|
|
||||||
if (!chatbox) {
|
|
||||||
return log.error(`Could not get collection.chatbox for message: ${JSON.stringify(this.toJSON())}`);
|
|
||||||
}
|
|
||||||
const nick = Strophe.getResourceFromJid(this.get('from'));
|
const nick = Strophe.getResourceFromJid(this.get('from'));
|
||||||
const occupant_id = this.get('occupant_id');
|
const occupant_id = this.get('occupant_id');
|
||||||
this.occupant = chatbox.occupants.findOccupant({ nick, occupant_id });
|
|
||||||
|
|
||||||
if (!this.occupant && api.settings.get('muc_send_probes')) {
|
this.occupant = this.chatbox.occupants.findOccupant({ nick, occupant_id });
|
||||||
this.occupant = chatbox.occupants.create({ nick, occupant_id, 'type': 'unavailable' });
|
|
||||||
const jid = `${chatbox.get('jid')}/${nick}`;
|
if (!this.occupant) {
|
||||||
|
this.occupant = this.chatbox.occupants.create({
|
||||||
|
nick,
|
||||||
|
occupant_id,
|
||||||
|
jid: this.get('from_real_jid'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (api.settings.get('muc_send_probes')) {
|
||||||
|
const jid = `${this.chatbox.get('jid')}/${nick}`;
|
||||||
api.user.presence.send('probe', jid);
|
api.user.presence.send('probe', jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.occupant) {
|
|
||||||
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
|
|
||||||
} else {
|
|
||||||
this.listenTo(chatbox.occupants, 'add', this.onOccupantAdded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
import debounce from 'lodash-es/debounce';
|
import debounce from 'lodash-es/debounce';
|
||||||
import invoke from 'lodash-es/invoke';
|
|
||||||
import isElement from 'lodash-es/isElement';
|
import isElement from 'lodash-es/isElement';
|
||||||
import log from '../../log';
|
import log from '../../log';
|
||||||
import p from '../../utils/parse-helpers';
|
import p from '../../utils/parse-helpers';
|
||||||
import pick from 'lodash-es/pick';
|
import pick from 'lodash-es/pick';
|
||||||
import sizzle from 'sizzle';
|
import sizzle from 'sizzle';
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
|
import { ROOMSTATUS } from './constants.js';
|
||||||
import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
|
import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
|
||||||
|
import { TimeoutError } from '../../shared/errors.js';
|
||||||
import { _converse, api, converse } from '../../core.js';
|
import { _converse, api, converse } from '../../core.js';
|
||||||
import { computeAffiliationsDelta, setAffiliations, getAffiliationList } from './affiliations/utils.js';
|
import { computeAffiliationsDelta, setAffiliations, getAffiliationList } from './affiliations/utils.js';
|
||||||
import { handleCorrection } from '../../shared/chat/utils.js';
|
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
|
import { handleCorrection } from '../../shared/chat/utils.js';
|
||||||
import { initStorage } from '../../utils/storage.js';
|
import { initStorage } from '../../utils/storage.js';
|
||||||
import { isArchived, getMediaURLsMetadata } from '../../shared/parsers.js';
|
import { isArchived, getMediaURLsMetadata } from '../../shared/parsers.js';
|
||||||
import { isUniView, getUniqueId, safeSave } from '../../utils/core.js';
|
import { isUniView, getUniqueId, safeSave } from '../../utils/core.js';
|
||||||
import { parseMUCMessage, parseMUCPresence } from './parsers.js';
|
import { parseMUCMessage, parseMUCPresence } from './parsers.js';
|
||||||
import { sendMarker } from '../../shared/actions.js';
|
import { sendMarker } from '../../shared/actions.js';
|
||||||
import { ROOMSTATUS } from './constants.js';
|
|
||||||
|
|
||||||
const { u } = converse.env;
|
const { u } = converse.env;
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ const ChatRoomMixin = {
|
|||||||
* *Hook* which allows plugins to update an outgoing MUC join presence stanza
|
* *Hook* which allows plugins to update an outgoing MUC join presence stanza
|
||||||
* @event _converse#constructedMUCPresence
|
* @event _converse#constructedMUCPresence
|
||||||
* @param { _converse.ChatRoom } - The MUC from which this message stanza is being sent.
|
* @param { _converse.ChatRoom } - The MUC from which this message stanza is being sent.
|
||||||
* @param { XMLElement } stanza - The stanza which will be sent out
|
* @param { Element } stanza - The stanza which will be sent out
|
||||||
*/
|
*/
|
||||||
stanza = await api.hook('constructedMUCPresence', this, stanza);
|
stanza = await api.hook('constructedMUCPresence', this, stanza);
|
||||||
return stanza;
|
return stanza;
|
||||||
@ -507,7 +507,7 @@ const ChatRoomMixin = {
|
|||||||
* Handles incoming message stanzas from the service that hosts this MUC
|
* Handles incoming message stanzas from the service that hosts this MUC
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#handleMessageFromMUCHost
|
* @method _converse.ChatRoom#handleMessageFromMUCHost
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
handleMessageFromMUCHost (stanza) {
|
handleMessageFromMUCHost (stanza) {
|
||||||
if (this.isEntered()) {
|
if (this.isEntered()) {
|
||||||
@ -528,7 +528,7 @@ const ChatRoomMixin = {
|
|||||||
* Handles XEP-0452 MUC Mention Notification messages
|
* Handles XEP-0452 MUC Mention Notification messages
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#handleForwardedMentions
|
* @method _converse.ChatRoom#handleForwardedMentions
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
handleForwardedMentions (stanza) {
|
handleForwardedMentions (stanza) {
|
||||||
if (this.isEntered()) {
|
if (this.isEntered()) {
|
||||||
@ -558,7 +558,7 @@ const ChatRoomMixin = {
|
|||||||
* Parses an incoming message stanza and queues it for processing.
|
* Parses an incoming message stanza and queues it for processing.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#handleMessageStanza
|
* @method _converse.ChatRoom#handleMessageStanza
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
async handleMessageStanza (stanza) {
|
async handleMessageStanza (stanza) {
|
||||||
stanza = stanza.tree?.() ?? stanza;
|
stanza = stanza.tree?.() ?? stanza;
|
||||||
@ -709,9 +709,9 @@ const ChatRoomMixin = {
|
|||||||
* or error message within a specific timeout period.
|
* or error message within a specific timeout period.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#sendTimedMessage
|
* @method _converse.ChatRoom#sendTimedMessage
|
||||||
* @param { _converse.Message|XMLElement } message
|
* @param { _converse.Message|Element } message
|
||||||
* @returns { Promise<XMLElement>|Promise<_converse.TimeoutError> } Returns a promise
|
* @returns { Promise<Element>|Promise<TimeoutError> } Returns a promise
|
||||||
* which resolves with the reflected message stanza or with an error stanza or {@link _converse.TimeoutError}.
|
* which resolves with the reflected message stanza or with an error stanza or {@link TimeoutError}.
|
||||||
*/
|
*/
|
||||||
sendTimedMessage (el) {
|
sendTimedMessage (el) {
|
||||||
if (typeof el.tree === 'function') {
|
if (typeof el.tree === 'function') {
|
||||||
@ -724,9 +724,10 @@ const ChatRoomMixin = {
|
|||||||
el.setAttribute('id', id);
|
el.setAttribute('id', id);
|
||||||
}
|
}
|
||||||
const promise = getOpenPromise();
|
const promise = getOpenPromise();
|
||||||
const timeoutHandler = _converse.connection.addTimedHandler(_converse.STANZA_TIMEOUT, () => {
|
const timeout = api.settings.get('stanza_timeout');
|
||||||
|
const timeoutHandler = _converse.connection.addTimedHandler(timeout, () => {
|
||||||
_converse.connection.deleteHandler(handler);
|
_converse.connection.deleteHandler(handler);
|
||||||
const err = new _converse.TimeoutError('Timeout Error: No response from server');
|
const err = new TimeoutError('Timeout Error: No response from server');
|
||||||
promise.resolve(err);
|
promise.resolve(err);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -776,7 +777,7 @@ const ChatRoomMixin = {
|
|||||||
|
|
||||||
if (u.isErrorStanza(result)) {
|
if (u.isErrorStanza(result)) {
|
||||||
log.error(result);
|
log.error(result);
|
||||||
} else if (result instanceof _converse.TimeoutError) {
|
} else if (result instanceof TimeoutError) {
|
||||||
log.error(result);
|
log.error(result);
|
||||||
message.save({
|
message.save({
|
||||||
editable,
|
editable,
|
||||||
@ -793,7 +794,7 @@ const ChatRoomMixin = {
|
|||||||
* Retract someone else's message in this groupchat.
|
* Retract someone else's message in this groupchat.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#retractOtherMessage
|
* @method _converse.ChatRoom#retractOtherMessage
|
||||||
* @param { _converse.Message } message - The message which we're retracting.
|
* @param { _converse.ChatRoomMessage } message - The message which we're retracting.
|
||||||
* @param { string } [reason] - The reason for retracting the message.
|
* @param { string } [reason] - The reason for retracting the message.
|
||||||
* @example
|
* @example
|
||||||
* const room = await api.rooms.get(jid);
|
* const room = await api.rooms.get(jid);
|
||||||
@ -828,7 +829,7 @@ const ChatRoomMixin = {
|
|||||||
* Sends an IQ stanza to the XMPP server to retract a message in this groupchat.
|
* Sends an IQ stanza to the XMPP server to retract a message in this groupchat.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#sendRetractionIQ
|
* @method _converse.ChatRoom#sendRetractionIQ
|
||||||
* @param { _converse.Message } message - The message which we're retracting.
|
* @param { _converse.ChatRoomMessage } message - The message which we're retracting.
|
||||||
* @param { string } [reason] - The reason for retracting the message.
|
* @param { string } [reason] - The reason for retracting the message.
|
||||||
*/
|
*/
|
||||||
sendRetractionIQ (message, reason) {
|
sendRetractionIQ (message, reason) {
|
||||||
@ -1243,7 +1244,7 @@ const ChatRoomMixin = {
|
|||||||
* 'roomconfig' data.
|
* 'roomconfig' data.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#autoConfigureChatRoom
|
* @method _converse.ChatRoom#autoConfigureChatRoom
|
||||||
* @returns { Promise<XMLElement> }
|
* @returns { Promise<Element> }
|
||||||
* Returns a promise which resolves once a response IQ has
|
* Returns a promise which resolves once a response IQ has
|
||||||
* been received.
|
* been received.
|
||||||
*/
|
*/
|
||||||
@ -1262,7 +1263,7 @@ const ChatRoomMixin = {
|
|||||||
* has been received.
|
* has been received.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#fetchRoomConfiguration
|
* @method _converse.ChatRoom#fetchRoomConfiguration
|
||||||
* @returns { Promise<XMLElement> }
|
* @returns { Promise<Element> }
|
||||||
*/
|
*/
|
||||||
fetchRoomConfiguration () {
|
fetchRoomConfiguration () {
|
||||||
return api.sendIQ($iq({ 'to': this.get('jid'), 'type': 'get' }).c('query', { xmlns: Strophe.NS.MUC_OWNER }));
|
return api.sendIQ($iq({ 'to': this.get('jid'), 'type': 'get' }).c('query', { xmlns: Strophe.NS.MUC_OWNER }));
|
||||||
@ -1273,7 +1274,7 @@ const ChatRoomMixin = {
|
|||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#sendConfiguration
|
* @method _converse.ChatRoom#sendConfiguration
|
||||||
* @param { Array } config - The groupchat configuration
|
* @param { Array } config - The groupchat configuration
|
||||||
* @returns { Promise<XMLElement> } - A promise which resolves with
|
* @returns { Promise<Element> } - A promise which resolves with
|
||||||
* the `result` stanza received from the XMPP server.
|
* the `result` stanza received from the XMPP server.
|
||||||
*/
|
*/
|
||||||
sendConfiguration (config = []) {
|
sendConfiguration (config = []) {
|
||||||
@ -1715,7 +1716,7 @@ const ChatRoomMixin = {
|
|||||||
* Given a presence stanza, update the occupant model based on its contents.
|
* Given a presence stanza, update the occupant model based on its contents.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#updateOccupantsOnPresence
|
* @method _converse.ChatRoom#updateOccupantsOnPresence
|
||||||
* @param { XMLElement } pres - The presence stanza
|
* @param { Element } pres - The presence stanza
|
||||||
*/
|
*/
|
||||||
updateOccupantsOnPresence (pres) {
|
updateOccupantsOnPresence (pres) {
|
||||||
const data = parseMUCPresence(pres, this);
|
const data = parseMUCPresence(pres, this);
|
||||||
@ -1902,7 +1903,7 @@ const ChatRoomMixin = {
|
|||||||
* the `from` attribute. Doesn't check the `type` attribute.
|
* the `from` attribute. Doesn't check the `type` attribute.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#isOwnMessage
|
* @method _converse.ChatRoom#isOwnMessage
|
||||||
* @param { Object|XMLElement|_converse.Message } msg
|
* @param { Object|Element|_converse.Message } msg
|
||||||
* @returns { boolean }
|
* @returns { boolean }
|
||||||
*/
|
*/
|
||||||
isOwnMessage (msg) {
|
isOwnMessage (msg) {
|
||||||
@ -2150,7 +2151,7 @@ const ChatRoomMixin = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} actor - The nickname of the actor that caused the notification
|
* @param { String } actor - The nickname of the actor that caused the notification
|
||||||
* @param {String|Array<String>} states - The state or states representing the type of notificcation
|
* @param {String|Array<String>} states - The state or states representing the type of notificcation
|
||||||
*/
|
*/
|
||||||
removeNotification (actor, states) {
|
removeNotification (actor, states) {
|
||||||
@ -2174,8 +2175,8 @@ const ChatRoomMixin = {
|
|||||||
*
|
*
|
||||||
* The state can be a XEP-0085 Chat State or a XEP-0045 join/leave
|
* The state can be a XEP-0085 Chat State or a XEP-0045 join/leave
|
||||||
* state.
|
* state.
|
||||||
* @param {String} actor - The nickname of the actor that causes the notification
|
* @param { String } actor - The nickname of the actor that causes the notification
|
||||||
* @param {String} state - The state representing the type of notificcation
|
* @param { String } state - The state representing the type of notificcation
|
||||||
*/
|
*/
|
||||||
updateNotifications (actor, state) {
|
updateNotifications (actor, state) {
|
||||||
const actors_per_state = this.notifications.toJSON();
|
const actors_per_state = this.notifications.toJSON();
|
||||||
@ -2223,7 +2224,7 @@ const ChatRoomMixin = {
|
|||||||
/**
|
/**
|
||||||
* Given {@link MessageAttributes} look for XEP-0316 Room Notifications and create info
|
* Given {@link MessageAttributes} look for XEP-0316 Room Notifications and create info
|
||||||
* messages for them.
|
* messages for them.
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
handleMEPNotification (attrs) {
|
handleMEPNotification (attrs) {
|
||||||
if (attrs.from !== this.get('jid') || !attrs.activities) {
|
if (attrs.from !== this.get('jid') || !attrs.activities) {
|
||||||
@ -2320,7 +2321,7 @@ const ChatRoomMixin = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a presence stanza that disconnects the user from the MUC
|
* Handle a presence stanza that disconnects the user from the MUC
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
handleDisconnection (stanza) {
|
handleDisconnection (stanza) {
|
||||||
const is_self = stanza.querySelector("status[code='110']") !== null;
|
const is_self = stanza.querySelector("status[code='110']") !== null;
|
||||||
@ -2342,7 +2343,7 @@ const ChatRoomMixin = {
|
|||||||
// each <x/> element pertains to a single user.
|
// each <x/> element pertains to a single user.
|
||||||
const item = x.querySelector('item');
|
const item = x.querySelector('item');
|
||||||
const reason = item ? item.querySelector('reason')?.textContent : undefined;
|
const reason = item ? item.querySelector('reason')?.textContent : undefined;
|
||||||
const actor = item ? invoke(item.querySelector('actor'), 'getAttribute', 'nick') : undefined;
|
const actor = item ? item.querySelector('actor')?.getAttribute('nick') : undefined;
|
||||||
const message = _converse.muc.disconnect_messages[codes[0]];
|
const message = _converse.muc.disconnect_messages[codes[0]];
|
||||||
const status = codes.includes('301') ? ROOMSTATUS.BANNED : ROOMSTATUS.DISCONNECTED;
|
const status = codes.includes('301') ? ROOMSTATUS.BANNED : ROOMSTATUS.DISCONNECTED;
|
||||||
this.setDisconnectionState(message, reason, actor, status);
|
this.setDisconnectionState(message, reason, actor, status);
|
||||||
@ -2455,7 +2456,7 @@ const ChatRoomMixin = {
|
|||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#createInfoMessage
|
* @method _converse.ChatRoom#createInfoMessage
|
||||||
* @param { string } code - The MUC status code
|
* @param { string } code - The MUC status code
|
||||||
* @param { XMLElement } stanza - The original stanza that contains the code
|
* @param { Element } stanza - The original stanza that contains the code
|
||||||
* @param { Boolean } is_self - Whether this stanza refers to our own presence
|
* @param { Boolean } is_self - Whether this stanza refers to our own presence
|
||||||
*/
|
*/
|
||||||
createInfoMessage (code, stanza, is_self) {
|
createInfoMessage (code, stanza, is_self) {
|
||||||
@ -2498,7 +2499,7 @@ const ChatRoomMixin = {
|
|||||||
* Create info messages based on a received presence or message stanza
|
* Create info messages based on a received presence or message stanza
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#createInfoMessages
|
* @method _converse.ChatRoom#createInfoMessages
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
createInfoMessages (stanza) {
|
createInfoMessages (stanza) {
|
||||||
const codes = sizzle(`x[xmlns="${Strophe.NS.MUC_USER}"] status`, stanza).map(s => s.getAttribute('code'));
|
const codes = sizzle(`x[xmlns="${Strophe.NS.MUC_USER}"] status`, stanza).map(s => s.getAttribute('code'));
|
||||||
@ -2517,7 +2518,7 @@ const ChatRoomMixin = {
|
|||||||
* implied by) the server.
|
* implied by) the server.
|
||||||
* @param { String } reason - The reason provided for the disconnection
|
* @param { String } reason - The reason provided for the disconnection
|
||||||
* @param { String } actor - The person (if any) responsible for this disconnection
|
* @param { String } actor - The person (if any) responsible for this disconnection
|
||||||
* @param { Integer } status - The status code (see `ROOMSTATUS`)
|
* @param { number } status - The status code (see `ROOMSTATUS`)
|
||||||
*/
|
*/
|
||||||
setDisconnectionState (message, reason, actor, status=ROOMSTATUS.DISCONNECTED) {
|
setDisconnectionState (message, reason, actor, status=ROOMSTATUS.DISCONNECTED) {
|
||||||
this.session.save({
|
this.session.save({
|
||||||
@ -2554,7 +2555,7 @@ const ChatRoomMixin = {
|
|||||||
* `connection_status` value for this {@link _converse.ChatRoom} as
|
* `connection_status` value for this {@link _converse.ChatRoom} as
|
||||||
* well as any additional output that can be shown to the user.
|
* well as any additional output that can be shown to the user.
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The presence stanza
|
* @param { Element } stanza - The presence stanza
|
||||||
*/
|
*/
|
||||||
onErrorPresence (stanza) {
|
onErrorPresence (stanza) {
|
||||||
const __ = _converse.__;
|
const __ = _converse.__;
|
||||||
@ -2619,7 +2620,7 @@ const ChatRoomMixin = {
|
|||||||
* Listens for incoming presence stanzas from the service that hosts this MUC
|
* Listens for incoming presence stanzas from the service that hosts this MUC
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#onPresenceFromMUCHost
|
* @method _converse.ChatRoom#onPresenceFromMUCHost
|
||||||
* @param { XMLElement } stanza - The presence stanza
|
* @param { Element } stanza - The presence stanza
|
||||||
*/
|
*/
|
||||||
onPresenceFromMUCHost (stanza) {
|
onPresenceFromMUCHost (stanza) {
|
||||||
if (stanza.getAttribute('type') === 'error') {
|
if (stanza.getAttribute('type') === 'error') {
|
||||||
@ -2638,7 +2639,7 @@ const ChatRoomMixin = {
|
|||||||
* Handles incoming presence stanzas coming from the MUC
|
* Handles incoming presence stanzas coming from the MUC
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#onPresence
|
* @method _converse.ChatRoom#onPresence
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
onPresence (stanza) {
|
onPresence (stanza) {
|
||||||
if (stanza.getAttribute('type') === 'error') {
|
if (stanza.getAttribute('type') === 'error') {
|
||||||
@ -2671,7 +2672,7 @@ const ChatRoomMixin = {
|
|||||||
* user is the groupchat's owner.
|
* user is the groupchat's owner.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#onOwnPresence
|
* @method _converse.ChatRoom#onOwnPresence
|
||||||
* @param { XMLElement } pres - The stanza
|
* @param { Element } pres - The stanza
|
||||||
*/
|
*/
|
||||||
async onOwnPresence (stanza) {
|
async onOwnPresence (stanza) {
|
||||||
await this.occupants.fetched;
|
await this.occupants.fetched;
|
||||||
|
@ -10,9 +10,9 @@ class ChatRoomOccupant extends Model {
|
|||||||
|
|
||||||
defaults () { // eslint-disable-line class-methods-use-this
|
defaults () { // eslint-disable-line class-methods-use-this
|
||||||
return {
|
return {
|
||||||
'hats': [],
|
hats: [],
|
||||||
'show': 'offline',
|
show: 'offline',
|
||||||
'states': []
|
states: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ const { NS } = Strophe;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a message stanza for XEP-0317 MEP notification data
|
* Parses a message stanza for XEP-0317 MEP notification data
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @returns { Array } Returns an array of objects representing <activity> elements.
|
* @returns { Array } Returns an array of objects representing <activity> elements.
|
||||||
*/
|
*/
|
||||||
export function getMEPActivities (stanza) {
|
export function getMEPActivities (stanza) {
|
||||||
@ -61,7 +61,7 @@ export function getMEPActivities (stanza) {
|
|||||||
* Note, this function doesn't check whether this is actually a MAM archived stanza.
|
* Note, this function doesn't check whether this is actually a MAM archived stanza.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @returns { Object }
|
* @returns { Object }
|
||||||
*/
|
*/
|
||||||
function getJIDFromMUCUserData (stanza) {
|
function getJIDFromMUCUserData (stanza) {
|
||||||
@ -71,8 +71,8 @@ function getJIDFromMUCUserData (stanza) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @param { XMLElement } original_stanza - The original stanza, that contains the
|
* @param { Element } original_stanza - The original stanza, that contains the
|
||||||
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
||||||
* @returns { Object }
|
* @returns { Object }
|
||||||
*/
|
*/
|
||||||
@ -140,8 +140,8 @@ function getSender (attrs, chatbox) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a passed in message stanza and returns an object of attributes.
|
* Parses a passed in message stanza and returns an object of attributes.
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @param { XMLElement } original_stanza - The original stanza, that contains the
|
* @param { Element } original_stanza - The original stanza, that contains the
|
||||||
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
||||||
* @param { _converse.ChatRoom } chatbox
|
* @param { _converse.ChatRoom } chatbox
|
||||||
* @param { _converse } _converse
|
* @param { _converse } _converse
|
||||||
@ -342,7 +342,7 @@ export function parseMemberListIQ (iq) {
|
|||||||
/**
|
/**
|
||||||
* Parses a passed in MUC presence stanza and returns an object of attributes.
|
* Parses a passed in MUC presence stanza and returns an object of attributes.
|
||||||
* @method parseMUCPresence
|
* @method parseMUCPresence
|
||||||
* @param { XMLElement } stanza - The presence stanza
|
* @param { Element } stanza - The presence stanza
|
||||||
* @param { _converse.ChatRoom } chatbox
|
* @param { _converse.ChatRoom } chatbox
|
||||||
* @returns { MUCPresenceAttributes }
|
* @returns { MUCPresenceAttributes }
|
||||||
*/
|
*/
|
||||||
|
@ -83,7 +83,14 @@ describe("A MUC occupant", function () {
|
|||||||
await u.waitUntil(() => model.messages.length);
|
await u.waitUntil(() => model.messages.length);
|
||||||
let message = model.messages.at(0);
|
let message = model.messages.at(0);
|
||||||
expect(message.get('occupant_id')).toBe("dd72603deec90a38ba552f7c68cbcc61bca202cd");
|
expect(message.get('occupant_id')).toBe("dd72603deec90a38ba552f7c68cbcc61bca202cd");
|
||||||
expect(message.occupant).toBeUndefined();
|
expect(message.occupant).not.toBeUndefined();
|
||||||
|
|
||||||
|
let occupant = message.occupant;
|
||||||
|
expect(occupant.getDisplayName()).toBe('3rdwitch');
|
||||||
|
expect(occupant.get('nick')).toBe('3rdwitch');
|
||||||
|
expect(occupant.get('jid')).toBe(undefined);
|
||||||
|
expect(occupant.get('occupant_id')).toBe("dd72603deec90a38ba552f7c68cbcc61bca202cd");
|
||||||
|
|
||||||
expect(message.getDisplayName()).toBe('3rdwitch');
|
expect(message.getDisplayName()).toBe('3rdwitch');
|
||||||
|
|
||||||
const presence = u.toStanza(`
|
const presence = u.toStanza(`
|
||||||
@ -98,7 +105,7 @@ describe("A MUC occupant", function () {
|
|||||||
</presence>`);
|
</presence>`);
|
||||||
_converse.connection._dataRecv(mock.createRequest(presence));
|
_converse.connection._dataRecv(mock.createRequest(presence));
|
||||||
|
|
||||||
const occupant = await u.waitUntil(() => model.getOccupantByNickname('thirdwitch'));
|
occupant = await u.waitUntil(() => model.getOccupantByNickname('thirdwitch'));
|
||||||
expect(occupant.get('occupant_id')).toBe('dd72603deec90a38ba552f7c68cbcc61bca202cd');
|
expect(occupant.get('occupant_id')).toBe('dd72603deec90a38ba552f7c68cbcc61bca202cd');
|
||||||
expect(model.occupants.findWhere({'occupant_id': "dd72603deec90a38ba552f7c68cbcc61bca202cd"})).toBe(occupant);
|
expect(model.occupants.findWhere({'occupant_id': "dd72603deec90a38ba552f7c68cbcc61bca202cd"})).toBe(occupant);
|
||||||
|
|
||||||
|
@ -85,10 +85,9 @@ export async function openChatRoom (jid, settings) {
|
|||||||
* See XEP-0249: Direct MUC invitations.
|
* See XEP-0249: Direct MUC invitations.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.ChatRoom#onDirectMUCInvitation
|
* @method _converse.ChatRoom#onDirectMUCInvitation
|
||||||
* @param { XMLElement } message - The message stanza containing the invitation.
|
* @param { Element } message - The message stanza containing the invitation.
|
||||||
*/
|
*/
|
||||||
export async function onDirectMUCInvitation (message) {
|
export async function onDirectMUCInvitation (message) {
|
||||||
const { __ } = _converse;
|
|
||||||
const x_el = sizzle('x[xmlns="jabber:x:conference"]', message).pop(),
|
const x_el = sizzle('x[xmlns="jabber:x:conference"]', message).pop(),
|
||||||
from = Strophe.getBareJidFromJid(message.getAttribute('from')),
|
from = Strophe.getBareJidFromJid(message.getAttribute('from')),
|
||||||
room_jid = x_el.getAttribute('jid'),
|
room_jid = x_el.getAttribute('jid'),
|
||||||
@ -99,21 +98,20 @@ export async function onDirectMUCInvitation (message) {
|
|||||||
result = true;
|
result = true;
|
||||||
} else {
|
} else {
|
||||||
// Invite request might come from someone not your roster list
|
// Invite request might come from someone not your roster list
|
||||||
let contact = _converse.roster.get(from);
|
const contact = _converse.roster.get(from)?.getDisplayName() ?? from;
|
||||||
contact = contact ? contact.getDisplayName() : from;
|
|
||||||
if (!reason) {
|
/**
|
||||||
result = await api.confirm(__('%1$s has invited you to join a groupchat: %2$s', contact, room_jid));
|
* *Hook* which is used to gather confirmation whether a direct MUC
|
||||||
} else {
|
* invitation should be accepted or not.
|
||||||
result = await api.confirm(
|
*
|
||||||
__(
|
* It's meant for consumers of `@converse/headless` to subscribe to
|
||||||
'%1$s has invited you to join a groupchat: %2$s, and left the following reason: "%3$s"',
|
* this hook and then ask the user to confirm.
|
||||||
contact,
|
*
|
||||||
room_jid,
|
* @event _converse#confirmDirectMUCInvitation
|
||||||
reason
|
*/
|
||||||
)
|
result = await api.hook('confirmDirectMUCInvitation', { contact, reason, jid: room_jid }, false);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const chatroom = await openChatRoom(room_jid, { 'password': x_el.getAttribute('password') });
|
const chatroom = await openChatRoom(room_jid, { 'password': x_el.getAttribute('password') });
|
||||||
if (chatroom.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED) {
|
if (chatroom.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED) {
|
||||||
|
@ -10,7 +10,7 @@ export default {
|
|||||||
* @method api.ping
|
* @method api.ping
|
||||||
* @param { String } [jid] - The JID of the service to ping
|
* @param { String } [jid] - The JID of the service to ping
|
||||||
* If the ping is sent out to the user's bare JID and no response is received it will attempt to reconnect.
|
* If the ping is sent out to the user's bare JID and no response is received it will attempt to reconnect.
|
||||||
* @param { Integer } [timeout] - The amount of time in
|
* @param { number } [timeout] - The amount of time in
|
||||||
* milliseconds to wait for a response. The default is 10000;
|
* milliseconds to wait for a response. The default is 10000;
|
||||||
* @returns { Boolean | null }
|
* @returns { Boolean | null }
|
||||||
* Whether the pinged entity responded with a non-error IQ stanza.
|
* Whether the pinged entity responded with a non-error IQ stanza.
|
||||||
|
@ -32,12 +32,12 @@ converse.plugins.add('converse-pubsub', {
|
|||||||
* Publshes an item to a PubSub node
|
* Publshes an item to a PubSub node
|
||||||
*
|
*
|
||||||
* @method _converse.api.pubsub.publish
|
* @method _converse.api.pubsub.publish
|
||||||
* @param {string} jid The JID of the pubsub service where the node resides.
|
* @param { string } jid The JID of the pubsub service where the node resides.
|
||||||
* @param {string} node The node being published to
|
* @param { string } node The node being published to
|
||||||
* @param {Strophe.Builder} item The Strophe.Builder representation of the XML element being published
|
* @param {Strophe.Builder} item The Strophe.Builder representation of the XML element being published
|
||||||
* @param {object} options An object representing the publisher options
|
* @param { object } options An object representing the publisher options
|
||||||
* (see https://xmpp.org/extensions/xep-0060.html#publisher-publish-options)
|
* (see https://xmpp.org/extensions/xep-0060.html#publisher-publish-options)
|
||||||
* @param {boolean} strict_options Indicates whether the publisher
|
* @param { boolean } strict_options Indicates whether the publisher
|
||||||
* options are a strict requirement or not. If they're NOT
|
* options are a strict requirement or not. If they're NOT
|
||||||
* strict, then Converse will publish to the node even if
|
* strict, then Converse will publish to the node even if
|
||||||
* the publish options precondication cannot be met.
|
* the publish options precondication cannot be met.
|
||||||
|
@ -55,8 +55,8 @@ export default {
|
|||||||
* Add a contact.
|
* Add a contact.
|
||||||
*
|
*
|
||||||
* @method _converse.api.contacts.add
|
* @method _converse.api.contacts.add
|
||||||
* @param {string} jid The JID of the contact to be added
|
* @param { string } jid The JID of the contact to be added
|
||||||
* @param {string} [name] A custom name to show the user by in the roster
|
* @param { string } [name] A custom name to show the user by in the roster
|
||||||
* @example
|
* @example
|
||||||
* _converse.api.contacts.add('buddy@example.com')
|
* _converse.api.contacts.add('buddy@example.com')
|
||||||
* @example
|
* @example
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import '@converse/headless/plugins/status/api.js';
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { _converse, api, converse } from "@converse/headless/core";
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
@ -93,21 +94,12 @@ const RosterContact = Model.extend({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a presence subscription request to this roster contact
|
* Send a presence subscription request to this roster contact
|
||||||
* @private
|
|
||||||
* @method _converse.RosterContacts#subscribe
|
* @method _converse.RosterContacts#subscribe
|
||||||
* @param { String } message - An optional message to explain the
|
* @param { String } message - An optional message to explain the
|
||||||
* reason for the subscription request.
|
* reason for the subscription request.
|
||||||
*/
|
*/
|
||||||
subscribe (message) {
|
subscribe (message) {
|
||||||
const pres = $pres({to: this.get('jid'), type: "subscribe"});
|
api.user.presence.send('subscribe', this.get('jid'), message);
|
||||||
if (message && message !== "") {
|
|
||||||
pres.c("status").t(message).up();
|
|
||||||
}
|
|
||||||
const nick = _converse.xmppstatus.getNickname() || _converse.xmppstatus.getFullname();
|
|
||||||
if (nick) {
|
|
||||||
pres.c('nick', {'xmlns': Strophe.NS.NICK}).t(nick).up();
|
|
||||||
}
|
|
||||||
api.send(pres);
|
|
||||||
this.save('ask', "subscribe"); // ask === 'subscribe' Means we have asked to subscribe to them.
|
this.save('ask', "subscribe"); // ask === 'subscribe' Means we have asked to subscribe to them.
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
@ -135,7 +127,6 @@ const RosterContact = Model.extend({
|
|||||||
* send notification of the subscription state change to the user.
|
* send notification of the subscription state change to the user.
|
||||||
* @private
|
* @private
|
||||||
* @method _converse.RosterContacts#ackUnsubscribe
|
* @method _converse.RosterContacts#ackUnsubscribe
|
||||||
* @param { String } jid - The Jabber ID of the user who is unsubscribing
|
|
||||||
*/
|
*/
|
||||||
ackUnsubscribe () {
|
ackUnsubscribe () {
|
||||||
api.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
|
api.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
|
||||||
|
@ -112,7 +112,7 @@ const RosterContacts = Collection.extend({
|
|||||||
* @method _converse.RosterContacts#addAndSubscribe
|
* @method _converse.RosterContacts#addAndSubscribe
|
||||||
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
||||||
* @param { String } name - The name of that user
|
* @param { String } name - The name of that user
|
||||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
* @param { Array<String> } groups - Any roster groups the user might belong to
|
||||||
* @param { String } message - An optional message to explain the reason for the subscription request.
|
* @param { String } message - An optional message to explain the reason for the subscription request.
|
||||||
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
||||||
*/
|
*/
|
||||||
@ -128,9 +128,7 @@ const RosterContacts = Collection.extend({
|
|||||||
* @method _converse.RosterContacts#sendContactAddIQ
|
* @method _converse.RosterContacts#sendContactAddIQ
|
||||||
* @param { String } jid - The Jabber ID of the user being added
|
* @param { String } jid - The Jabber ID of the user being added
|
||||||
* @param { String } name - The name of that user
|
* @param { String } name - The name of that user
|
||||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
* @param { Array<String> } groups - Any roster groups the user might belong to
|
||||||
* @param { Function } callback - A function to call once the IQ is returned
|
|
||||||
* @param { Function } errback - A function to call if an error occurred
|
|
||||||
*/
|
*/
|
||||||
sendContactAddIQ (jid, name, groups) {
|
sendContactAddIQ (jid, name, groups) {
|
||||||
name = name ? name : null;
|
name = name ? name : null;
|
||||||
@ -148,7 +146,7 @@ const RosterContacts = Collection.extend({
|
|||||||
* @method _converse.RosterContacts#addContactToRoster
|
* @method _converse.RosterContacts#addContactToRoster
|
||||||
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
||||||
* @param { String } name - The name of that user
|
* @param { String } name - The name of that user
|
||||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
* @param { Array<String> } groups - Any roster groups the user might belong to
|
||||||
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
||||||
*/
|
*/
|
||||||
async addContactToRoster (jid, name, groups, attributes) {
|
async addContactToRoster (jid, name, groups, attributes) {
|
||||||
@ -190,7 +188,7 @@ const RosterContacts = Collection.extend({
|
|||||||
* Handle roster updates from the XMPP server.
|
* Handle roster updates from the XMPP server.
|
||||||
* See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
* See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
||||||
* @method _converse.RosterContacts#onRosterPush
|
* @method _converse.RosterContacts#onRosterPush
|
||||||
* @param { XMLElement } IQ - The IQ stanza received from the XMPP server.
|
* @param { Element } iq - The IQ stanza received from the XMPP server.
|
||||||
*/
|
*/
|
||||||
onRosterPush (iq) {
|
onRosterPush (iq) {
|
||||||
const id = iq.getAttribute('id');
|
const id = iq.getAttribute('id');
|
||||||
@ -226,7 +224,7 @@ const RosterContacts = Collection.extend({
|
|||||||
/**
|
/**
|
||||||
* When the roster receives a push event from server (i.e. new entry in your contacts roster).
|
* When the roster receives a push event from server (i.e. new entry in your contacts roster).
|
||||||
* @event _converse#rosterPush
|
* @event _converse#rosterPush
|
||||||
* @type { XMLElement }
|
* @type { Element }
|
||||||
* @example _converse.api.listen.on('rosterPush', iq => { ... });
|
* @example _converse.api.listen.on('rosterPush', iq => { ... });
|
||||||
*/
|
*/
|
||||||
api.trigger('rosterPush', iq);
|
api.trigger('rosterPush', iq);
|
||||||
@ -279,7 +277,7 @@ const RosterContacts = Collection.extend({
|
|||||||
* See also the `cachedRoster` event further up, which gets called instead of
|
* See also the `cachedRoster` event further up, which gets called instead of
|
||||||
* `roster` if its already in `sessionStorage`.
|
* `roster` if its already in `sessionStorage`.
|
||||||
* @event _converse#roster
|
* @event _converse#roster
|
||||||
* @type { XMLElement }
|
* @type { Element }
|
||||||
* @example _converse.api.listen.on('roster', iq => { ... });
|
* @example _converse.api.listen.on('roster', iq => { ... });
|
||||||
* @example _converse.api.waitUntil('roster').then(iq => { ... });
|
* @example _converse.api.waitUntil('roster').then(iq => { ... });
|
||||||
*/
|
*/
|
||||||
@ -289,7 +287,7 @@ const RosterContacts = Collection.extend({
|
|||||||
/**
|
/**
|
||||||
* Update or create RosterContact models based on the given `item` XML
|
* Update or create RosterContact models based on the given `item` XML
|
||||||
* node received in the resulting IQ stanza from the server.
|
* node received in the resulting IQ stanza from the server.
|
||||||
* @param { XMLElement } item
|
* @param { Element } item
|
||||||
*/
|
*/
|
||||||
updateContact (item) {
|
updateContact (item) {
|
||||||
const jid = item.getAttribute('jid');
|
const jid = item.getAttribute('jid');
|
||||||
@ -379,9 +377,7 @@ const RosterContacts = Collection.extend({
|
|||||||
_converse.xmppstatus.save({'status': show}, {'silent': true});
|
_converse.xmppstatus.save({'status': show}, {'silent': true});
|
||||||
|
|
||||||
const status_message = presence.querySelector('status')?.textContent;
|
const status_message = presence.querySelector('status')?.textContent;
|
||||||
if (status_message) {
|
if (status_message) _converse.xmppstatus.save({ status_message });
|
||||||
_converse.xmppstatus.save({'status_message': status_message});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (_converse.jid === jid && presence_type === 'unavailable') {
|
if (_converse.jid === jid && presence_type === 'unavailable') {
|
||||||
// XXX: We've received an "unavailable" presence from our
|
// XXX: We've received an "unavailable" presence from our
|
||||||
@ -414,11 +410,11 @@ const RosterContacts = Collection.extend({
|
|||||||
return; // Ignore MUC
|
return; // Ignore MUC
|
||||||
}
|
}
|
||||||
|
|
||||||
const status_message = presence.querySelector('status')?.textContent;
|
|
||||||
const contact = this.get(bare_jid);
|
const contact = this.get(bare_jid);
|
||||||
|
|
||||||
if (contact && (status_message !== contact.get('status'))) {
|
if (contact) {
|
||||||
contact.save({'status': status_message});
|
const status = presence.querySelector('status')?.textContent;
|
||||||
|
if (contact.get('status') !== status) contact.save({status});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (presence_type === 'subscribed' && contact) {
|
if (presence_type === 'subscribed' && contact) {
|
||||||
|
@ -30,7 +30,7 @@ export const Presence = Model.extend({
|
|||||||
const hpr = this.getHighestPriorityResource();
|
const hpr = this.getHighestPriorityResource();
|
||||||
const show = hpr?.attributes?.show || 'offline';
|
const show = hpr?.attributes?.show || 'offline';
|
||||||
if (this.get('show') !== show) {
|
if (this.get('show') !== show) {
|
||||||
this.save({'show': show});
|
this.save({ show });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -48,16 +48,16 @@ export const Presence = Model.extend({
|
|||||||
* from the passed in presence stanza.
|
* from the passed in presence stanza.
|
||||||
* Also updates the presence if the resource has higher priority (and is newer).
|
* Also updates the presence if the resource has higher priority (and is newer).
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } presence: The presence stanza
|
* @param { Element } presence: The presence stanza
|
||||||
*/
|
*/
|
||||||
addResource (presence) {
|
addResource (presence) {
|
||||||
const jid = presence.getAttribute('from'),
|
const jid = presence.getAttribute('from');
|
||||||
name = Strophe.getResourceFromJid(jid),
|
const name = Strophe.getResourceFromJid(jid);
|
||||||
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop(),
|
const delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, presence).pop();
|
||||||
priority = presence.querySelector('priority')?.textContent ?? 0,
|
const priority = presence.querySelector('priority')?.textContent;
|
||||||
resource = this.resources.get(name),
|
const resource = this.resources.get(name);
|
||||||
settings = {
|
const settings = {
|
||||||
'name': name,
|
name,
|
||||||
'priority': isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
|
'priority': isNaN(parseInt(priority, 10)) ? 0 : parseInt(priority, 10),
|
||||||
'show': presence.querySelector('show')?.textContent ?? 'online',
|
'show': presence.querySelector('show')?.textContent ?? 'online',
|
||||||
'timestamp': delay ? dayjs(delay.getAttribute('stamp')).toISOString() : (new Date()).toISOString()
|
'timestamp': delay ? dayjs(delay.getAttribute('stamp')).toISOString() : (new Date()).toISOString()
|
||||||
@ -78,9 +78,7 @@ export const Presence = Model.extend({
|
|||||||
*/
|
*/
|
||||||
removeResource (name) {
|
removeResource (name) {
|
||||||
const resource = this.resources.get(name);
|
const resource = this.resources.get(name);
|
||||||
if (resource) {
|
resource?.destroy();
|
||||||
resource.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import log from "@converse/headless/log";
|
import log from "@converse/headless/log";
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { RosterFilter } from '@converse/headless/plugins/roster/filter.js';
|
import { RosterFilter } from '@converse/headless/plugins/roster/filter.js';
|
||||||
|
import { STATUS_WEIGHTS } from "../../shared/constants";
|
||||||
import { _converse, api, converse } from "@converse/headless/core";
|
import { _converse, api, converse } from "@converse/headless/core";
|
||||||
import { initStorage } from '@converse/headless/utils/storage.js';
|
import { initStorage } from '@converse/headless/utils/storage.js';
|
||||||
|
import { shouldClearCache } from '@converse/headless/utils/core.js';
|
||||||
|
|
||||||
const { $pres } = converse.env;
|
const { $pres } = converse.env;
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ async function clearPresences () {
|
|||||||
*/
|
*/
|
||||||
export async function onClearSession () {
|
export async function onClearSession () {
|
||||||
await clearPresences();
|
await clearPresences();
|
||||||
if (_converse.shouldClearCache()) {
|
if (shouldClearCache()) {
|
||||||
if (_converse.rostergroups) {
|
if (_converse.rostergroups) {
|
||||||
await _converse.rostergroups.clearStore();
|
await _converse.rostergroups.clearStore();
|
||||||
delete _converse.rostergroups;
|
delete _converse.rostergroups;
|
||||||
@ -197,12 +199,12 @@ export function rejectPresenceSubscription (jid, message) {
|
|||||||
export function contactsComparator (contact1, contact2) {
|
export function contactsComparator (contact1, contact2) {
|
||||||
const status1 = contact1.presence.get('show') || 'offline';
|
const status1 = contact1.presence.get('show') || 'offline';
|
||||||
const status2 = contact2.presence.get('show') || 'offline';
|
const status2 = contact2.presence.get('show') || 'offline';
|
||||||
if (_converse.STATUS_WEIGHTS[status1] === _converse.STATUS_WEIGHTS[status2]) {
|
if (STATUS_WEIGHTS[status1] === STATUS_WEIGHTS[status2]) {
|
||||||
const name1 = (contact1.getDisplayName()).toLowerCase();
|
const name1 = (contact1.getDisplayName()).toLowerCase();
|
||||||
const name2 = (contact2.getDisplayName()).toLowerCase();
|
const name2 = (contact2.getDisplayName()).toLowerCase();
|
||||||
return name1 < name2 ? -1 : (name1 > name2? 1 : 0);
|
return name1 < name2 ? -1 : (name1 > name2? 1 : 0);
|
||||||
} else {
|
} else {
|
||||||
return _converse.STATUS_WEIGHTS[status1] < _converse.STATUS_WEIGHTS[status2] ? -1 : 1;
|
return STATUS_WEIGHTS[status1] < STATUS_WEIGHTS[status2] ? -1 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,38 +1,8 @@
|
|||||||
import { _converse, api } from '@converse/headless/core';
|
import { _converse, api } from '../../core';
|
||||||
|
import { STATUS_WEIGHTS } from '../../shared/constants';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
|
||||||
* @namespace _converse.api.user.presence
|
|
||||||
* @memberOf _converse.api.user
|
|
||||||
*/
|
|
||||||
presence: {
|
|
||||||
/**
|
|
||||||
* Send out a presence stanza
|
|
||||||
* @method _converse.api.user.presence.send
|
|
||||||
* @param { String } type
|
|
||||||
* @param { String } to
|
|
||||||
* @param { String } [status] - An optional status message
|
|
||||||
* @param { Element[]|Strophe.Builder[]|Element|Strophe.Builder } [child_nodes]
|
|
||||||
* Nodes(s) to be added as child nodes of the `presence` XML element.
|
|
||||||
*/
|
|
||||||
async send (type, to, status, child_nodes) {
|
|
||||||
await api.waitUntil('statusInitialized');
|
|
||||||
if (child_nodes && !Array.isArray(child_nodes)) {
|
|
||||||
child_nodes = [child_nodes];
|
|
||||||
}
|
|
||||||
const model = _converse.xmppstatus
|
|
||||||
const presence = await model.constructPresence(type, to, status);
|
|
||||||
child_nodes?.map(c => c?.tree() ?? c).forEach(c => presence.cnode(c).up());
|
|
||||||
api.send(presence);
|
|
||||||
|
|
||||||
if (['away', 'chat', 'dnd', 'online', 'xa', undefined].includes(type)) {
|
|
||||||
const mucs = await api.rooms.get();
|
|
||||||
mucs.forEach(muc => muc.sendStatusPresence(type, status, child_nodes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set and get the user's chat status, also called their *availability*.
|
* Set and get the user's chat status, also called their *availability*.
|
||||||
* @namespace _converse.api.user.status
|
* @namespace _converse.api.user.status
|
||||||
@ -55,15 +25,15 @@ export default {
|
|||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @method _converse.api.user.status.set
|
* @method _converse.api.user.status.set
|
||||||
* @param {string} value The user's chat status (e.g. 'away', 'dnd', 'offline', 'online', 'unavailable' or 'xa')
|
* @param { string } value The user's chat status (e.g. 'away', 'dnd', 'offline', 'online', 'unavailable' or 'xa')
|
||||||
* @param {string} [message] A custom status message
|
* @param { string } [message] A custom status message
|
||||||
*
|
*
|
||||||
* @example _converse.api.user.status.set('dnd');
|
* @example _converse.api.user.status.set('dnd');
|
||||||
* @example _converse.api.user.status.set('dnd', 'In a meeting');
|
* @example _converse.api.user.status.set('dnd', 'In a meeting');
|
||||||
*/
|
*/
|
||||||
async set (value, message) {
|
async set (value, message) {
|
||||||
const data = {'status': value};
|
const data = {'status': value};
|
||||||
if (!Object.keys(_converse.STATUS_WEIGHTS).includes(value)) {
|
if (!Object.keys(STATUS_WEIGHTS).includes(value)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1'
|
'Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1'
|
||||||
);
|
);
|
||||||
@ -85,7 +55,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* @async
|
* @async
|
||||||
* @method _converse.api.user.status.message.get
|
* @method _converse.api.user.status.message.get
|
||||||
* @returns {string} The status message
|
* @returns { Promise<string> } The status message
|
||||||
* @example const message = _converse.api.user.status.message.get()
|
* @example const message = _converse.api.user.status.message.get()
|
||||||
*/
|
*/
|
||||||
async get () {
|
async get () {
|
||||||
@ -95,7 +65,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* @async
|
* @async
|
||||||
* @method _converse.api.user.status.message.set
|
* @method _converse.api.user.status.message.set
|
||||||
* @param {string} status The status message
|
* @param { string } status The status message
|
||||||
* @example _converse.api.user.status.message.set('In a meeting');
|
* @example _converse.api.user.status.message.set('In a meeting');
|
||||||
*/
|
*/
|
||||||
async set (status) {
|
async set (status) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import XMPPStatus from './status.js';
|
import XMPPStatus from './status.js';
|
||||||
import status_api from './api.js';
|
import status_api from './api.js';
|
||||||
import { _converse, api, converse } from '@converse/headless/core';
|
import { _converse, api, converse } from '@converse/headless/core';
|
||||||
|
import { shouldClearCache } from '@converse/headless/utils/core.js';
|
||||||
import {
|
import {
|
||||||
addStatusToMUCJoinPresence,
|
addStatusToMUCJoinPresence,
|
||||||
initStatus,
|
initStatus,
|
||||||
@ -52,7 +53,7 @@ converse.plugins.add('converse-status', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
api.listen.on('clearSession', () => {
|
api.listen.on('clearSession', () => {
|
||||||
if (_converse.shouldClearCache() && _converse.xmppstatus) {
|
if (shouldClearCache() && _converse.xmppstatus) {
|
||||||
_converse.xmppstatus.destroy();
|
_converse.xmppstatus.destroy();
|
||||||
delete _converse.xmppstatus;
|
delete _converse.xmppstatus;
|
||||||
api.promises.add(['statusInitialized']);
|
api.promises.add(['statusInitialized']);
|
||||||
|
@ -5,10 +5,11 @@ import { _converse, api, converse } from '@converse/headless/core';
|
|||||||
|
|
||||||
const { Strophe, $pres } = converse.env;
|
const { Strophe, $pres } = converse.env;
|
||||||
|
|
||||||
const XMPPStatus = Model.extend({
|
export default class XMPPStatus extends Model {
|
||||||
defaults () {
|
|
||||||
|
defaults () { // eslint-disable-line class-methods-use-this
|
||||||
return { "status": api.settings.get("default_state") }
|
return { "status": api.settings.get("default_state") }
|
||||||
},
|
}
|
||||||
|
|
||||||
initialize () {
|
initialize () {
|
||||||
this.on('change', item => {
|
this.on('change', item => {
|
||||||
@ -19,54 +20,72 @@ const XMPPStatus = Model.extend({
|
|||||||
api.user.presence.send(this.get('status'), null, this.get('status_message'));
|
api.user.presence.send(this.get('status'), null, this.get('status_message'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
getNickname () {
|
getDisplayName () {
|
||||||
|
return this.getFullname() || this.getNickname() || _converse.bare_jid;
|
||||||
|
}
|
||||||
|
|
||||||
|
getNickname () { // eslint-disable-line class-methods-use-this
|
||||||
return api.settings.get('nickname');
|
return api.settings.get('nickname');
|
||||||
},
|
}
|
||||||
|
|
||||||
getFullname () {
|
getFullname () { // eslint-disable-line class-methods-use-this
|
||||||
// Gets overridden in converse-vcard
|
return ''; // Gets overridden in converse-vcard
|
||||||
return '';
|
}
|
||||||
},
|
|
||||||
|
|
||||||
|
/** Constructs a presence stanza
|
||||||
|
* @param { string } [type]
|
||||||
|
* @param { string } [to] - The JID to which this presence should be sent
|
||||||
|
* @param { string } [status_message]
|
||||||
|
*/
|
||||||
async constructPresence (type, to=null, status_message) {
|
async constructPresence (type, to=null, status_message) {
|
||||||
type = typeof type === 'string' ? type : (this.get('status') || api.settings.get("default_state"));
|
type = typeof type === 'string' ? type : (this.get('status') || api.settings.get("default_state"));
|
||||||
status_message = typeof status_message === 'string' ? status_message : this.get('status_message');
|
status_message = typeof status_message === 'string' ? status_message : this.get('status_message');
|
||||||
|
|
||||||
let presence;
|
let presence;
|
||||||
const attrs = {to};
|
|
||||||
if ((type === 'unavailable') ||
|
if (type === 'subscribe') {
|
||||||
|
presence = $pres({ to, type });
|
||||||
|
const { xmppstatus } = _converse;
|
||||||
|
const nick = xmppstatus.getNickname();
|
||||||
|
if (nick) presence.c('nick', {'xmlns': Strophe.NS.NICK}).t(nick).up();
|
||||||
|
|
||||||
|
} else if ((type === 'unavailable') ||
|
||||||
(type === 'probe') ||
|
(type === 'probe') ||
|
||||||
(type === 'error') ||
|
(type === 'error') ||
|
||||||
(type === 'unsubscribe') ||
|
(type === 'unsubscribe') ||
|
||||||
(type === 'unsubscribed') ||
|
(type === 'unsubscribed') ||
|
||||||
(type === 'subscribe') ||
|
|
||||||
(type === 'subscribed')) {
|
(type === 'subscribed')) {
|
||||||
attrs['type'] = type;
|
presence = $pres({ to, type });
|
||||||
presence = $pres(attrs);
|
|
||||||
} else if (type === 'offline') {
|
} else if (type === 'offline') {
|
||||||
attrs['type'] = 'unavailable';
|
presence = $pres({ to, type: 'unavailable' });
|
||||||
presence = $pres(attrs);
|
|
||||||
} else if (type === 'online') {
|
} else if (type === 'online') {
|
||||||
presence = $pres(attrs);
|
presence = $pres({ to });
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
presence = $pres(attrs).c('show').t(type).up();
|
presence = $pres({ to }).c('show').t(type).up();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status_message) {
|
if (status_message) presence.c('status').t(status_message).up();
|
||||||
presence.c('status').t(status_message).up();
|
|
||||||
}
|
|
||||||
|
|
||||||
const priority = api.settings.get("priority");
|
const priority = api.settings.get("priority");
|
||||||
presence.c('priority').t(isNaN(Number(priority)) ? 0 : priority).up();
|
presence.c('priority').t(isNaN(Number(priority)) ? 0 : priority).up();
|
||||||
if (_converse.idle) {
|
|
||||||
|
const { idle, idle_seconds } = _converse;
|
||||||
|
if (idle) {
|
||||||
const idle_since = new Date();
|
const idle_since = new Date();
|
||||||
idle_since.setSeconds(idle_since.getSeconds() - _converse.idle_seconds);
|
idle_since.setSeconds(idle_since.getSeconds() - idle_seconds);
|
||||||
presence.c('idle', {xmlns: Strophe.NS.IDLE, since: idle_since.toISOString()});
|
presence.c('idle', { xmlns: Strophe.NS.IDLE, since: idle_since.toISOString() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* *Hook* which allows plugins to modify a presence stanza
|
||||||
|
* @event _converse#constructedPresence
|
||||||
|
*/
|
||||||
presence = await api.hook('constructedPresence', null, presence);
|
presence = await api.hook('constructedPresence', null, presence);
|
||||||
return presence;
|
return presence;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
export default XMPPStatus;
|
|
||||||
|
@ -22,8 +22,8 @@ export default {
|
|||||||
* for the passed in JID.
|
* for the passed in JID.
|
||||||
*
|
*
|
||||||
* @method _converse.api.vcard.set
|
* @method _converse.api.vcard.set
|
||||||
* @param {string} jid The JID for which the VCard should be set
|
* @param { string } jid The JID for which the VCard should be set
|
||||||
* @param {object} data A map of VCard keys and values
|
* @param { object } data A map of VCard keys and values
|
||||||
* @example
|
* @example
|
||||||
* let jid = _converse.bare_jid;
|
* let jid = _converse.bare_jid;
|
||||||
* _converse.api.vcard.set( jid, {
|
* _converse.api.vcard.set( jid, {
|
||||||
@ -67,7 +67,7 @@ export default {
|
|||||||
* @param {Model|string} model Either a `Model` instance, or a string JID.
|
* @param {Model|string} model Either a `Model` instance, or a string JID.
|
||||||
* If a `Model` instance is passed in, then it must have either a `jid`
|
* If a `Model` instance is passed in, then it must have either a `jid`
|
||||||
* attribute or a `muc_jid` attribute.
|
* attribute or a `muc_jid` attribute.
|
||||||
* @param {boolean} [force] A boolean indicating whether the vcard should be
|
* @param { boolean } [force] A boolean indicating whether the vcard should be
|
||||||
* fetched from the server even if it's been fetched before.
|
* fetched from the server even if it's been fetched before.
|
||||||
* @returns {promise} A Promise which resolves with the VCard data for a particular JID or for
|
* @returns {promise} A Promise which resolves with the VCard data for a particular JID or for
|
||||||
* a `Model` instance which represents an entity with a JID (such as a roster contact,
|
* a `Model` instance which represents an entity with a JID (such as a roster contact,
|
||||||
@ -106,8 +106,8 @@ export default {
|
|||||||
* returned VCard data.
|
* returned VCard data.
|
||||||
*
|
*
|
||||||
* @method _converse.api.vcard.update
|
* @method _converse.api.vcard.update
|
||||||
* @param {Model} model A `Model` instance
|
* @param { Model } model A `Model` instance
|
||||||
* @param {boolean} [force] A boolean indicating whether the vcard should be
|
* @param { boolean } [force] A boolean indicating whether the vcard should be
|
||||||
* fetched again even if it's been fetched before.
|
* fetched again even if it's been fetched before.
|
||||||
* @returns {promise} A promise which resolves once the update has completed.
|
* @returns {promise} A promise which resolves once the update has completed.
|
||||||
* @example
|
* @example
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import log from "@converse/headless/log";
|
import log from "@converse/headless/log";
|
||||||
import { _converse, api, converse } from "../../core.js";
|
import { _converse, api, converse } from "../../core.js";
|
||||||
import { initStorage } from '@converse/headless/utils/storage.js';
|
import { initStorage } from '@converse/headless/utils/storage.js';
|
||||||
|
import { shouldClearCache } from '@converse/headless/utils/core.js';
|
||||||
|
|
||||||
const { Strophe, $iq, u } = converse.env;
|
const { Strophe, $iq, u } = converse.env;
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ export async function initVCardCollection () {
|
|||||||
|
|
||||||
|
|
||||||
export function clearVCardsSession () {
|
export function clearVCardsSession () {
|
||||||
if (_converse.shouldClearCache()) {
|
if (shouldClearCache()) {
|
||||||
api.promises.add('VCardsInitialized');
|
api.promises.add('VCardsInitialized');
|
||||||
if (_converse.vcards) {
|
if (_converse.vcards) {
|
||||||
_converse.vcards.clearStore();
|
_converse.vcards.clearStore();
|
||||||
|
@ -1,11 +1,36 @@
|
|||||||
import i18n from './i18n.js';
|
import i18n from './i18n.js';
|
||||||
import log from '../log.js';
|
import log from '../log.js';
|
||||||
import { CONNECTION_STATUS } from './constants';
|
import pluggable from 'pluggable.js/src/pluggable.js';
|
||||||
|
import { Events } from '@converse/skeletor/src/events.js';
|
||||||
import { Router } from '@converse/skeletor/src/router.js';
|
import { Router } from '@converse/skeletor/src/router.js';
|
||||||
import { TimeoutError } from './errors.js';
|
|
||||||
import { createStore, getDefaultStore } from '../utils/storage.js';
|
import { createStore, getDefaultStore } from '../utils/storage.js';
|
||||||
import { getInitSettings } from './settings/utils.js';
|
import { getInitSettings } from './settings/utils.js';
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
|
import { shouldClearCache } from '../utils/core.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ACTIVE,
|
||||||
|
ANONYMOUS,
|
||||||
|
CHATROOMS_TYPE,
|
||||||
|
CLOSED,
|
||||||
|
COMPOSING,
|
||||||
|
CONTROLBOX_TYPE,
|
||||||
|
DEFAULT_IMAGE,
|
||||||
|
DEFAULT_IMAGE_TYPE,
|
||||||
|
EXTERNAL,
|
||||||
|
FAILURE,
|
||||||
|
GONE,
|
||||||
|
HEADLINES_TYPE,
|
||||||
|
INACTIVE,
|
||||||
|
LOGIN,
|
||||||
|
LOGOUT,
|
||||||
|
OPENED,
|
||||||
|
PAUSED,
|
||||||
|
PREBIND,
|
||||||
|
PRIVATE_CHAT_TYPE,
|
||||||
|
SUCCESS,
|
||||||
|
VERSION_NAME
|
||||||
|
} from './constants';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,67 +41,51 @@ import { getOpenPromise } from '@converse/openpromise';
|
|||||||
*/
|
*/
|
||||||
const _converse = {
|
const _converse = {
|
||||||
log,
|
log,
|
||||||
CONNECTION_STATUS,
|
|
||||||
|
shouldClearCache, // TODO: Should be moved to utils with next major release
|
||||||
|
VERSION_NAME,
|
||||||
|
|
||||||
templates: {},
|
templates: {},
|
||||||
promises: {
|
promises: {
|
||||||
'initialized': getOpenPromise()
|
'initialized': getOpenPromise()
|
||||||
},
|
},
|
||||||
|
|
||||||
STATUS_WEIGHTS: {
|
// TODO: remove constants in next major release
|
||||||
'offline': 6,
|
ANONYMOUS,
|
||||||
'unavailable': 5,
|
CLOSED,
|
||||||
'xa': 4,
|
EXTERNAL,
|
||||||
'away': 3,
|
LOGIN,
|
||||||
'dnd': 2,
|
LOGOUT,
|
||||||
'chat': 1, // We currently don't differentiate between "chat" and "online"
|
OPENED,
|
||||||
'online': 1
|
PREBIND,
|
||||||
},
|
|
||||||
ANONYMOUS: 'anonymous',
|
|
||||||
CLOSED: 'closed',
|
|
||||||
EXTERNAL: 'external',
|
|
||||||
LOGIN: 'login',
|
|
||||||
LOGOUT: 'logout',
|
|
||||||
OPENED: 'opened',
|
|
||||||
PREBIND: 'prebind',
|
|
||||||
|
|
||||||
/**
|
SUCCESS,
|
||||||
* @constant
|
FAILURE,
|
||||||
* @type { integer }
|
|
||||||
*/
|
|
||||||
STANZA_TIMEOUT: 20000,
|
|
||||||
|
|
||||||
SUCCESS: 'success',
|
DEFAULT_IMAGE_TYPE,
|
||||||
FAILURE: 'failure',
|
DEFAULT_IMAGE,
|
||||||
|
|
||||||
// Generated from css/images/user.svg
|
INACTIVE,
|
||||||
DEFAULT_IMAGE_TYPE: 'image/svg+xml',
|
ACTIVE,
|
||||||
DEFAULT_IMAGE: "PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCI+CiA8cmVjdCB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgZmlsbD0iIzU1NSIvPgogPGNpcmNsZSBjeD0iNjQiIGN5PSI0MSIgcj0iMjQiIGZpbGw9IiNmZmYiLz4KIDxwYXRoIGQ9Im0yOC41IDExMiB2LTEyIGMwLTEyIDEwLTI0IDI0LTI0IGgyMyBjMTQgMCAyNCAxMiAyNCAyNCB2MTIiIGZpbGw9IiNmZmYiLz4KPC9zdmc+Cg==",
|
COMPOSING,
|
||||||
|
PAUSED,
|
||||||
|
GONE,
|
||||||
|
|
||||||
|
PRIVATE_CHAT_TYPE,
|
||||||
|
CHATROOMS_TYPE,
|
||||||
|
HEADLINES_TYPE,
|
||||||
|
CONTROLBOX_TYPE,
|
||||||
|
|
||||||
TIMEOUTS: {
|
|
||||||
// Set as module attr so that we can override in tests.
|
// Set as module attr so that we can override in tests.
|
||||||
|
// TODO: replace with config settings
|
||||||
|
TIMEOUTS: {
|
||||||
PAUSED: 10000,
|
PAUSED: 10000,
|
||||||
INACTIVE: 90000
|
INACTIVE: 90000
|
||||||
},
|
},
|
||||||
|
|
||||||
// XEP-0085 Chat states
|
|
||||||
// https://xmpp.org/extensions/xep-0085.html
|
|
||||||
INACTIVE: 'inactive',
|
|
||||||
ACTIVE: 'active',
|
|
||||||
COMPOSING: 'composing',
|
|
||||||
PAUSED: 'paused',
|
|
||||||
GONE: 'gone',
|
|
||||||
|
|
||||||
// Chat types
|
|
||||||
PRIVATE_CHAT_TYPE: 'chatbox',
|
|
||||||
CHATROOMS_TYPE: 'chatroom',
|
|
||||||
HEADLINES_TYPE: 'headline',
|
|
||||||
CONTROLBOX_TYPE: 'controlbox',
|
|
||||||
|
|
||||||
default_connection_options: {'explicitResourceBinding': true},
|
default_connection_options: {'explicitResourceBinding': true},
|
||||||
router: new Router(),
|
router: new Router(),
|
||||||
|
|
||||||
TimeoutError: TimeoutError,
|
|
||||||
|
|
||||||
isTestEnv: () => {
|
isTestEnv: () => {
|
||||||
return getInitSettings()['bosh_service_url'] === 'montague.lit/http-bind';
|
return getInitSettings()['bosh_service_url'] === 'montague.lit/http-bind';
|
||||||
},
|
},
|
||||||
@ -112,4 +121,10 @@ const _converse = {
|
|||||||
'___': str => str
|
'___': str => str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make _converse an event emitter
|
||||||
|
Object.assign(_converse, Events);
|
||||||
|
|
||||||
|
// Make _converse pluggable
|
||||||
|
pluggable.enable(_converse, '_converse', 'pluggable');
|
||||||
|
|
||||||
export default _converse;
|
export default _converse;
|
||||||
|
132
src/headless/shared/api/events.js
Normal file
132
src/headless/shared/api/events.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import _converse from '../_converse.js';
|
||||||
|
import isFunction from '../../utils/core.js';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* Lets you trigger events, which can be listened to via
|
||||||
|
* {@link _converse.api.listen.on} or {@link _converse.api.listen.once}
|
||||||
|
* (see [_converse.api.listen](http://localhost:8000/docs/html/api/-_converse.api.listen.html)).
|
||||||
|
*
|
||||||
|
* Some events also double as promises and can be waited on via {@link _converse.api.waitUntil}.
|
||||||
|
*
|
||||||
|
* @method _converse.api.trigger
|
||||||
|
* @param { string } name - The event name
|
||||||
|
* @param {...any} [argument] - Argument to be passed to the event handler
|
||||||
|
* @param { object } [options]
|
||||||
|
* @param { boolean } [options.synchronous] - Whether the event is synchronous or not.
|
||||||
|
* When a synchronous event is fired, a promise will be returned
|
||||||
|
* by {@link _converse.api.trigger} which resolves once all the
|
||||||
|
* event handlers' promises have been resolved.
|
||||||
|
*/
|
||||||
|
async trigger (name) {
|
||||||
|
if (!_converse._events) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const args = Array.from(arguments);
|
||||||
|
const options = args.pop();
|
||||||
|
if (options && options.synchronous) {
|
||||||
|
const events = _converse._events[name] || [];
|
||||||
|
const event_args = args.splice(1);
|
||||||
|
await Promise.all(events.map(e => e.callback.apply(e.ctx, event_args)));
|
||||||
|
} else {
|
||||||
|
_converse.trigger.apply(_converse, arguments);
|
||||||
|
}
|
||||||
|
const promise = _converse.promises[name];
|
||||||
|
if (promise !== undefined) {
|
||||||
|
promise.resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a hook which can be intercepted by registered listeners via
|
||||||
|
* {@link _converse.api.listen.on} or {@link _converse.api.listen.once}.
|
||||||
|
* (see [_converse.api.listen](http://localhost:8000/docs/html/api/-_converse.api.listen.html)).
|
||||||
|
* A hook is a special kind of event which allows you to intercept a data
|
||||||
|
* structure in order to modify it, before passing it back.
|
||||||
|
* @async
|
||||||
|
* @param { string } name - The hook name
|
||||||
|
* @param {...any} context - The context to which the hook applies (could be for example, a {@link _converse.ChatBox})).
|
||||||
|
* @param {...any} data - The data structure to be intercepted and modified by the hook listeners.
|
||||||
|
* @returns {Promise<any>} - A promise that resolves with the modified data structure.
|
||||||
|
*/
|
||||||
|
hook (name, context, data) {
|
||||||
|
const events = _converse._events[name] || [];
|
||||||
|
if (events.length) {
|
||||||
|
// Create a chain of promises, with each one feeding its output to
|
||||||
|
// the next. The first input is a promise with the original data
|
||||||
|
// sent to this hook.
|
||||||
|
return events.reduce((o, e) => o.then(d => e.callback(context, d)), Promise.resolve(data));
|
||||||
|
} else {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converse emits events to which you can subscribe to.
|
||||||
|
*
|
||||||
|
* The `listen` namespace exposes methods for creating event listeners
|
||||||
|
* (aka handlers) for these events.
|
||||||
|
*
|
||||||
|
* @namespace _converse.api.listen
|
||||||
|
* @memberOf _converse
|
||||||
|
*/
|
||||||
|
listen: {
|
||||||
|
/**
|
||||||
|
* Lets you listen to an event exactly once.
|
||||||
|
* @method _converse.api.listen.once
|
||||||
|
* @param { string } name The event's name
|
||||||
|
* @param { function } callback The callback method to be called when the event is emitted.
|
||||||
|
* @param { object } [context] The value of the `this` parameter for the callback.
|
||||||
|
* @example _converse.api.listen.once('message', function (messageXML) { ... });
|
||||||
|
*/
|
||||||
|
once: _converse.once.bind(_converse),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you subscribe to an event.
|
||||||
|
* Every time the event fires, the callback method specified by `callback` will be called.
|
||||||
|
* @method _converse.api.listen.on
|
||||||
|
* @param { string } name The event's name
|
||||||
|
* @param { function } callback The callback method to be called when the event is emitted.
|
||||||
|
* @param { object } [context] The value of the `this` parameter for the callback.
|
||||||
|
* @example _converse.api.listen.on('message', function (messageXML) { ... });
|
||||||
|
*/
|
||||||
|
on: _converse.on.bind(_converse),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To stop listening to an event, you can use the `not` method.
|
||||||
|
* @method _converse.api.listen.not
|
||||||
|
* @param { string } name The event's name
|
||||||
|
* @param { function } callback The callback method that is to no longer be called when the event fires
|
||||||
|
* @example _converse.api.listen.not('message', function (messageXML);
|
||||||
|
*/
|
||||||
|
not: _converse.off.bind(_converse),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to an incoming stanza
|
||||||
|
* Every a matched stanza is received, the callback method specified by
|
||||||
|
* `callback` will be called.
|
||||||
|
* @method _converse.api.listen.stanza
|
||||||
|
* @param { string } name The stanza's name
|
||||||
|
* @param { object } options Matching options (e.g. 'ns' for namespace, 'type' for stanza type, also 'id' and 'from');
|
||||||
|
* @param { function } handler The callback method to be called when the stanza appears
|
||||||
|
*/
|
||||||
|
stanza (name, options, handler) {
|
||||||
|
if (isFunction(options)) {
|
||||||
|
handler = options;
|
||||||
|
options = {};
|
||||||
|
} else {
|
||||||
|
options = options || {};
|
||||||
|
}
|
||||||
|
_converse.connection.addHandler(
|
||||||
|
handler,
|
||||||
|
options.ns,
|
||||||
|
name,
|
||||||
|
options.type,
|
||||||
|
options.id,
|
||||||
|
options.from,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
31
src/headless/shared/api/index.js
Normal file
31
src/headless/shared/api/index.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import _converse from '../_converse.js';
|
||||||
|
import connection_api from '../connection/api.js';
|
||||||
|
import events_api from '../api/events.js';
|
||||||
|
import promise_api from '../api/promise.js';
|
||||||
|
import send_api from '../api/send.js';
|
||||||
|
import user_api from '../api/user.js';
|
||||||
|
import { settings_api } from '../settings/api.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ### The private API
|
||||||
|
*
|
||||||
|
* The private API methods are only accessible via the closured {@link _converse}
|
||||||
|
* object, which is only available to plugins.
|
||||||
|
*
|
||||||
|
* These methods are kept private (i.e. not global) because they may return
|
||||||
|
* sensitive data which should be kept off-limits to other 3rd-party scripts
|
||||||
|
* that might be running in the page.
|
||||||
|
*
|
||||||
|
* @namespace _converse.api
|
||||||
|
* @memberOf _converse
|
||||||
|
*/
|
||||||
|
const api = _converse.api = {
|
||||||
|
connection: connection_api,
|
||||||
|
settings: settings_api,
|
||||||
|
...send_api,
|
||||||
|
...user_api,
|
||||||
|
...events_api,
|
||||||
|
...promise_api,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default api;
|
35
src/headless/shared/api/presence.js
Normal file
35
src/headless/shared/api/presence.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { _converse, api } from '../../core.js';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* @namespace _converse.api.user.presence
|
||||||
|
* @memberOf _converse.api.user
|
||||||
|
*/
|
||||||
|
presence: {
|
||||||
|
/**
|
||||||
|
* Send out a presence stanza
|
||||||
|
* @method _converse.api.user.presence.send
|
||||||
|
* @param { String } [type]
|
||||||
|
* @param { String } [to]
|
||||||
|
* @param { String } [status] - An optional status message
|
||||||
|
* @param { Array<Element>|Array<Strophe.Builder>|Element|Strophe.Builder } [child_nodes]
|
||||||
|
* Nodes(s) to be added as child nodes of the `presence` XML element.
|
||||||
|
*/
|
||||||
|
async send (type, to, status, child_nodes) {
|
||||||
|
await api.waitUntil('statusInitialized');
|
||||||
|
if (child_nodes && !Array.isArray(child_nodes)) {
|
||||||
|
child_nodes = [child_nodes];
|
||||||
|
}
|
||||||
|
const model = _converse.xmppstatus
|
||||||
|
const presence = await model.constructPresence(type, to, status);
|
||||||
|
child_nodes?.map(c => c?.tree() ?? c).forEach(c => presence.cnode(c).up());
|
||||||
|
api.send(presence);
|
||||||
|
|
||||||
|
if (['away', 'chat', 'dnd', 'online', 'xa', undefined].includes(type)) {
|
||||||
|
const mucs = await api.rooms.get();
|
||||||
|
mucs.forEach(muc => muc.sendStatusPresence(type, status, child_nodes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
src/headless/shared/api/promise.js
Normal file
78
src/headless/shared/api/promise.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import _converse from '@converse/headless/shared/_converse.js';
|
||||||
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
|
import { waitUntil, isFunction } from '../../utils/core.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* Converse and its plugins trigger various events which you can listen to via the
|
||||||
|
* {@link _converse.api.listen} namespace.
|
||||||
|
*
|
||||||
|
* Some of these events are also available as [ES2015 Promises](http://es6-features.org/#PromiseUsage)
|
||||||
|
* although not all of them could logically act as promises, since some events
|
||||||
|
* might be fired multpile times whereas promises are to be resolved (or
|
||||||
|
* rejected) only once.
|
||||||
|
*
|
||||||
|
* Events which are also promises include:
|
||||||
|
*
|
||||||
|
* * [cachedRoster](/docs/html/events.html#cachedroster)
|
||||||
|
* * [chatBoxesFetched](/docs/html/events.html#chatBoxesFetched)
|
||||||
|
* * [pluginsInitialized](/docs/html/events.html#pluginsInitialized)
|
||||||
|
* * [roster](/docs/html/events.html#roster)
|
||||||
|
* * [rosterContactsFetched](/docs/html/events.html#rosterContactsFetched)
|
||||||
|
* * [rosterGroupsFetched](/docs/html/events.html#rosterGroupsFetched)
|
||||||
|
* * [rosterInitialized](/docs/html/events.html#rosterInitialized)
|
||||||
|
*
|
||||||
|
* The various plugins might also provide promises, and they do this by using the
|
||||||
|
* `promises.add` api method.
|
||||||
|
*
|
||||||
|
* @namespace _converse.api.promises
|
||||||
|
* @memberOf _converse.api
|
||||||
|
*/
|
||||||
|
promises: {
|
||||||
|
/**
|
||||||
|
* By calling `promises.add`, a new [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
|
||||||
|
* is made available for other code or plugins to depend on via the
|
||||||
|
* {@link _converse.api.waitUntil} method.
|
||||||
|
*
|
||||||
|
* Generally, it's the responsibility of the plugin which adds the promise to
|
||||||
|
* also resolve it.
|
||||||
|
*
|
||||||
|
* This is done by calling {@link _converse.api.trigger}, which not only resolves the
|
||||||
|
* promise, but also emits an event with the same name (which can be listened to
|
||||||
|
* via {@link _converse.api.listen}).
|
||||||
|
*
|
||||||
|
* @method _converse.api.promises.add
|
||||||
|
* @param {string|array} [name|names] The name or an array of names for the promise(s) to be added
|
||||||
|
* @param { boolean } [replace=true] Whether this promise should be replaced with a new one when the user logs out.
|
||||||
|
* @example _converse.api.promises.add('foo-completed');
|
||||||
|
*/
|
||||||
|
add (promises, replace=true) {
|
||||||
|
promises = Array.isArray(promises) ? promises : [promises];
|
||||||
|
promises.forEach(name => {
|
||||||
|
const promise = getOpenPromise();
|
||||||
|
promise.replace = replace;
|
||||||
|
_converse.promises[name] = promise;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until a promise is resolved or until the passed in function returns
|
||||||
|
* a truthy value.
|
||||||
|
* @method _converse.api.waitUntil
|
||||||
|
* @param {string|function} condition - The name of the promise to wait for,
|
||||||
|
* or a function which should eventually return a truthy value.
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
waitUntil (condition) {
|
||||||
|
if (isFunction(condition)) {
|
||||||
|
return waitUntil(condition);
|
||||||
|
} else {
|
||||||
|
const promise = _converse.promises[condition];
|
||||||
|
if (promise === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
212
src/headless/shared/api/public.js
Normal file
212
src/headless/shared/api/public.js
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
import ConnectionFeedback from './../connection/feedback.js';
|
||||||
|
import URI from 'urijs';
|
||||||
|
import _converse from '../_converse.js';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import i18n from '../i18n';
|
||||||
|
import log from '../../log.js';
|
||||||
|
import sizzle from 'sizzle';
|
||||||
|
import u, { setUnloadEvent } from '../../utils/core.js';
|
||||||
|
import { ANONYMOUS, CHAT_STATES, KEYCODES, VERSION_NAME } from '../constants.js';
|
||||||
|
import { Collection } from "@converse/skeletor/src/collection";
|
||||||
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
|
import { Strophe, $build, $iq, $msg, $pres } from 'strophe.js/src/strophe';
|
||||||
|
import { TimeoutError } from '../errors.js';
|
||||||
|
import { filesize } from 'filesize';
|
||||||
|
import { html } from 'lit';
|
||||||
|
import { initAppSettings } from '../settings/utils.js';
|
||||||
|
import { sprintf } from 'sprintf-js';
|
||||||
|
import { stx } from '../../utils/stanza.js';
|
||||||
|
|
||||||
|
import {
|
||||||
|
cleanup,
|
||||||
|
initClientConfig,
|
||||||
|
initPlugins,
|
||||||
|
initSessionStorage,
|
||||||
|
registerGlobalEventHandlers,
|
||||||
|
} from '../../utils/init.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ### The Public API
|
||||||
|
*
|
||||||
|
* This namespace contains public API methods which are are
|
||||||
|
* accessible on the global `converse` object.
|
||||||
|
* They are public, because any JavaScript in the
|
||||||
|
* page can call them. Public methods therefore don’t expose any sensitive
|
||||||
|
* or closured data. To do that, you’ll need to create a plugin, which has
|
||||||
|
* access to the private API method.
|
||||||
|
*
|
||||||
|
* @global
|
||||||
|
* @namespace converse
|
||||||
|
*/
|
||||||
|
export const converse = Object.assign(window.converse || {}, {
|
||||||
|
|
||||||
|
CHAT_STATES,
|
||||||
|
|
||||||
|
keycodes: KEYCODES,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public API method which initializes Converse.
|
||||||
|
* This method must always be called when using Converse.
|
||||||
|
* @async
|
||||||
|
* @memberOf converse
|
||||||
|
* @method initialize
|
||||||
|
* @param { object } config A map of [configuration-settings](https://conversejs.org/docs/html/configuration.html#configuration-settings).
|
||||||
|
* @example
|
||||||
|
* converse.initialize({
|
||||||
|
* auto_list_rooms: false,
|
||||||
|
* auto_subscribe: false,
|
||||||
|
* bosh_service_url: 'https://bind.example.com',
|
||||||
|
* hide_muc_server: false,
|
||||||
|
* i18n: 'en',
|
||||||
|
* play_sounds: true,
|
||||||
|
* show_controlbox_by_default: true,
|
||||||
|
* debug: false,
|
||||||
|
* roster_groups: true
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
async initialize (settings) {
|
||||||
|
const { api } = _converse;
|
||||||
|
await cleanup(_converse);
|
||||||
|
|
||||||
|
setUnloadEvent();
|
||||||
|
initAppSettings(settings);
|
||||||
|
_converse.strict_plugin_dependencies = settings.strict_plugin_dependencies; // Needed by pluggable.js
|
||||||
|
log.setLogLevel(api.settings.get("loglevel"));
|
||||||
|
|
||||||
|
if (api.settings.get("authentication") === ANONYMOUS) {
|
||||||
|
if (api.settings.get("auto_login") && !api.settings.get('jid')) {
|
||||||
|
throw new Error("Config Error: you need to provide the server's " +
|
||||||
|
"domain via the 'jid' option when using anonymous " +
|
||||||
|
"authentication with auto_login.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_converse.router.route(
|
||||||
|
/^converse\?loglevel=(debug|info|warn|error|fatal)$/, 'loglevel',
|
||||||
|
l => log.setLogLevel(l)
|
||||||
|
);
|
||||||
|
_converse.connfeedback = new ConnectionFeedback();
|
||||||
|
|
||||||
|
/* When reloading the page:
|
||||||
|
* For new sessions, we need to send out a presence stanza to notify
|
||||||
|
* the server/network that we're online.
|
||||||
|
* When re-attaching to an existing session we don't need to again send out a presence stanza,
|
||||||
|
* because it's as if "we never left" (see onConnectStatusChanged).
|
||||||
|
* https://github.com/conversejs/converse.js/issues/521
|
||||||
|
*/
|
||||||
|
_converse.send_initial_presence = true;
|
||||||
|
|
||||||
|
await initSessionStorage(_converse);
|
||||||
|
await initClientConfig(_converse);
|
||||||
|
await i18n.initialize();
|
||||||
|
initPlugins(_converse);
|
||||||
|
|
||||||
|
// Register all custom elements
|
||||||
|
// XXX: api.elements is defined in the UI part of Converse, outside of @converse/headless.
|
||||||
|
// This line should probably be moved to the UI code as part of a larger refactoring.
|
||||||
|
api.elements?.register();
|
||||||
|
|
||||||
|
registerGlobalEventHandlers(_converse);
|
||||||
|
|
||||||
|
try {
|
||||||
|
!History.started && _converse.router.history.start();
|
||||||
|
} catch (e) {
|
||||||
|
log.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const plugins = _converse.pluggable.plugins
|
||||||
|
if (api.settings.get("auto_login") || api.settings.get("keepalive") && plugins['converse-bosh']?.enabled()) {
|
||||||
|
await api.user.login(null, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered once converse.initialize has finished.
|
||||||
|
* @event _converse#initialized
|
||||||
|
*/
|
||||||
|
api.trigger('initialized');
|
||||||
|
|
||||||
|
if (_converse.isTestEnv()) {
|
||||||
|
return _converse;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes methods for adding and removing plugins. You'll need to write a plugin
|
||||||
|
* if you want to have access to the private API methods defined further down below.
|
||||||
|
*
|
||||||
|
* For more information on plugins, read the documentation on [writing a plugin](/docs/html/plugin_development.html).
|
||||||
|
* @namespace plugins
|
||||||
|
* @memberOf converse
|
||||||
|
*/
|
||||||
|
plugins: {
|
||||||
|
/**
|
||||||
|
* Registers a new plugin.
|
||||||
|
* @method converse.plugins.add
|
||||||
|
* @param { string } name The name of the plugin
|
||||||
|
* @param { object } plugin The plugin object
|
||||||
|
* @example
|
||||||
|
* const plugin = {
|
||||||
|
* initialize: function () {
|
||||||
|
* // Gets called as soon as the plugin has been loaded.
|
||||||
|
*
|
||||||
|
* // Inside this method, you have access to the private
|
||||||
|
* // API via `_covnerse.api`.
|
||||||
|
*
|
||||||
|
* // The private _converse object contains the core logic
|
||||||
|
* // and data-structures of Converse.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* converse.plugins.add('myplugin', plugin);
|
||||||
|
*/
|
||||||
|
add (name, plugin) {
|
||||||
|
plugin.__name__ = name;
|
||||||
|
if (_converse.pluggable.plugins[name] !== undefined) {
|
||||||
|
throw new TypeError(
|
||||||
|
`Error: plugin with name "${name}" has already been ` + 'registered!'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_converse.pluggable.plugins[name] = plugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Utility methods and globals from bundled 3rd party libraries.
|
||||||
|
* @typedef ConverseEnv
|
||||||
|
* @property { Error } converse.env.TimeoutError
|
||||||
|
* @property { function } converse.env.$build - Creates a Strophe.Builder, for creating stanza objects.
|
||||||
|
* @property { function } converse.env.$iq - Creates a Strophe.Builder with an <iq/> element as the root.
|
||||||
|
* @property { function } converse.env.$msg - Creates a Strophe.Builder with an <message/> element as the root.
|
||||||
|
* @property { function } converse.env.$pres - Creates a Strophe.Builder with an <presence/> element as the root.
|
||||||
|
* @property { function } converse.env.Promise - The Promise implementation used by Converse.
|
||||||
|
* @property { function } converse.env.Strophe - The [Strophe](http://strophe.im/strophejs) XMPP library used by Converse.
|
||||||
|
* @property { function } converse.env.f - And instance of Lodash with its methods wrapped to produce immutable auto-curried iteratee-first data-last methods.
|
||||||
|
* @property { function } converse.env.sizzle - [Sizzle](https://sizzlejs.com) CSS selector engine.
|
||||||
|
* @property { function } converse.env.sprintf
|
||||||
|
* @property { object } converse.env._ - The instance of [lodash-es](http://lodash.com) used by Converse.
|
||||||
|
* @property { object } converse.env.dayjs - [DayJS](https://github.com/iamkun/dayjs) date manipulation library.
|
||||||
|
* @property { object } converse.env.utils - Module containing common utility methods used by Converse.
|
||||||
|
* @memberOf converse
|
||||||
|
*/
|
||||||
|
'env': {
|
||||||
|
$build,
|
||||||
|
$iq,
|
||||||
|
$msg,
|
||||||
|
$pres,
|
||||||
|
'utils': u,
|
||||||
|
Collection,
|
||||||
|
Model,
|
||||||
|
Promise,
|
||||||
|
Strophe,
|
||||||
|
TimeoutError,
|
||||||
|
URI,
|
||||||
|
VERSION_NAME,
|
||||||
|
dayjs,
|
||||||
|
filesize,
|
||||||
|
html,
|
||||||
|
log,
|
||||||
|
sizzle,
|
||||||
|
sprintf,
|
||||||
|
stx,
|
||||||
|
u,
|
||||||
|
}
|
||||||
|
});
|
81
src/headless/shared/api/send.js
Normal file
81
src/headless/shared/api/send.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import _converse from '../../shared/_converse.js';
|
||||||
|
import log from '../../log.js';
|
||||||
|
import { Strophe } from 'strophe.js/src/strophe';
|
||||||
|
import { TimeoutError } from '../errors.js';
|
||||||
|
import { toStanza } from '../../utils/stanza.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* Allows you to send XML stanzas.
|
||||||
|
* @method _converse.api.send
|
||||||
|
* @param { Element | Stanza } stanza
|
||||||
|
* @return { void }
|
||||||
|
* @example
|
||||||
|
* const msg = converse.env.$msg({
|
||||||
|
* 'from': 'juliet@example.com/balcony',
|
||||||
|
* 'to': 'romeo@example.net',
|
||||||
|
* 'type':'chat'
|
||||||
|
* });
|
||||||
|
* _converse.api.send(msg);
|
||||||
|
*/
|
||||||
|
send (stanza) {
|
||||||
|
const { api } = _converse;
|
||||||
|
if (!api.connection.connected()) {
|
||||||
|
log.warn("Not sending stanza because we're not connected!");
|
||||||
|
log.warn(Strophe.serialize(stanza));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof stanza === 'string') {
|
||||||
|
stanza = toStanza(stanza);
|
||||||
|
} else if (stanza?.tree) {
|
||||||
|
stanza = stanza.tree();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stanza.tagName === 'iq') {
|
||||||
|
return api.sendIQ(stanza);
|
||||||
|
} else {
|
||||||
|
_converse.connection.send(stanza);
|
||||||
|
api.trigger('send', stanza);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an IQ stanza
|
||||||
|
* @method _converse.api.sendIQ
|
||||||
|
* @param { Element } stanza
|
||||||
|
* @param { number } [timeout] - The default timeout value is taken from
|
||||||
|
* the `stanza_timeout` configuration setting.
|
||||||
|
* @param { Boolean } [reject=true] - Whether an error IQ should cause the promise
|
||||||
|
* to be rejected. If `false`, the promise will resolve instead of being rejected.
|
||||||
|
* @returns { Promise } A promise which resolves (or potentially rejected) once we
|
||||||
|
* receive a `result` or `error` stanza or once a timeout is reached.
|
||||||
|
* If the IQ stanza being sent is of type `result` or `error`, there's
|
||||||
|
* nothing to wait for, so an already resolved promise is returned.
|
||||||
|
*/
|
||||||
|
sendIQ (stanza, timeout, reject=true) {
|
||||||
|
const { api, connection } = _converse;
|
||||||
|
|
||||||
|
let promise;
|
||||||
|
stanza = stanza.tree?.() ?? stanza;
|
||||||
|
if (['get', 'set'].includes(stanza.getAttribute('type'))) {
|
||||||
|
timeout = timeout || api.settings.get('stanza_timeout');
|
||||||
|
if (reject) {
|
||||||
|
promise = new Promise((resolve, reject) => connection.sendIQ(stanza, resolve, reject, timeout));
|
||||||
|
promise.catch((e) => {
|
||||||
|
if (e === null) {
|
||||||
|
throw new TimeoutError(
|
||||||
|
`Timeout error after ${timeout}ms for the following IQ stanza: ${Strophe.serialize(stanza)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
promise = new Promise((resolve) => connection.sendIQ(stanza, resolve, resolve, timeout));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_converse.connection.sendIQ(stanza);
|
||||||
|
promise = Promise.resolve();
|
||||||
|
}
|
||||||
|
api.trigger('send', stanza);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
}
|
114
src/headless/shared/api/user.js
Normal file
114
src/headless/shared/api/user.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import _converse from '../_converse.js';
|
||||||
|
import presence_api from './presence.js';
|
||||||
|
import u, { replacePromise } from '../../utils/core.js';
|
||||||
|
import { attemptNonPreboundSession, initConnection, setUserJID } from '../../utils/init.js';
|
||||||
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
|
import { user_settings_api } from '../settings/api.js';
|
||||||
|
import { LOGOUT, PREBIND } from '../constants.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/**
|
||||||
|
* This grouping collects API functions related to the current logged in user.
|
||||||
|
*
|
||||||
|
* @namespace _converse.api.user
|
||||||
|
* @memberOf _converse.api
|
||||||
|
*/
|
||||||
|
user: {
|
||||||
|
settings: user_settings_api,
|
||||||
|
...presence_api,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method _converse.api.user.jid
|
||||||
|
* @returns {string} The current user's full JID (Jabber ID)
|
||||||
|
* @example _converse.api.user.jid())
|
||||||
|
*/
|
||||||
|
jid () {
|
||||||
|
return _converse.connection.jid;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the user in.
|
||||||
|
*
|
||||||
|
* If called without any parameters, Converse will try
|
||||||
|
* to log the user in by calling the `prebind_url` or `credentials_url` depending
|
||||||
|
* on whether prebinding is used or not.
|
||||||
|
*
|
||||||
|
* @method _converse.api.user.login
|
||||||
|
* @param { string } [jid]
|
||||||
|
* @param { string } [password]
|
||||||
|
* @param { boolean } [automatic=false] - An internally used flag that indicates whether
|
||||||
|
* this method was called automatically once the connection has been
|
||||||
|
* initialized. It's used together with the `auto_login` configuration flag
|
||||||
|
* to determine whether Converse should try to log the user in if it
|
||||||
|
* fails to restore a previous auth'd session.
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
|
async login (jid, password, automatic=false) {
|
||||||
|
const { api } = _converse;
|
||||||
|
jid = jid || api.settings.get('jid');
|
||||||
|
if (!_converse.connection?.jid || (jid && !u.isSameDomain(_converse.connection.jid, jid))) {
|
||||||
|
initConnection();
|
||||||
|
}
|
||||||
|
if (api.settings.get("connection_options")?.worker && (await _converse.connection.restoreWorkerSession())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (jid) {
|
||||||
|
jid = await setUserJID(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See whether there is a BOSH session to re-attach to
|
||||||
|
const bosh_plugin = _converse.pluggable.plugins['converse-bosh'];
|
||||||
|
if (bosh_plugin?.enabled()) {
|
||||||
|
if (await _converse.restoreBOSHSession()) {
|
||||||
|
return;
|
||||||
|
} else if (api.settings.get("authentication") === PREBIND && (!automatic || api.settings.get("auto_login"))) {
|
||||||
|
return _converse.startNewPreboundBOSHSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
password = password || api.settings.get("password");
|
||||||
|
const credentials = (jid && password) ? { jid, password } : null;
|
||||||
|
attemptNonPreboundSession(credentials, automatic);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the user out of the current XMPP session.
|
||||||
|
* @method _converse.api.user.logout
|
||||||
|
* @example _converse.api.user.logout();
|
||||||
|
*/
|
||||||
|
async logout () {
|
||||||
|
const { api } = _converse;
|
||||||
|
/**
|
||||||
|
* Triggered before the user is logged out
|
||||||
|
* @event _converse#beforeLogout
|
||||||
|
*/
|
||||||
|
await api.trigger('beforeLogout', {'synchronous': true});
|
||||||
|
|
||||||
|
const promise = getOpenPromise();
|
||||||
|
const complete = () => {
|
||||||
|
// Recreate all the promises
|
||||||
|
Object.keys(_converse.promises).forEach(replacePromise);
|
||||||
|
delete _converse.jid
|
||||||
|
|
||||||
|
// Remove the session JID, otherwise the user would just be logged
|
||||||
|
// in again upon reload. See #2759
|
||||||
|
localStorage.removeItem('conversejs-session-jid');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered once the user has logged out.
|
||||||
|
* @event _converse#logout
|
||||||
|
*/
|
||||||
|
api.trigger('logout');
|
||||||
|
promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
_converse.connection.setDisconnectionCause(LOGOUT, undefined, true);
|
||||||
|
if (_converse.connection !== undefined) {
|
||||||
|
api.listen.once('disconnected', () => complete());
|
||||||
|
_converse.connection.disconnect();
|
||||||
|
} else {
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/headless/shared/connection/feedback.js
Normal file
15
src/headless/shared/connection/feedback.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import _converse from '../_converse';
|
||||||
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
|
import { Strophe } from 'strophe.js/src/strophe';
|
||||||
|
|
||||||
|
export default Model.extend({
|
||||||
|
defaults: {
|
||||||
|
'connection_status': Strophe.Status.DISCONNECTED,
|
||||||
|
'message': ''
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize () {
|
||||||
|
const { api } = _converse;
|
||||||
|
this.on('change', () => api.trigger('connfeedback', _converse.connfeedback));
|
||||||
|
}
|
||||||
|
});
|
@ -1,11 +1,12 @@
|
|||||||
import debounce from 'lodash-es/debounce';
|
import debounce from 'lodash-es/debounce';
|
||||||
import log from "../../log.js";
|
import log from "../../log.js";
|
||||||
import sizzle from 'sizzle';
|
import sizzle from 'sizzle';
|
||||||
import { BOSH_WAIT } from '../../shared/constants.js';
|
import { ANONYMOUS, BOSH_WAIT, LOGOUT } from '../../shared/constants.js';
|
||||||
|
import { CONNECTION_STATUS } from '../constants';
|
||||||
import { Strophe } from 'strophe.js/src/core.js';
|
import { Strophe } from 'strophe.js/src/core.js';
|
||||||
import { _converse, api } from "../../core.js";
|
import { _converse, api } from "../../core.js";
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
|
||||||
import { clearSession, tearDown } from "../../utils/core.js";
|
import { clearSession, tearDown } from "../../utils/core.js";
|
||||||
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
import { setUserJID, } from '../../utils/init.js';
|
import { setUserJID, } from '../../utils/init.js';
|
||||||
|
|
||||||
const i = Object.keys(Strophe.Status).reduce((max, k) => Math.max(max, Strophe.Status[k]), 0);
|
const i = Object.keys(Strophe.Status).reduce((max, k) => Math.max(max, Strophe.Status[k]), 0);
|
||||||
@ -127,7 +128,7 @@ export class Connection extends Strophe.Connection {
|
|||||||
this._proto = new Strophe.Bosh(this);
|
this._proto = new Strophe.Bosh(this);
|
||||||
this.service = api.settings.get('bosh_service_url');
|
this.service = api.settings.get('bosh_service_url');
|
||||||
} else if (api.connection.isType('bosh') && api.settings.get("websocket_url")) {
|
} else if (api.connection.isType('bosh') && api.settings.get("websocket_url")) {
|
||||||
if (api.settings.get("authentication") === _converse.ANONYMOUS) {
|
if (api.settings.get("authentication") === ANONYMOUS) {
|
||||||
// When reconnecting anonymously, we need to connect with only
|
// When reconnecting anonymously, we need to connect with only
|
||||||
// the domain, not the full JID that we had in our previous
|
// the domain, not the full JID that we had in our previous
|
||||||
// (now failed) session.
|
// (now failed) session.
|
||||||
@ -149,7 +150,7 @@ export class Connection extends Strophe.Connection {
|
|||||||
const conn_status = _converse.connfeedback.get('connection_status');
|
const conn_status = _converse.connfeedback.get('connection_status');
|
||||||
if (conn_status === Strophe.Status.CONNFAIL) {
|
if (conn_status === Strophe.Status.CONNFAIL) {
|
||||||
this.switchTransport();
|
this.switchTransport();
|
||||||
} else if (conn_status === Strophe.Status.AUTHFAIL && api.settings.get("authentication") === _converse.ANONYMOUS) {
|
} else if (conn_status === Strophe.Status.AUTHFAIL && api.settings.get("authentication") === ANONYMOUS) {
|
||||||
// When reconnecting anonymously, we need to connect with only
|
// When reconnecting anonymously, we need to connect with only
|
||||||
// the domain, not the full JID that we had in our previous
|
// the domain, not the full JID that we had in our previous
|
||||||
// (now failed) session.
|
// (now failed) session.
|
||||||
@ -163,7 +164,7 @@ export class Connection extends Strophe.Connection {
|
|||||||
*/
|
*/
|
||||||
api.trigger('will-reconnect');
|
api.trigger('will-reconnect');
|
||||||
|
|
||||||
if (api.settings.get("authentication") === _converse.ANONYMOUS) {
|
if (api.settings.get("authentication") === ANONYMOUS) {
|
||||||
await clearSession();
|
await clearSession();
|
||||||
}
|
}
|
||||||
return api.user.login();
|
return api.user.login();
|
||||||
@ -264,7 +265,7 @@ export class Connection extends Strophe.Connection {
|
|||||||
if (api.settings.get("auto_reconnect")) {
|
if (api.settings.get("auto_reconnect")) {
|
||||||
const reason = this.disconnection_reason;
|
const reason = this.disconnection_reason;
|
||||||
if (this.disconnection_cause === Strophe.Status.AUTHFAIL) {
|
if (this.disconnection_cause === Strophe.Status.AUTHFAIL) {
|
||||||
if (api.settings.get("credentials_url") || api.settings.get("authentication") === _converse.ANONYMOUS) {
|
if (api.settings.get("credentials_url") || api.settings.get("authentication") === ANONYMOUS) {
|
||||||
// If `credentials_url` is set, we reconnect, because we might
|
// If `credentials_url` is set, we reconnect, because we might
|
||||||
// be receiving expirable tokens from the credentials_url.
|
// be receiving expirable tokens from the credentials_url.
|
||||||
//
|
//
|
||||||
@ -286,7 +287,7 @@ export class Connection extends Strophe.Connection {
|
|||||||
);
|
);
|
||||||
return this.finishDisconnection();
|
return this.finishDisconnection();
|
||||||
} else if (
|
} else if (
|
||||||
this.disconnection_cause === _converse.LOGOUT ||
|
this.disconnection_cause === LOGOUT ||
|
||||||
reason === Strophe.ErrorCondition.NO_AUTH_MECH ||
|
reason === Strophe.ErrorCondition.NO_AUTH_MECH ||
|
||||||
reason === "host-unknown" ||
|
reason === "host-unknown" ||
|
||||||
reason === "remote-connection-failed"
|
reason === "remote-connection-failed"
|
||||||
@ -308,7 +309,7 @@ export class Connection extends Strophe.Connection {
|
|||||||
*/
|
*/
|
||||||
onConnectStatusChanged (status, message) {
|
onConnectStatusChanged (status, message) {
|
||||||
const { __ } = _converse;
|
const { __ } = _converse;
|
||||||
log.debug(`Status changed to: ${_converse.CONNECTION_STATUS[status]}`);
|
log.debug(`Status changed to: ${CONNECTION_STATUS[status]}`);
|
||||||
if (status === Strophe.Status.ATTACHFAIL) {
|
if (status === Strophe.Status.ATTACHFAIL) {
|
||||||
this.setConnectionStatus(status);
|
this.setConnectionStatus(status);
|
||||||
this.worker_attach_promise?.resolve(false);
|
this.worker_attach_promise?.resolve(false);
|
||||||
|
@ -1,6 +1,46 @@
|
|||||||
import { Strophe } from 'strophe.js/src/strophe';
|
import { Strophe } from 'strophe.js/src/strophe';
|
||||||
|
|
||||||
export const BOSH_WAIT = 59;
|
export const BOSH_WAIT = 59;
|
||||||
|
export const VERSION_NAME = "v10.1.6";
|
||||||
|
|
||||||
|
export const STATUS_WEIGHTS = {
|
||||||
|
offline: 6,
|
||||||
|
unavailable: 5,
|
||||||
|
xa: 4,
|
||||||
|
away: 3,
|
||||||
|
dnd: 2,
|
||||||
|
chat: 1, // We don't differentiate between "chat" and "online"
|
||||||
|
online: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ANONYMOUS = 'anonymous';
|
||||||
|
export const CLOSED = 'closed';
|
||||||
|
export const EXTERNAL = 'external';
|
||||||
|
export const LOGIN = 'login';
|
||||||
|
export const LOGOUT = 'logout';
|
||||||
|
export const OPENED = 'opened';
|
||||||
|
export const PREBIND = 'prebind';
|
||||||
|
export const SUCCESS = 'success';
|
||||||
|
export const FAILURE = 'failure';
|
||||||
|
|
||||||
|
// Generated from css/images/user.svg
|
||||||
|
export const DEFAULT_IMAGE_TYPE = 'image/svg+xml';
|
||||||
|
export const DEFAULT_IMAGE =
|
||||||
|
'PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCI+CiA8cmVjdCB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgZmlsbD0iIzU1NSIvPgogPGNpcmNsZSBjeD0iNjQiIGN5PSI0MSIgcj0iMjQiIGZpbGw9IiNmZmYiLz4KIDxwYXRoIGQ9Im0yOC41IDExMiB2LTEyIGMwLTEyIDEwLTI0IDI0LTI0IGgyMyBjMTQgMCAyNCAxMiAyNCAyNCB2MTIiIGZpbGw9IiNmZmYiLz4KPC9zdmc+Cg==';
|
||||||
|
|
||||||
|
// XEP-0085 Chat states
|
||||||
|
// https =//xmpp.org/extensions/xep-0085.html
|
||||||
|
export const INACTIVE = 'inactive';
|
||||||
|
export const ACTIVE = 'active';
|
||||||
|
export const COMPOSING = 'composing';
|
||||||
|
export const PAUSED = 'paused';
|
||||||
|
export const GONE = 'gone';
|
||||||
|
|
||||||
|
// Chat types
|
||||||
|
export const PRIVATE_CHAT_TYPE = 'chatbox';
|
||||||
|
export const CHATROOMS_TYPE = 'chatroom';
|
||||||
|
export const HEADLINES_TYPE = 'headline';
|
||||||
|
export const CONTROLBOX_TYPE = 'controlbox';
|
||||||
|
|
||||||
export const CONNECTION_STATUS = {};
|
export const CONNECTION_STATUS = {};
|
||||||
CONNECTION_STATUS[Strophe.Status.ATTACHED] = 'ATTACHED';
|
CONNECTION_STATUS[Strophe.Status.ATTACHED] = 'ATTACHED';
|
||||||
@ -15,6 +55,43 @@ CONNECTION_STATUS[Strophe.Status.ERROR] = 'ERROR';
|
|||||||
CONNECTION_STATUS[Strophe.Status.RECONNECTING] = 'RECONNECTING';
|
CONNECTION_STATUS[Strophe.Status.RECONNECTING] = 'RECONNECTING';
|
||||||
CONNECTION_STATUS[Strophe.Status.REDIRECT] = 'REDIRECT';
|
CONNECTION_STATUS[Strophe.Status.REDIRECT] = 'REDIRECT';
|
||||||
|
|
||||||
|
// Add Strophe Namespaces
|
||||||
|
Strophe.addNamespace('ACTIVITY', 'http://jabber.org/protocol/activity');
|
||||||
|
Strophe.addNamespace('CARBONS', 'urn:xmpp:carbons:2');
|
||||||
|
Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates');
|
||||||
|
Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
|
||||||
|
Strophe.addNamespace('DELAY', 'urn:xmpp:delay');
|
||||||
|
Strophe.addNamespace('EME', 'urn:xmpp:eme:0');
|
||||||
|
Strophe.addNamespace('FASTEN', 'urn:xmpp:fasten:0');
|
||||||
|
Strophe.addNamespace('FORWARD', 'urn:xmpp:forward:0');
|
||||||
|
Strophe.addNamespace('HINTS', 'urn:xmpp:hints');
|
||||||
|
Strophe.addNamespace('HTTPUPLOAD', 'urn:xmpp:http:upload:0');
|
||||||
|
Strophe.addNamespace('MAM', 'urn:xmpp:mam:2');
|
||||||
|
Strophe.addNamespace('MARKERS', 'urn:xmpp:chat-markers:0');
|
||||||
|
Strophe.addNamespace('MENTIONS', 'urn:xmpp:mmn:0');
|
||||||
|
Strophe.addNamespace('MESSAGE_CORRECT', 'urn:xmpp:message-correct:0');
|
||||||
|
Strophe.addNamespace('MODERATE', 'urn:xmpp:message-moderate:0');
|
||||||
|
Strophe.addNamespace('NICK', 'http://jabber.org/protocol/nick');
|
||||||
|
Strophe.addNamespace('OCCUPANTID', 'urn:xmpp:occupant-id:0');
|
||||||
|
Strophe.addNamespace('OMEMO', 'eu.siacs.conversations.axolotl');
|
||||||
|
Strophe.addNamespace('OUTOFBAND', 'jabber:x:oob');
|
||||||
|
Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
|
||||||
|
Strophe.addNamespace('RAI', 'urn:xmpp:rai:0');
|
||||||
|
Strophe.addNamespace('RECEIPTS', 'urn:xmpp:receipts');
|
||||||
|
Strophe.addNamespace('REFERENCE', 'urn:xmpp:reference:0');
|
||||||
|
Strophe.addNamespace('REGISTER', 'jabber:iq:register');
|
||||||
|
Strophe.addNamespace('RETRACT', 'urn:xmpp:message-retract:0');
|
||||||
|
Strophe.addNamespace('ROSTERX', 'http://jabber.org/protocol/rosterx');
|
||||||
|
Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
||||||
|
Strophe.addNamespace('SID', 'urn:xmpp:sid:0');
|
||||||
|
Strophe.addNamespace('SPOILER', 'urn:xmpp:spoiler:0');
|
||||||
|
Strophe.addNamespace('STANZAS', 'urn:ietf:params:xml:ns:xmpp-stanzas');
|
||||||
|
Strophe.addNamespace('STYLING', 'urn:xmpp:styling:0');
|
||||||
|
Strophe.addNamespace('VCARD', 'vcard-temp');
|
||||||
|
Strophe.addNamespace('VCARDUPDATE', 'vcard-temp:x:update');
|
||||||
|
Strophe.addNamespace('XFORM', 'jabber:x:data');
|
||||||
|
Strophe.addNamespace('XHTML', 'http://www.w3.org/1999/xhtml');
|
||||||
|
|
||||||
// Core plugins are whitelisted automatically
|
// Core plugins are whitelisted automatically
|
||||||
// These are just the @converse/headless plugins, for the full converse,
|
// These are just the @converse/headless plugins, for the full converse,
|
||||||
// the other plugins are whitelisted in src/consts.js
|
// the other plugins are whitelisted in src/consts.js
|
||||||
@ -35,7 +112,7 @@ export const CORE_PLUGINS = [
|
|||||||
'converse-roster',
|
'converse-roster',
|
||||||
'converse-smacks',
|
'converse-smacks',
|
||||||
'converse-status',
|
'converse-status',
|
||||||
'converse-vcard'
|
'converse-vcard',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const URL_PARSE_OPTIONS = { 'start': /(\b|_)(?:([a-z][a-z0-9.+-]*:\/\/)|xmpp:|mailto:|www\.)/gi };
|
export const URL_PARSE_OPTIONS = { 'start': /(\b|_)(?:([a-z][a-z0-9.+-]*:\/\/)|xmpp:|mailto:|www\.)/gi };
|
||||||
@ -56,5 +133,5 @@ export const KEYCODES = {
|
|||||||
FORWARD_SLASH: 47,
|
FORWARD_SLASH: 47,
|
||||||
AT: 50,
|
AT: 50,
|
||||||
META: 91,
|
META: 91,
|
||||||
META_RIGHT: 93
|
META_RIGHT: 93,
|
||||||
}
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Custom error for indicating timeouts
|
* Custom error for indicating timeouts
|
||||||
* @namespace _converse
|
* @namespace converse.env
|
||||||
*/
|
*/
|
||||||
export class TimeoutError extends Error {}
|
export class TimeoutError extends Error {}
|
||||||
|
@ -28,7 +28,7 @@ export class StanzaParseError extends Error {
|
|||||||
* Extract the XEP-0359 stanza IDs from the passed in stanza
|
* Extract the XEP-0359 stanza IDs from the passed in stanza
|
||||||
* and return a map containing them.
|
* and return a map containing them.
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @returns { Object }
|
* @returns { Object }
|
||||||
*/
|
*/
|
||||||
export function getStanzaIDs (stanza, original_stanza) {
|
export function getStanzaIDs (stanza, original_stanza) {
|
||||||
@ -72,8 +72,8 @@ export function getEncryptionAttributes (stanza) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @param { XMLElement } original_stanza - The original stanza, that contains the
|
* @param { Element } original_stanza - The original stanza, that contains the
|
||||||
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
||||||
* @returns { Object }
|
* @returns { Object }
|
||||||
*/
|
*/
|
||||||
@ -222,7 +222,7 @@ export function getOutOfBandAttributes (stanza) {
|
|||||||
/**
|
/**
|
||||||
* Returns the human readable error message contained in a `groupchat` message stanza of type `error`.
|
* Returns the human readable error message contained in a `groupchat` message stanza of type `error`.
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
*/
|
*/
|
||||||
export function getErrorAttributes (stanza) {
|
export function getErrorAttributes (stanza) {
|
||||||
if (stanza.getAttribute('type') === 'error') {
|
if (stanza.getAttribute('type') === 'error') {
|
||||||
@ -240,7 +240,7 @@ export function getErrorAttributes (stanza) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a message stanza, find and return any XEP-0372 references
|
* Given a message stanza, find and return any XEP-0372 references
|
||||||
* @param { XMLElement } stana - The message stanza
|
* @param { Element } stana - The message stanza
|
||||||
* @returns { Reference }
|
* @returns { Reference }
|
||||||
*/
|
*/
|
||||||
export function getReferences (stanza) {
|
export function getReferences (stanza) {
|
||||||
@ -279,7 +279,7 @@ export function getReceiptId (stanza) {
|
|||||||
/**
|
/**
|
||||||
* Determines whether the passed in stanza is a XEP-0280 Carbon
|
* Determines whether the passed in stanza is a XEP-0280 Carbon
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @returns { Boolean }
|
* @returns { Boolean }
|
||||||
*/
|
*/
|
||||||
export function isCarbon (stanza) {
|
export function isCarbon (stanza) {
|
||||||
@ -293,7 +293,7 @@ export function isCarbon (stanza) {
|
|||||||
/**
|
/**
|
||||||
* Returns the XEP-0085 chat state contained in a message stanza
|
* Returns the XEP-0085 chat state contained in a message stanza
|
||||||
* @private
|
* @private
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
*/
|
*/
|
||||||
export function getChatState (stanza) {
|
export function getChatState (stanza) {
|
||||||
return sizzle(
|
return sizzle(
|
||||||
@ -319,7 +319,7 @@ export function isValidReceiptRequest (stanza, attrs) {
|
|||||||
/**
|
/**
|
||||||
* Check whether the passed-in stanza is a forwarded message that is "bare",
|
* Check whether the passed-in stanza is a forwarded message that is "bare",
|
||||||
* i.e. it's not forwarded as part of a larger protocol, like MAM.
|
* i.e. it's not forwarded as part of a larger protocol, like MAM.
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
*/
|
*/
|
||||||
export function throwErrorIfInvalidForward (stanza) {
|
export function throwErrorIfInvalidForward (stanza) {
|
||||||
const bare_forward = sizzle(`message > forwarded[xmlns="${Strophe.NS.FORWARD}"]`, stanza).length;
|
const bare_forward = sizzle(`message > forwarded[xmlns="${Strophe.NS.FORWARD}"]`, stanza).length;
|
||||||
@ -334,7 +334,7 @@ export function throwErrorIfInvalidForward (stanza) {
|
|||||||
* Determines whether the passed in stanza is a XEP-0333 Chat Marker
|
* Determines whether the passed in stanza is a XEP-0333 Chat Marker
|
||||||
* @private
|
* @private
|
||||||
* @method getChatMarker
|
* @method getChatMarker
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @returns { Boolean }
|
* @returns { Boolean }
|
||||||
*/
|
*/
|
||||||
export function getChatMarker (stanza) {
|
export function getChatMarker (stanza) {
|
||||||
@ -371,7 +371,7 @@ export function isServerMessage (stanza) {
|
|||||||
* Determines whether the passed in stanza is a XEP-0313 MAM stanza
|
* Determines whether the passed in stanza is a XEP-0313 MAM stanza
|
||||||
* @private
|
* @private
|
||||||
* @method isArchived
|
* @method isArchived
|
||||||
* @param { XMLElement } stanza - The message stanza
|
* @param { Element } stanza - The message stanza
|
||||||
* @returns { Boolean }
|
* @returns { Boolean }
|
||||||
*/
|
*/
|
||||||
export function isArchived (original_stanza) {
|
export function isArchived (original_stanza) {
|
||||||
@ -382,7 +382,7 @@ export function isArchived (original_stanza) {
|
|||||||
/**
|
/**
|
||||||
* Returns an object containing all attribute names and values for a particular element.
|
* Returns an object containing all attribute names and values for a particular element.
|
||||||
* @method getAttributes
|
* @method getAttributes
|
||||||
* @param { XMLElement } stanza
|
* @param { Element } stanza
|
||||||
* @returns { Object }
|
* @returns { Object }
|
||||||
*/
|
*/
|
||||||
export function getAttributes (stanza) {
|
export function getAttributes (stanza) {
|
||||||
|
@ -19,8 +19,8 @@ Strophe.addNamespace('RSM', 'http://jabber.org/protocol/rsm');
|
|||||||
* [XEP-0059 RSM](https://xmpp.org/extensions/xep-0059.html) Attributes that can be used to filter query results
|
* [XEP-0059 RSM](https://xmpp.org/extensions/xep-0059.html) Attributes that can be used to filter query results
|
||||||
* @property { String } [after] - The XEP-0359 stanza ID of a message after which messages should be returned. Implies forward paging.
|
* @property { String } [after] - The XEP-0359 stanza ID of a message after which messages should be returned. Implies forward paging.
|
||||||
* @property { String } [before] - The XEP-0359 stanza ID of a message before which messages should be returned. Implies backward paging.
|
* @property { String } [before] - The XEP-0359 stanza ID of a message before which messages should be returned. Implies backward paging.
|
||||||
* @property { Integer } [index=0] - The index of the results page to return.
|
* @property { number } [index=0] - The index of the results page to return.
|
||||||
* @property { Integer } [max] - The maximum number of items to return.
|
* @property { number } [max] - The maximum number of items to return.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const RSM_QUERY_PARAMETERS = ['after', 'before', 'index', 'max'];
|
const RSM_QUERY_PARAMETERS = ['after', 'before', 'index', 'max'];
|
||||||
@ -84,7 +84,7 @@ export class RSM {
|
|||||||
* Returns a `<set>` XML element that confirms to XEP-0059 Result Set Management.
|
* Returns a `<set>` XML element that confirms to XEP-0059 Result Set Management.
|
||||||
* The element is constructed based on the {@link module:converse-rsm~RSMQueryParameters}
|
* The element is constructed based on the {@link module:converse-rsm~RSMQueryParameters}
|
||||||
* that are set on this RSM instance.
|
* that are set on this RSM instance.
|
||||||
* @returns { XMLElement }
|
* @returns { Element }
|
||||||
*/
|
*/
|
||||||
toXML () {
|
toXML () {
|
||||||
const xml = $build('set', {xmlns: Strophe.NS.RSM});
|
const xml = $build('set', {xmlns: Strophe.NS.RSM});
|
||||||
|
@ -29,7 +29,7 @@ export const settings_api = {
|
|||||||
* `converse.initialize`.
|
* `converse.initialize`.
|
||||||
*
|
*
|
||||||
* @method _converse.api.settings.extend
|
* @method _converse.api.settings.extend
|
||||||
* @param {object} settings The configuration settings
|
* @param { object } settings The configuration settings
|
||||||
* @example
|
* @example
|
||||||
* _converse.api.settings.extend({
|
* _converse.api.settings.extend({
|
||||||
* 'enable_foo': true
|
* 'enable_foo': true
|
||||||
@ -70,9 +70,10 @@ export const settings_api = {
|
|||||||
* running and you want to change the configuration on-the-fly.
|
* running and you want to change the configuration on-the-fly.
|
||||||
*
|
*
|
||||||
* @method _converse.api.settings.set
|
* @method _converse.api.settings.set
|
||||||
* @param {Object} [settings] An object containing configuration settings.
|
* @param { Object | string } [settings_or_key]
|
||||||
* @param {string} [key] Alternatively to passing in an object, you can pass in a key and a value.
|
* An object containing configuration settings.
|
||||||
* @param {string} [value]
|
* Alternatively to passing in an object, you can pass in a key and a value.
|
||||||
|
* @param { string } [value]
|
||||||
* @example _converse.api.settings.set("play_sounds", true);
|
* @example _converse.api.settings.set("play_sounds", true);
|
||||||
* @example
|
* @example
|
||||||
* _converse.api.settings.set({
|
* _converse.api.settings.set({
|
||||||
@ -80,8 +81,8 @@ export const settings_api = {
|
|||||||
* "hide_offline_users": true
|
* "hide_offline_users": true
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
set (key, val) {
|
set (settings_or_key, value) {
|
||||||
updateAppSettings(key, val);
|
updateAppSettings(settings_or_key, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,7 +111,7 @@ export const settings_api = {
|
|||||||
* To stop listening to an event, you can use the `not` method.
|
* To stop listening to an event, you can use the `not` method.
|
||||||
* @method _converse.api.settings.listen.not
|
* @method _converse.api.settings.listen.not
|
||||||
* @param { String } name The event's name
|
* @param { String } name The event's name
|
||||||
* @param { Function } callback The callback method that is to no longer be called when the event fires
|
* @param { Function } handler The callback method that is to no longer be called when the event fires
|
||||||
* @example _converse.api.settings.listen.not('change', callback);
|
* @example _converse.api.settings.listen.not('change', callback);
|
||||||
*/
|
*/
|
||||||
not (name, handler) {
|
not (name, handler) {
|
||||||
@ -142,7 +143,7 @@ export const user_settings_api = {
|
|||||||
/**
|
/**
|
||||||
* Get the value of a particular user setting.
|
* Get the value of a particular user setting.
|
||||||
* @method _converse.api.user.settings.get
|
* @method _converse.api.user.settings.get
|
||||||
* @param {String} key - The setting name
|
* @param { String } key - The setting name
|
||||||
* @param {*} [fallback] - An optional fallback value if the user setting is undefined
|
* @param {*} [fallback] - An optional fallback value if the user setting is undefined
|
||||||
* @returns {Promise} Promise which resolves with the value of the particular configuration setting.
|
* @returns {Promise} Promise which resolves with the value of the particular configuration setting.
|
||||||
* @example _converse.api.user.settings.get("foo");
|
* @example _converse.api.user.settings.get("foo");
|
||||||
@ -156,9 +157,9 @@ export const user_settings_api = {
|
|||||||
* Set one or many user settings.
|
* Set one or many user settings.
|
||||||
* @async
|
* @async
|
||||||
* @method _converse.api.user.settings.set
|
* @method _converse.api.user.settings.set
|
||||||
* @param {Object} [settings] An object containing configuration settings.
|
* @param { Object } [settings] An object containing configuration settings.
|
||||||
* @param {string} [key] Alternatively to passing in an object, you can pass in a key and a value.
|
* @param { string } [key] Alternatively to passing in an object, you can pass in a key and a value.
|
||||||
* @param {string} [value]
|
* @param { string } [value]
|
||||||
* @example _converse.api.user.settings.set("foo", "bar");
|
* @example _converse.api.user.settings.set("foo", "bar");
|
||||||
* @example
|
* @example
|
||||||
* _converse.api.user.settings.set({
|
* _converse.api.user.settings.set({
|
||||||
|
@ -101,6 +101,7 @@ export const DEFAULT_SETTINGS = {
|
|||||||
sid: undefined,
|
sid: undefined,
|
||||||
singleton: false,
|
singleton: false,
|
||||||
strict_plugin_dependencies: false,
|
strict_plugin_dependencies: false,
|
||||||
|
stanza_timeout: 20000,
|
||||||
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
|
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
|
||||||
websocket_url: undefined,
|
websocket_url: undefined,
|
||||||
whitelisted_plugins: [],
|
whitelisted_plugins: [],
|
||||||
|
@ -8,14 +8,20 @@ import _converse from '@converse/headless/shared/_converse.js';
|
|||||||
import compact from "lodash-es/compact";
|
import compact from "lodash-es/compact";
|
||||||
import isObject from "lodash-es/isObject";
|
import isObject from "lodash-es/isObject";
|
||||||
import last from "lodash-es/last";
|
import last from "lodash-es/last";
|
||||||
import log from '@converse/headless/log.js';
|
import log from '../log.js';
|
||||||
import sizzle from "sizzle";
|
import sizzle from "sizzle";
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { Strophe } from 'strophe.js/src/strophe.js';
|
import { Strophe } from 'strophe.js/src/strophe.js';
|
||||||
import { getOpenPromise } from '@converse/openpromise';
|
import { getOpenPromise } from '@converse/openpromise';
|
||||||
import { settings_api } from '@converse/headless/shared/settings/api.js';
|
import { settings_api } from '../shared/settings/api.js';
|
||||||
import { stx , toStanza } from './stanza.js';
|
import { stx , toStanza } from './stanza.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The utils object
|
||||||
|
* @namespace u
|
||||||
|
*/
|
||||||
|
const u = {};
|
||||||
|
|
||||||
export function isElement (el) {
|
export function isElement (el) {
|
||||||
return el instanceof Element || el instanceof HTMLDocument;
|
return el instanceof Element || el instanceof HTMLDocument;
|
||||||
}
|
}
|
||||||
@ -24,6 +30,10 @@ export function isError (obj) {
|
|||||||
return Object.prototype.toString.call(obj) === "[object Error]";
|
return Object.prototype.toString.call(obj) === "[object Error]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFunction (val) {
|
||||||
|
return typeof val === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
export function isEmptyMessage (attrs) {
|
export function isEmptyMessage (attrs) {
|
||||||
if (attrs instanceof Model) {
|
if (attrs instanceof Model) {
|
||||||
attrs = attrs.attributes;
|
attrs = attrs.attributes;
|
||||||
@ -35,7 +45,8 @@ export function isEmptyMessage (attrs) {
|
|||||||
!attrs['body'];
|
!attrs['body'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We distinguish between UniView and MultiView instances.
|
/**
|
||||||
|
* We distinguish between UniView and MultiView instances.
|
||||||
*
|
*
|
||||||
* UniView means that only one chat is visible, even though there might be multiple ongoing chats.
|
* UniView means that only one chat is visible, even though there might be multiple ongoing chats.
|
||||||
* MultiView means that multiple chats may be visible simultaneously.
|
* MultiView means that multiple chats may be visible simultaneously.
|
||||||
@ -44,16 +55,24 @@ export function isUniView () {
|
|||||||
return ['mobile', 'fullscreen', 'embedded'].includes(settings_api.get("view_mode"));
|
return ['mobile', 'fullscreen', 'embedded'].includes(settings_api.get("view_mode"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldClearCache () {
|
||||||
|
const { api } = _converse;
|
||||||
|
return !_converse.config.get('trusted') ||
|
||||||
|
api.settings.get('clear_cache_on_logout') ||
|
||||||
|
_converse.isTestEnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function tearDown () {
|
export async function tearDown () {
|
||||||
await _converse.api.trigger('beforeTearDown', {'synchronous': true});
|
const { api } = _converse;
|
||||||
|
await api.trigger('beforeTearDown', {'synchronous': true});
|
||||||
window.removeEventListener('click', _converse.onUserActivity);
|
window.removeEventListener('click', _converse.onUserActivity);
|
||||||
window.removeEventListener('focus', _converse.onUserActivity);
|
window.removeEventListener('focus', _converse.onUserActivity);
|
||||||
window.removeEventListener('keypress', _converse.onUserActivity);
|
window.removeEventListener('keypress', _converse.onUserActivity);
|
||||||
window.removeEventListener('mousemove', _converse.onUserActivity);
|
window.removeEventListener('mousemove', _converse.onUserActivity);
|
||||||
window.removeEventListener(_converse.unloadevent, _converse.onUserActivity);
|
window.removeEventListener(_converse.unloadevent, _converse.onUserActivity);
|
||||||
window.clearInterval(_converse.everySecondTrigger);
|
window.clearInterval(_converse.everySecondTrigger);
|
||||||
_converse.api.trigger('afterTearDown');
|
api.trigger('afterTearDown');
|
||||||
return _converse;
|
return _converse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +80,7 @@ export async function tearDown () {
|
|||||||
export function clearSession () {
|
export function clearSession () {
|
||||||
_converse.session?.destroy();
|
_converse.session?.destroy();
|
||||||
delete _converse.session;
|
delete _converse.session;
|
||||||
_converse.shouldClearCache() && _converse.api.user.settings.clear();
|
shouldClearCache() && _converse.api.user.settings.clear();
|
||||||
/**
|
/**
|
||||||
* Synchronouse event triggered once the user session has been cleared,
|
* Synchronouse event triggered once the user session has been cleared,
|
||||||
* for example when the user has logged out or when Converse has
|
* for example when the user has logged out or when Converse has
|
||||||
@ -86,13 +105,6 @@ export function prefixMentions (message) {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The utils object
|
|
||||||
* @namespace u
|
|
||||||
*/
|
|
||||||
const u = {};
|
|
||||||
|
|
||||||
u.isTagEqual = function (stanza, name) {
|
u.isTagEqual = function (stanza, name) {
|
||||||
if (stanza.tree?.()) {
|
if (stanza.tree?.()) {
|
||||||
return u.isTagEqual(stanza.tree(), name);
|
return u.isTagEqual(stanza.tree(), name);
|
||||||
@ -183,7 +195,7 @@ u.isChatRoom = function (model) {
|
|||||||
return model && (model.get('type') === 'chatroom');
|
return model && (model.get('type') === 'chatroom');
|
||||||
}
|
}
|
||||||
|
|
||||||
u.isErrorObject = function (o) {
|
export function isErrorObject (o) {
|
||||||
return o instanceof Error;
|
return o instanceof Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +268,7 @@ u.stringToElement = function (s) {
|
|||||||
* Checks whether the DOM element matches the given selector.
|
* Checks whether the DOM element matches the given selector.
|
||||||
* @private
|
* @private
|
||||||
* @method u#matchesSelector
|
* @method u#matchesSelector
|
||||||
* @param { DOMElement } el - The DOM element
|
* @param { Element } el - The DOM element
|
||||||
* @param { String } selector - The selector
|
* @param { String } selector - The selector
|
||||||
*/
|
*/
|
||||||
u.matchesSelector = function (el, selector) {
|
u.matchesSelector = function (el, selector) {
|
||||||
@ -275,7 +287,7 @@ u.matchesSelector = function (el, selector) {
|
|||||||
* Returns a list of children of the DOM element that match the selector.
|
* Returns a list of children of the DOM element that match the selector.
|
||||||
* @private
|
* @private
|
||||||
* @method u#queryChildren
|
* @method u#queryChildren
|
||||||
* @param { DOMElement } el - the DOM element
|
* @param { Element } el - the DOM element
|
||||||
* @param { String } selector - the selector they should be matched against
|
* @param { String } selector - the selector they should be matched against
|
||||||
*/
|
*/
|
||||||
u.queryChildren = function (el, selector) {
|
u.queryChildren = function (el, selector) {
|
||||||
@ -394,10 +406,10 @@ u.siblingIndex = function (el) {
|
|||||||
/**
|
/**
|
||||||
* Returns the current word being written in the input element
|
* Returns the current word being written in the input element
|
||||||
* @method u#getCurrentWord
|
* @method u#getCurrentWord
|
||||||
* @param {HTMLElement} input - The HTMLElement in which text is being entered
|
* @param { HTMLElement } input - The HTMLElement in which text is being entered
|
||||||
* @param {integer} [index] - An optional rightmost boundary index. If given, the text
|
* @param { number } [index] - An optional rightmost boundary index. If given, the text
|
||||||
* value of the input element will only be considered up until this index.
|
* value of the input element will only be considered up until this index.
|
||||||
* @param {string} [delineator] - An optional string delineator to
|
* @param { string } [delineator] - An optional string delineator to
|
||||||
* differentiate between words.
|
* differentiate between words.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@ -477,8 +489,8 @@ export function getUniqueId (suffix) {
|
|||||||
/**
|
/**
|
||||||
* Clears the specified timeout and interval.
|
* Clears the specified timeout and interval.
|
||||||
* @method u#clearTimers
|
* @method u#clearTimers
|
||||||
* @param {number} timeout - Id if the timeout to clear.
|
* @param { number } timeout - Id if the timeout to clear.
|
||||||
* @param {number} interval - Id of the interval to clear.
|
* @param { number } interval - Id of the interval to clear.
|
||||||
* @private
|
* @private
|
||||||
* @copyright Simen Bekkhus 2016
|
* @copyright Simen Bekkhus 2016
|
||||||
* @license MIT
|
* @license MIT
|
||||||
@ -493,16 +505,16 @@ function clearTimers(timeout, interval) {
|
|||||||
* Creates a {@link Promise} that resolves if the passed in function returns a truthy value.
|
* Creates a {@link Promise} that resolves if the passed in function returns a truthy value.
|
||||||
* Rejects if it throws or does not return truthy within the given max_wait.
|
* Rejects if it throws or does not return truthy within the given max_wait.
|
||||||
* @method u#waitUntil
|
* @method u#waitUntil
|
||||||
* @param {Function} func - The function called every check_delay,
|
* @param { Function } func - The function called every check_delay,
|
||||||
* and the result of which is the resolved value of the promise.
|
* and the result of which is the resolved value of the promise.
|
||||||
* @param {number} [max_wait=300] - The time to wait before rejecting the promise.
|
* @param { number } [max_wait=300] - The time to wait before rejecting the promise.
|
||||||
* @param {number} [check_delay=3] - The time to wait before each invocation of {func}.
|
* @param { number } [check_delay=3] - The time to wait before each invocation of {func}.
|
||||||
* @returns {Promise} A promise resolved with the value of func,
|
* @returns {Promise} A promise resolved with the value of func,
|
||||||
* or rejected with the exception thrown by it or it times out.
|
* or rejected with the exception thrown by it or it times out.
|
||||||
* @copyright Simen Bekkhus 2016
|
* @copyright Simen Bekkhus 2016
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
u.waitUntil = function (func, max_wait=300, check_delay=3) {
|
export function waitUntil (func, max_wait=300, check_delay=3) {
|
||||||
// Run the function once without setting up any listeners in case it's already true
|
// Run the function once without setting up any listeners in case it's already true
|
||||||
try {
|
try {
|
||||||
const result = func();
|
const result = func();
|
||||||
@ -620,6 +632,9 @@ export function saveWindowState (ev) {
|
|||||||
|
|
||||||
|
|
||||||
export default Object.assign({
|
export default Object.assign({
|
||||||
|
shouldClearCache,
|
||||||
|
waitUntil, // TODO: remove. Only the API should be used
|
||||||
|
isErrorObject,
|
||||||
getRandomInt,
|
getRandomInt,
|
||||||
getUniqueId,
|
getUniqueId,
|
||||||
isElement,
|
isElement,
|
||||||
|
@ -13,7 +13,7 @@ const tplXformValue = (value) => `<value>${value}</value>`;
|
|||||||
* Takes an HTML DOM and turns it into an XForm field.
|
* Takes an HTML DOM and turns it into an XForm field.
|
||||||
* @private
|
* @private
|
||||||
* @method u#webForm2xForm
|
* @method u#webForm2xForm
|
||||||
* @param { DOMElement } field - the field to convert
|
* @param { Element } field - the field to convert
|
||||||
*/
|
*/
|
||||||
export function webForm2xForm (field) {
|
export function webForm2xForm (field) {
|
||||||
const name = field.getAttribute('name');
|
const name = field.getAttribute('name');
|
||||||
|
@ -4,7 +4,7 @@ import debounce from 'lodash-es/debounce';
|
|||||||
import localDriver from 'localforage-webextensionstorage-driver/local';
|
import localDriver from 'localforage-webextensionstorage-driver/local';
|
||||||
import log from '../log.js';
|
import log from '../log.js';
|
||||||
import syncDriver from 'localforage-webextensionstorage-driver/sync';
|
import syncDriver from 'localforage-webextensionstorage-driver/sync';
|
||||||
import { CORE_PLUGINS } from '../shared/constants.js';
|
import { ANONYMOUS, CORE_PLUGINS, EXTERNAL, LOGIN, PREBIND } from '../shared/constants.js';
|
||||||
import { Connection, MockConnection } from '../shared/connection/index.js';
|
import { Connection, MockConnection } from '../shared/connection/index.js';
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { Strophe } from 'strophe.js/src/strophe';
|
import { Strophe } from 'strophe.js/src/strophe';
|
||||||
@ -43,7 +43,7 @@ export function initConnection () {
|
|||||||
const api = _converse.api;
|
const api = _converse.api;
|
||||||
|
|
||||||
if (! api.settings.get('bosh_service_url')) {
|
if (! api.settings.get('bosh_service_url')) {
|
||||||
if (api.settings.get("authentication") === _converse.PREBIND) {
|
if (api.settings.get("authentication") === PREBIND) {
|
||||||
throw new Error("authentication is set to 'prebind' but we don't have a BOSH connection");
|
throw new Error("authentication is set to 'prebind' but we don't have a BOSH connection");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ function initPersistentStorage (_converse, store_name) {
|
|||||||
|
|
||||||
function saveJIDtoSession (_converse, jid) {
|
function saveJIDtoSession (_converse, jid) {
|
||||||
jid = _converse.session.get('jid') || jid;
|
jid = _converse.session.get('jid') || jid;
|
||||||
if (_converse.api.settings.get("authentication") !== _converse.ANONYMOUS && !Strophe.getResourceFromJid(jid)) {
|
if (_converse.api.settings.get("authentication") !== ANONYMOUS && !Strophe.getResourceFromJid(jid)) {
|
||||||
jid = jid.toLowerCase() + Connection.generateResource();
|
jid = jid.toLowerCase() + Connection.generateResource();
|
||||||
}
|
}
|
||||||
_converse.jid = jid;
|
_converse.jid = jid;
|
||||||
@ -357,7 +357,7 @@ async function getLoginCredentialsFromBrowser () {
|
|||||||
if (!jid) return null;
|
if (!jid) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const creds = await navigator.credentials.get({'password': true});
|
const creds = await navigator.credentials.get({ password: true});
|
||||||
if (creds && creds.type == 'password' && isValidJID(creds.id)) {
|
if (creds && creds.type == 'password' && isValidJID(creds.id)) {
|
||||||
// XXX: We don't actually compare `creds.id` with `jid` because
|
// XXX: We don't actually compare `creds.id` with `jid` because
|
||||||
// the user might have been presented a list of credentials with
|
// the user might have been presented a list of credentials with
|
||||||
@ -387,7 +387,7 @@ async function getLoginCredentialsFromSCRAMKeys () {
|
|||||||
export async function attemptNonPreboundSession (credentials, automatic) {
|
export async function attemptNonPreboundSession (credentials, automatic) {
|
||||||
const { api } = _converse;
|
const { api } = _converse;
|
||||||
|
|
||||||
if (api.settings.get("authentication") === _converse.LOGIN) {
|
if (api.settings.get("authentication") === LOGIN) {
|
||||||
// XXX: If EITHER ``keepalive`` or ``auto_login`` is ``true`` and
|
// XXX: If EITHER ``keepalive`` or ``auto_login`` is ``true`` and
|
||||||
// ``authentication`` is set to ``login``, then Converse will try to log the user in,
|
// ``authentication`` is set to ``login``, then Converse will try to log the user in,
|
||||||
// since we don't have a way to distinguish between wether we're
|
// since we don't have a way to distinguish between wether we're
|
||||||
@ -417,7 +417,7 @@ export async function attemptNonPreboundSession (credentials, automatic) {
|
|||||||
if (!_converse.isTestEnv()) log.warn("attemptNonPreboundSession: Couldn't find credentials to log in with");
|
if (!_converse.isTestEnv()) log.warn("attemptNonPreboundSession: Couldn't find credentials to log in with");
|
||||||
|
|
||||||
} else if (
|
} else if (
|
||||||
[_converse.ANONYMOUS, _converse.EXTERNAL].includes(api.settings.get("authentication")) &&
|
[ANONYMOUS, EXTERNAL].includes(api.settings.get("authentication")) &&
|
||||||
(!automatic || api.settings.get("auto_login"))
|
(!automatic || api.settings.get("auto_login"))
|
||||||
) {
|
) {
|
||||||
connect();
|
connect();
|
||||||
@ -431,7 +431,7 @@ export async function attemptNonPreboundSession (credentials, automatic) {
|
|||||||
* The user's plaintext password is not stored, nor any material from which
|
* The user's plaintext password is not stored, nor any material from which
|
||||||
* the user's plaintext password could be recovered.
|
* the user's plaintext password could be recovered.
|
||||||
*
|
*
|
||||||
* @param { String } JID - The XMPP address for which to fetch the SCRAM keys
|
* @param { String } jid - The XMPP address for which to fetch the SCRAM keys
|
||||||
* @returns { Promise } A promise which resolves once we've fetched the previously
|
* @returns { Promise } A promise which resolves once we've fetched the previously
|
||||||
* used login keys.
|
* used login keys.
|
||||||
*/
|
*/
|
||||||
@ -444,9 +444,16 @@ export async function savedLoginInfo (jid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { Object } [credentials]
|
||||||
|
* @param { string } credentials.password
|
||||||
|
* @param { Object } credentials.password
|
||||||
|
* @param { string } credentials.password.ck
|
||||||
|
* @returns { Promise<void> }
|
||||||
|
*/
|
||||||
async function connect (credentials) {
|
async function connect (credentials) {
|
||||||
const { api } = _converse;
|
const { api } = _converse;
|
||||||
if ([_converse.ANONYMOUS, _converse.EXTERNAL].includes(api.settings.get("authentication"))) {
|
if ([ANONYMOUS, EXTERNAL].includes(api.settings.get("authentication"))) {
|
||||||
if (!_converse.jid) {
|
if (!_converse.jid) {
|
||||||
throw new Error("Config Error: when using anonymous login " +
|
throw new Error("Config Error: when using anonymous login " +
|
||||||
"you need to provide the server's domain via the 'jid' option. " +
|
"you need to provide the server's domain via the 'jid' option. " +
|
||||||
@ -457,7 +464,7 @@ async function connect (credentials) {
|
|||||||
_converse.connection.reset();
|
_converse.connection.reset();
|
||||||
}
|
}
|
||||||
_converse.connection.connect(_converse.jid.toLowerCase());
|
_converse.connection.connect(_converse.jid.toLowerCase());
|
||||||
} else if (api.settings.get("authentication") === _converse.LOGIN) {
|
} else if (api.settings.get("authentication") === LOGIN) {
|
||||||
const password = credentials?.password ?? (_converse.connection?.pass || api.settings.get("password"));
|
const password = credentials?.password ?? (_converse.connection?.pass || api.settings.get("password"));
|
||||||
if (!password) {
|
if (!password) {
|
||||||
if (api.settings.get("auto_login")) {
|
if (api.settings.get("auto_login")) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user