Compare commits

...

24 Commits

Author SHA1 Message Date
pitchum a461444bed make version (instead of make release) 2023-10-08 13:53:45 +00:00
pitchum 1307f87912 Simplify chapril release process 2023-10-07 08:15:40 +00:00
pitchum 23cf858a02 Add some bash safeguards in README.charpil.md 2023-10-07 08:13:09 +00:00
pitchum b49146b36f [Branding] Customize homepage's text and links + CSS adjustments. 2023-10-07 08:13:09 +00:00
pitchum 8d67dce865 [Branding] Replace Converse's logo with Chapril's logo. 2023-10-07 08:13:07 +00:00
pitchum 543807aa50 Create a README for Chapril's build. 2023-10-07 08:12:53 +00:00
JC Brand 82a8c3f9fc Release 10.1.6 2023-08-31 21:30:48 +02:00
JC Brand 3e680e88d8 Fix import path 2023-08-31 21:20:40 +02:00
JC Brand 005f5374f0 Fixes #3246 2023-08-31 21:20:40 +02:00
JC Brand 79bb8e76ce Fix GIF rendering artifacts related to patching 2023-08-31 21:20:40 +02:00
JC Brand 61192f91d9 Fix GIF rendering issue
Remove the GIF parsing code from this repo and instead add a dependency on gifuct-js.
2023-08-31 21:20:40 +02:00
JC Brand e31d4c7bac Release 10.1.5
Refine the `dist` step by creating a proper temporary file.

I spent a lot of time trying to pinpoint the underlying cause, why
translation chunk files are empty when generating a bundle with newer JS
features (i.e. not pinning preset-env to IE11) but couldn't find it.
2023-06-30 06:38:40 +02:00
JC Brand c30569dfd3 Release 10.1.5
Found another bug while trying to make the release.

Running `npm run nodeps` last breaks dynamic importing of the DayJS
translations. I'm not sure why, I think maybe because of broken `.map`
files.

The fix for now is to move the js-po files out of the way, and then copy
them back in after running `npm run build`.

Hopefully all of this won't be necessary with gettext 0.22 which should
support template literals
2023-06-29 23:41:15 +02:00
JC Brand 5e02b9bd5d Release 10.1.5 (this time hopefully for real)
As I was making the release, I found a bug in the Makefile that still
prevented the locale JSON files from being properly generated.
2023-06-29 23:09:49 +02:00
JC Brand 9114db8764 Release 10.1.5 2023-06-29 22:29:11 +02:00
JC Brand bc7621c25d Updates #3207 - Generate po files in the release checkout
Refactor the Makefile somewhat.

- Rename `make release` to `make version`
- Add `make release-checkout` which checks out the release branch
2023-06-29 22:16:19 +02:00
ssantos ae518aa2c3 Translated using Weblate (Portuguese)
Currently translated at 99.8% (539 of 540 strings)

Translation: Converse.js/Translations
Translate-URL: https://hosted.weblate.org/projects/conversejs/translations/pt/
2023-06-29 21:55:15 +02:00
josé m e4a4b2819c Translated using Weblate (Galician)
Currently translated at 100.0% (540 of 540 strings)

Translation: Converse.js/Translations
Translate-URL: https://hosted.weblate.org/projects/conversejs/translations/gl/
2023-06-29 21:55:15 +02:00
JC Brand 5310021b67 Modernize the i18n code.
- Remove old deprecated API methods `systemLanguage`, `browserLanguage`
  and `userLanguage`.
- Add types via JSDoc
2023-06-29 09:43:53 +02:00
SilverYoCha e18fdd56b1 Fix #3209.
Fixing some technical errors when avoiding importing the `converse` global with bootstrap modal API.
2023-06-27 11:07:35 +02:00
JC Brand 94963662e7 Fix ordering or args 2023-06-25 11:22:16 +02:00
JC Brand 4f14d50f5d Check out depth of 1 when deploying 2023-06-25 11:15:46 +02:00
JC Brand 699ab71f21 Larger sponsor image 2023-06-25 11:13:24 +02:00
JC Brand daeb641530 Postrelease 2023-06-25 11:09:50 +02:00
35 changed files with 488 additions and 920 deletions

View File

@ -1,6 +1,17 @@
# Changelog
## 10.1.3 (2023-06-25)
## 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

View File

@ -2,7 +2,7 @@
*
* An XMPP chat client that runs in the browser.
*
* Version: 10.1.4
* Version: 10.1.6
*
* Copyright: JC Brand 2013-2018
* Except for 3rd party dependencies.

View File

@ -65,10 +65,7 @@ certs:
########################################################################
## Translation machinery
dist/converse-no-dependencies.js: src webpack/webpack.common.js webpack/webpack.nodeps.js @converse/headless node_modules
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.4 dist/converse-no-dependencies.js -c
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
src/i18n/converse.pot: dist/converse-no-dependencies.js
$(GETTEXT) 2>&1 > /dev/null; exit $$?;
@ -85,10 +82,8 @@ po:
########################################################################
## Release management
.PHONY: release
release:
rm -rf release && mkdir release
cd release
.PHONY: version
version:
$(SED) -i '/^export const VERSION_NAME =/s/=.*/= "v$(VERSION)";/' src/headless/shared/constants.js
$(SED) -i '/Version:/s/:.*/: $(VERSION)/' COPYRIGHT
$(SED) -i '/Project-Id-Version:/s/:.*/: Converse.js $(VERSION)\n"/' src/i18n/converse.pot
@ -105,14 +100,18 @@ release:
make po
make dist
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:
git clone git@github.com:conversejs/converse.js.git --depth 1 --branch $(BRANCH) release/
cd release && make dist && npm pack && npm publish
cd release/src/headless && npm pack && npm publish
find ./release/ -name "converse.js-*.tgz" -exec mv {} . \;
find ./release/src/headless -name "converse-headless-*.tgz" -exec mv {} . \;
rm -rf release
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
postrelease:
@ -120,7 +119,7 @@ postrelease:
.PHONY: deploy
deploy:
git clone --branch v$(VERSION) git@github.com:conversejs/converse.js.git $(VERSION)
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
@ -157,6 +156,9 @@ devserver: node_modules
########################################################################
## 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
npm run build
@ -203,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
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
install:: dist

17
README.chapril.md Normal file
View 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?}/
```

View File

@ -1,18 +1,18 @@
# 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.
3. Run `make release VERSION=10.1.4`
3. Run `make version VERSION=10.1.6`
4. Do a `git diff` to check if things look sane.
5. Do a quick manual test with the `dist` files (via `index.html`)
6. `git commit -am "Release 10.1.4"`
7. `git tag -s v10.1.4 -m "Release 10.1.4"`
8. `git push && git push origin v10.1.4`
9. `make publish BRANCH=v10.1.4`
6. `git commit -am "Release 10.1.6"`
7. `git tag -s v10.1.6 -m "Release 10.1.6"`
8. `git push && git push origin v10.1.6`
9. `make publish BRANCH=v10.1.6`
10. Update release page on Github
* Upload tar files
11. Update https://conversejs.org
* `cd /home/conversejs/converse.js`
* `make deploy VERSION=10.1.4`
* `make deploy VERSION=10.1.6`
12. Update the repository on weblate
13. Decide on next release number and run `make postrelease VERSION=10.1.5`
13. Decide on next release number and run `make postrelease VERSION=10.1.7`

View File

@ -28,6 +28,7 @@
});
converse.initialize({
i18n: 'af',
theme: 'dracula',
auto_away: 300,
enable_smacks: true,
@ -39,8 +40,8 @@
muc_show_logs_before_join: true,
notify_all_room_messages: ['discuss@conference.conversejs.org'],
view_mode: 'fullscreen',
websocket_url: 'wss://conversejs.org/xmpp-websocket',
// websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
// websocket_url: 'wss://conversejs.org/xmpp-websocket',
websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
whitelisted_plugins: ['converse-debug'],
// connection_options: { worker: '/dist/shared-connection-worker.js' }
});

View File

@ -48,9 +48,9 @@ copyright = u'2018, JC Brand'
# built documents.
#
# The short X.Y version.
version = '10.1.4'
version = '10.1.6'
# The full version, including alpha/beta/rc tags.
release = '10.1.4'
release = '10.1.6'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -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:
* https://cdn.conversejs.org/10.1.4/dist/converse.min.js
* https://cdn.conversejs.org/10.1.4/dist/converse.min.css
* https://cdn.conversejs.org/10.1.6/dist/converse.min.js
* https://cdn.conversejs.org/10.1.6/dist/converse.min.css
You can include these two URLs inside the *<head>* element of your website
via the *script* and *link* tags:
.. code-block:: html
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/10.1.4/dist/converse.min.css">
<script src="https://cdn.conversejs.org/10.1.4/dist/converse.min.js" charset="utf-8"></script>
<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.6/dist/converse.min.js" charset="utf-8"></script>
Option 2: Download the builds from Github

View File

@ -240,7 +240,7 @@
<div class="sponsors">
<h2>Converse is supported by:</h2>
<ul >
<li><a href="https://bairesdev.com/sponsoring-open-source-projects/?utm_source=conversejs" target="_blank" rel="noopener"><img style="width: 10em" src="/media/logos/bairesdev-primary.png" alt="BairesDev"></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://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://www.keycdn.com?utm_source=conversejs" target="_blank" rel="noopener"><img style="height: 3em" src="/logo/keycdn.svg" alt="KeyCDN"></a></li>

View File

@ -11,17 +11,17 @@
<!-- 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 type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.4/css/font-awesome.min.css" />
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.4/css/website.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.6/css/website.min.css" />
<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="analytics.js"></script>
<!-- *********************************************************************** -->
<![if gte IE 11]>
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.4/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/10.1.4/dist/converse.min.js"></script>
<script src="https://cdn.conversejs.org/10.1.6/dist/converse.min.js"></script>
<![endif]>
</head>
@ -66,7 +66,7 @@
<table id="jslicense-labels1" style="width: 100%">
<tr>
<td>
<a href="https://cdn.conversejs.org/10.1.4/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>
<a href="https://www.mozilla.org/en-US/MPL/2.0/">MPL-2.0</a>

View File

@ -1,20 +1,34 @@
<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">
<circle cx="180" cy="180" r="170" stroke="black" stroke-width="3" fill="white"/>
<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>
<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;"
xml:space="preserve" version="1.1"
viewBox="0 0 376 311" height="20%" width="10rem"
sodipodi:docname="chapril-logo.svg" inkscape:version="0.92.1 r15371">
<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"/>
<metadata id="metadata114">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<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>
</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>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -1,108 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
class="converse-svg-logo"
viewBox="0 0 364 364"
version="1.1"
id="svg13"
sodipodi:docname="conversejs-with-byline.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<metadata
id="metadata19">
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="chapril-logo"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
class="converse-svg-logo"
xml:space="preserve" version="1.1"
viewBox="0 0 376 311" height="20%" width="6rem"
sodipodi:docname="chapril-logo.svg" inkscape:version="0.92.1 r15371">
<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"/>
<metadata id="metadata114">
<rdf:RDF>
<cc:Work
rdf:about="">
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Converse</dc:title>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<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>
</rdf:RDF>
</metadata>
<defs
id="defs17">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 182 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="364 : 182 : 1"
inkscape:persp3d-origin="182 : 121.33333 : 1"
id="perspective2147" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
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>
<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>
<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>

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -2,7 +2,7 @@
"short_name": "Converse",
"name": "Converse Chat",
"description": "Messaging Freedom",
"version": "10.1.4",
"version": "10.1.6",
"categories": ["social"],
"icons": [
{

View File

@ -19,9 +19,9 @@
<script type="text/javascript" src="analytics.js"></script>
<!-- *********************************************************************** -->
<link type="text/css" rel="stylesheet" media="screen" href="https://cdn.conversejs.org/10.1.4/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/10.1.4/dist/converse.min.js"></script>
<script src="https://cdn.conversejs.org/10.1.6/dist/converse.min.js"></script>
</head>
<body id="page-top" data-spy="scroll" class="converse-website">

20
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "converse.js",
"version": "10.1.4",
"version": "10.1.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "converse.js",
"version": "10.1.4",
"version": "10.1.6",
"license": "MPL-2.0",
"workspaces": [
"src/headless"
@ -20,6 +20,7 @@
"dayjs": "^1.11.8",
"dompurify": "^2.3.1",
"favico.js-slevomat": "^0.3.11",
"gifuct-js": "^2.1.2",
"jed": "1.1.1",
"lit": "^2.4.0",
"localforage-webextensionstorage-driver": "^3.0.0",
@ -5612,6 +5613,14 @@
"safe-buffer": "^5.1.1"
}
},
"node_modules/gifuct-js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/gifuct-js/-/gifuct-js-2.1.2.tgz",
"integrity": "sha512-rI2asw77u0mGgwhV3qA+OEgYqaDn5UNqgs+Bx0FGwSpuqfYn+Ir6RQY5ENNQ8SbIiG/m5gVa7CD5RriO4f4Lsg==",
"dependencies": {
"js-binary-schema-parser": "^2.0.3"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -6632,6 +6641,11 @@
"integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==",
"peer": true
},
"node_modules/js-binary-schema-parser": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz",
"integrity": "sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -11235,7 +11249,7 @@
},
"src/headless": {
"name": "@converse/headless",
"version": "10.1.4",
"version": "10.1.6",
"license": "MPL-2.0",
"dependencies": {
"@converse/openpromise": "^0.0.1",

View File

@ -1,6 +1,6 @@
{
"name": "converse.js",
"version": "10.1.4",
"version": "10.1.6",
"description": "Browser based XMPP chat client",
"browser": "dist/converse.js",
"module": "src/index.js",
@ -119,6 +119,7 @@
"dayjs": "^1.11.8",
"dompurify": "^2.3.1",
"favico.js-slevomat": "^0.3.11",
"gifuct-js": "^2.1.2",
"jed": "1.1.1",
"lit": "^2.4.0",
"localforage-webextensionstorage-driver": "^3.0.0",

View File

@ -1,6 +1,6 @@
{
"name": "@converse/headless",
"version": "10.1.4",
"version": "10.1.6",
"description": "Converse.js Headless build",
"author": "JC Brand <jc@opkode.com>",
"contributors": [

View File

@ -1,7 +1,7 @@
import { Strophe } from 'strophe.js/src/strophe';
export const BOSH_WAIT = 59;
export const VERSION_NAME = "v10.1.4";
export const VERSION_NAME = "v10.1.6";
export const STATUS_WEIGHTS = {
offline: 6,

View File

@ -6,7 +6,7 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Converse.js 10.1.4\n"
"Project-Id-Version: Converse.js 10.1.5\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-25 11:01+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

View File

@ -8,15 +8,15 @@ msgstr ""
"Project-Id-Version: Converse.js 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-23 10:10+0200\n"
"PO-Revision-Date: 2023-02-19 20:17+0000\n"
"Last-Translator: nautilusx <translate@disroot.org>\n"
"PO-Revision-Date: 2023-08-16 01:15+0000\n"
"Last-Translator: W L <wl@mailhole.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/conversejs/"
"translations/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"Plural-Forms: nplurals=2; plural=n != 1;t st\n"
"X-Generator: Weblate 4.16-dev\n"
"domain: converse\n"
"lang: de\n"
@ -1380,7 +1380,7 @@ msgstr "Benutzername"
#: dist/converse-no-dependencies.js:99532
msgid "user@domain"
msgstr "user@domain"
msgstr "nutzer@domain"
#: dist/converse-no-dependencies.js:99538
msgid "Disconnected"

View File

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Converse.js 4.0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-23 10:10+0200\n"
"PO-Revision-Date: 2023-02-19 05:39+0000\n"
"PO-Revision-Date: 2023-06-29 05:51+0000\n"
"Last-Translator: \"josé m.\" <correoxm@disroot.org>\n"
"Language-Team: Galician <https://hosted.weblate.org/projects/conversejs/"
"translations/gl/>\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.16-dev\n"
"X-Generator: Weblate 4.18.1\n"
#: dist/converse-no-dependencies.js:29951
msgid "The connection has dropped, attempting to reconnect."
@ -714,9 +714,8 @@ msgid "Affiliation changed"
msgstr "Cambiou a afiliación"
#: dist/converse-no-dependencies.js:77005
#, fuzzy
msgid "role changed"
msgstr "Rol cambiado"
msgstr "rol cambiado"
#: dist/converse-no-dependencies.js:77099
msgid ""

View File

@ -5,53 +5,48 @@
* @description This is the internationalization module
*/
import Jed from 'jed';
import log from "@converse/headless/log.js";
import log from '@converse/headless/log.js';
import { _converse, api, converse, i18n } from '@converse/headless/core.js';
const { dayjs } = converse.env;
let jed_instance;
function detectLocale (library_check) {
/* Determine which locale is supported by the user's system as well
* as by the relevant library (e.g. converse.js or dayjs).
* @param { Function } library_check - Returns a boolean indicating whether
* the locale is supported.
*/
let locale;
if (window.navigator.userLanguage) {
locale = isLocaleAvailable(window.navigator.userLanguage, library_check);
}
if (window.navigator.languages && !locale) {
for (let i=0; i<window.navigator.languages.length && !locale; i++) {
locale = isLocaleAvailable(window.navigator.languages[i], library_check);
}
}
if (window.navigator.browserLanguage && !locale) {
locale = isLocaleAvailable(window.navigator.browserLanguage, library_check);
}
if (window.navigator.language && !locale) {
locale = isLocaleAvailable(window.navigator.language, library_check);
}
if (window.navigator.systemLanguage && !locale) {
locale = isLocaleAvailable(window.navigator.systemLanguage, library_check);
}
return locale || 'en';
}
/**
* @private
* @param { string } locale
* @param { string[] } supported_locales
*/
function isConverseLocale (locale, supported_locales) {
return typeof locale === 'string' && supported_locales.includes(locale);
}
/**
* Determines which locale is supported by the user's system as well
* as by the relevant library (e.g. converse.js or dayjs).
* @private
* @param { string } preferred_locale
* @param { Function } isSupportedByLibrary - Returns a boolean indicating whether
* the locale is supported.
* @returns { string }
*/
function getLocale (preferred_locale, isSupportedByLibrary) {
if (typeof preferred_locale === 'string') {
if (preferred_locale === 'en' || isSupportedByLibrary(preferred_locale)) {
return preferred_locale;
}
if (preferred_locale === 'en' || isSupportedByLibrary(preferred_locale)) {
return preferred_locale;
}
return detectLocale(isSupportedByLibrary) || 'en';
const { languages } = window.navigator;
let locale;
for (let i = 0; i < languages.length && !locale; i++) {
locale = isLocaleAvailable(languages[i], isSupportedByLibrary);
}
return locale || 'en';
}
/* Check whether the locale or sub locale (e.g. en-US, en) is supported.
/**
* Check whether the locale or sub locale (e.g. en-US, en) is supported.
* @private
* @param { String } locale - The locale to check for
* @param { Function } available - Returns a boolean indicating whether the locale is supported
*/
@ -59,49 +54,60 @@ function isLocaleAvailable (locale, available) {
if (available(locale)) {
return locale;
} else {
var sublocale = locale.split("-")[0];
var sublocale = locale.split('-')[0];
if (sublocale !== locale && available(sublocale)) {
return sublocale;
}
}
}
/**
* Given a locale, return the closest locale returned by dayJS
* @private
* @param { string } locale
*/
function getDayJSLocale (locale) {
const dayjs_locale = locale.toLowerCase().replace('_', '-');
return dayjs_locale === 'ug' ? 'ug-cn' : dayjs_locale;
}
/* Fetch the translations for the given local at the given URL.
/**
* Fetch the translations for the given local at the given URL.
* @private
* @method i18n#fetchTranslations
* @param { _converse }
* @returns { Jed }
*/
async function fetchTranslations (_converse) {
async function fetchTranslations () {
const { api, locale } = _converse;
const dayjs_locale = getDayJSLocale(locale);
if (!isConverseLocale(locale, api.settings.get("locales")) || locale === 'en') {
if (!isConverseLocale(locale, api.settings.get('locales')) || locale === 'en') {
return;
}
const { default: data } = await import(/*webpackChunkName: "locales/[request]" */ `../i18n/${locale}/LC_MESSAGES/converse.po`);
const { default: data } = await import(
/*webpackChunkName: "locales/[request]" */ `../i18n/${locale}/LC_MESSAGES/converse.po`
);
await import(/*webpackChunkName: "locales/dayjs/[request]" */ `dayjs/locale/${dayjs_locale}.js`);
dayjs.locale(getLocale(dayjs_locale, l => dayjs.locale(l)));
jed_instance = new Jed(data);
dayjs.locale(getLocale(dayjs_locale, (l) => dayjs.locale(l)));
return new Jed(data);
}
let jed_instance;
/**
* @namespace i18n
*/
Object.assign(i18n, {
/**
* @param { string } preferred_locale
* @param { string[] } available_locales
*/
getLocale (preferred_locale, available_locales) {
return getLocale(preferred_locale, preferred => isConverseLocale(preferred, available_locales));
return getLocale(preferred_locale, (preferred) => isConverseLocale(preferred, available_locales));
},
/**
* @param { string } str - The string to be translated
*/
translate (str) {
if (!jed_instance) {
return Jed.sprintf.apply(Jed, arguments);
@ -120,8 +126,8 @@ Object.assign(i18n, {
} else {
try {
const preferred_locale = api.settings.get('i18n');
_converse.locale = i18n.getLocale(preferred_locale, api.settings.get("locales"));
await fetchTranslations(_converse);
_converse.locale = i18n.getLocale(preferred_locale, api.settings.get('locales'));
jed_instance = await fetchTranslations();
} catch (e) {
log.fatal(e.message);
_converse.locale = 'en';
@ -131,7 +137,7 @@ Object.assign(i18n, {
__ (...args) {
return i18n.translate(...args);
}
},
});
export const __ = i18n.__;

View File

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Converse.js 4.2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-23 10:10+0200\n"
"PO-Revision-Date: 2022-12-15 06:49+0000\n"
"PO-Revision-Date: 2023-06-29 05:51+0000\n"
"Last-Translator: ssantos <ssantos@web.de>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/conversejs/"
"translations/pt/>\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.15-dev\n"
"X-Generator: Weblate 4.18.1\n"
#: dist/converse-no-dependencies.js:29951
msgid "The connection has dropped, attempting to reconnect."
@ -597,14 +597,12 @@ msgstr ""
"recarregar a página para solicitá-los novamente."
#: dist/converse-no-dependencies.js:58367
#, fuzzy
msgid "An error occurred while trying to fetch the command form"
msgstr ""
"Desculpe, ocorreu um erro ao tentar enviar o formulário de configuração."
msgstr "Ocorreu um erro ao tentar enviar o formulário de configuração"
#: dist/converse-no-dependencies.js:58409
msgid "A timeout occurred"
msgstr ""
msgstr "O tempo de espera se esgotou"
#: dist/converse-no-dependencies.js:60849
msgid "Timeout while trying to fetch archived messages."
@ -676,20 +674,19 @@ msgstr "Executar"
#: dist/converse-no-dependencies.js:74179
msgid "Previous"
msgstr ""
msgstr "Anterior"
#: dist/converse-no-dependencies.js:74180
msgid "Next"
msgstr ""
msgstr "Próximo"
#: dist/converse-no-dependencies.js:74181
msgid "Complete"
msgstr ""
msgstr "Completo"
#: dist/converse-no-dependencies.js:76835
#, fuzzy
msgid "Add to Contacts"
msgstr "Adicionar um contato"
msgstr "Adicionar aos Contatos"
#: dist/converse-no-dependencies.js:76845
#: dist/converse-no-dependencies.js:90215
@ -943,27 +940,25 @@ msgstr ""
"programador para obter mais detalhes"
#: dist/converse-no-dependencies.js:79561
#, fuzzy
msgid "Executing"
msgstr "Executar"
msgstr "A executar"
#: dist/converse-no-dependencies.js:79568
#: dist/converse-no-dependencies.js:79573
msgid "Completed"
msgstr ""
msgstr "Completo"
#: dist/converse-no-dependencies.js:79614
#, fuzzy
msgid ""
"An error occurred while trying to cancel the command. See the developer "
"console for details"
msgstr ""
"Desculpe, ocorreu um erro ao tentar executar o comando. Veja o console do "
"programador para obter mais detalhes"
"Ocorreu um erro ao tentar cancelar o comando. Veja o console do programador "
"para obter mais detalhes"
#: dist/converse-no-dependencies.js:79621
msgid "Error: unexpected result"
msgstr ""
msgstr "Erro: resultado inesperado"
#: dist/converse-no-dependencies.js:80123
msgid "Bookmark this groupchat"
@ -1003,9 +998,9 @@ msgid "Bookmarks"
msgstr "Favoritos"
#: dist/converse-no-dependencies.js:80983
#, fuzzy, javascript-format
#, javascript-format
msgid "Bookmark for \"%1$s\""
msgstr "Favoritos"
msgstr "Favorito para \"%1$s\""
#: dist/converse-no-dependencies.js:80984
msgid "Would you like this groupchat to be automatically joined upon startup?"
@ -1112,14 +1107,12 @@ msgid "Image: "
msgstr "Imagem: "
#: dist/converse-no-dependencies.js:89948
#, fuzzy
msgid "Older versions"
msgstr "Versões da mensagem"
msgstr "Versões antigas"
#: dist/converse-no-dependencies.js:89950
#, fuzzy
msgid "No older versions found"
msgstr "Servidor remoto não encontrado"
msgstr "Nenhuma versão anterior encontrada"
#: dist/converse-no-dependencies.js:89950
msgid "Current version"
@ -1499,9 +1492,8 @@ msgstr "Visitante"
#. harmony default export
#: dist/converse-no-dependencies.js:107043
#, fuzzy
msgid "Participant"
msgstr "Participantes"
msgstr "Participante"
#: dist/converse-no-dependencies.js:107043
msgid "Participants"
@ -1814,9 +1806,8 @@ msgid "Configure this groupchat"
msgstr "Configurar essa sala"
#: dist/converse-no-dependencies.js:111026
#, fuzzy
msgid "Change the nickname you're using in this groupchat"
msgstr "Registre um nome para esse bate-papo"
msgstr "Alterar o apelido que usa neste bate-papo"
#: dist/converse-no-dependencies.js:111039
msgid "Invite someone to join this groupchat"
@ -1988,61 +1979,56 @@ msgid "Profile"
msgstr "Perfil"
#: dist/converse-no-dependencies.js:114853
#, fuzzy
msgid "Reset Password"
msgstr "Palavra-passe"
msgstr "Resetar palavra-passe"
#: dist/converse-no-dependencies.js:114891
msgid "The new passwords must match"
msgstr ""
msgstr "As novas palavras-passe devem corresponder"
#: dist/converse-no-dependencies.js:114892
#, fuzzy
msgid "New password"
msgstr "Sem palavra-passe"
msgstr "Nova palavra-passe"
#: dist/converse-no-dependencies.js:114893
#, fuzzy
msgid "Confirm new password"
msgstr "Sem palavra-passe"
msgstr "Confirme a nova palavra-passe"
#: dist/converse-no-dependencies.js:115415
#, fuzzy
msgid "Timeout error"
msgstr "Erro de Expiração"
msgstr "Erro de tempo de espera"
#: dist/converse-no-dependencies.js:115422
msgid "Your server does not support in-band password reset"
msgstr ""
msgstr "O seu servidor não suporta a redefinição de palavra-passe aqui"
#: dist/converse-no-dependencies.js:115429
msgid ""
"Your server responded with an unknown error, check the console for details"
msgstr ""
"O seu servidor respondeu com um erro desconhecido, verifique o console de "
"programador para detalhes"
#: dist/converse-no-dependencies.js:115448
#, fuzzy
msgid "Timeout error while trying to set your password"
msgstr "O tempo esgotou ao tentar definir a afiliação"
msgstr "O tempo esgotou ao tentar definir a sua palavra-passe"
#: dist/converse-no-dependencies.js:115450
msgid "Your server does not allow in-band password reset"
msgstr ""
msgstr "O seu servidor não suporta a redefinição de palavra-passe aqui"
#: dist/converse-no-dependencies.js:115452
#: dist/converse-no-dependencies.js:115454
#, fuzzy
msgid "You are not allowed to change your password"
msgstr "Não está autorizado a criar novas salas de conversação."
msgstr "Não tem permissão para alterar a sua palavra-passe"
#: dist/converse-no-dependencies.js:115456
msgid "Success"
msgstr ""
msgstr "Sucesso"
#: dist/converse-no-dependencies.js:115456
#, fuzzy
msgid "Your new password has been set"
msgstr "Foi criada uma nova sala de conversação"
msgstr "A sua palavra-passe nova foi definida"
#. eslint-disable-line class-methods-use-this
#: dist/converse-no-dependencies.js:116001
@ -2498,9 +2484,8 @@ msgid "Add a new groupchat"
msgstr "Adicionar uma nova sala"
#: dist/converse-no-dependencies.js:126601
#, fuzzy
msgid "Show bookmarked groupchats"
msgstr "Mostrar Salas"
msgstr "Mostrar bate-papos favoritos"
#: dist/converse-no-dependencies.js:127178
#, javascript-format
@ -2513,9 +2498,8 @@ msgid "Add"
msgstr "Adicionar"
#: dist/converse-no-dependencies.js:127683
#, fuzzy
msgid "Group"
msgstr "Grupos"
msgstr "Grupo"
#. eslint-disable-line class-methods-use-this
#: dist/converse-no-dependencies.js:127892
@ -2538,12 +2522,11 @@ msgstr "Clique para ocultar estes contactos"
#. harmony default export
#: dist/converse-no-dependencies.js:128134
msgid "Contacts"
msgstr "Contatos"
msgstr "Contactos"
#: dist/converse-no-dependencies.js:128135
#, fuzzy
msgid "Click to toggle contacts"
msgstr "Clique para ocultar estes contactos"
msgstr "Clique para mostrar/esconder os contatos"
#: dist/converse-no-dependencies.js:128136
msgid "Add a contact"

View File

@ -4,7 +4,7 @@ import log from "@converse/headless/log";
import sizzle from 'sizzle';
import tplAlertComponent from "./templates/modal-alert.js";
import { View } from '@converse/skeletor/src/view.js';
import { addClass, removeElement } from '../../utils/html.js';
import { hasClass, addClass, removeElement, removeClass } from '../../utils/html.js';
import { render } from 'lit';
import './styles/_modal.scss';
@ -43,7 +43,7 @@ const BaseModal = View.extend({
},
onHide () {
u.removeClass('selected', this.trigger_el);
removeClass('selected', this.trigger_el);
!this.persistent && api.modal.remove(this);
},

View File

@ -10,16 +10,14 @@ export class ConverseBrandByline extends CustomElement {
return html`
${is_fullscreen
? html`
<p class="brand-subtitle">${_converse.VERSION_NAME}</p>
<p class="brand-subtitle">
<a target="_blank" rel="nofollow" href="https://conversejs.org">Open Source</a> XMPP chat client
brought to you by <a target="_blank" rel="nofollow" href="https://opkode.com">Opkode</a>
Une messagerie instantanée qui respecte vos libertés et votre vie privée.
</p>
<p class="brand-subtitle">
<a target="_blank" rel="nofollow" href="https://hosted.weblate.org/projects/conversejs/#languages"
>Translate</a
>
it into your own language
Application Web qui s'appuie sur <a target="_blank" rel="nofollow" href="https://conversejs.org">ConverseJS</a>,
un client XMPP conçu par <a target="_blank" rel="nofollow" href="https://opkode.com">Opkode</a>
<br/>
<small>${_converse.VERSION_NAME}</small>
</p>
`
: ''}

View File

@ -8,38 +8,55 @@ export class ConverseBrandLogo extends CustomElement {
render () { // eslint-disable-line class-methods-use-this
const is_fullscreen = api.settings.get('view_mode') === 'fullscreen';
return html`
<a class="brand-heading" href="https://conversejs.org" target="_blank" rel="noopener">
<a class="brand-heading" href="https://chapril.org/XMPP" target="_blank" rel="noopener">
<span class="brand-name-wrapper ${is_fullscreen ? 'brand-name-wrapper--fullscreen' : ''}">
<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>
<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="chapril-logo"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
class="converse-svg-logo"
xml:space="preserve" version="1.1"
viewBox="0 0 376 311" height="20%" width="6rem"
sodipodi:docname="chapril-logo.svg" inkscape:version="0.92.1 r15371">
<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"/>
<metadata id="metadata114">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<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>
</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>
</svg>
<span class="brand-name">
<span class="brand-name__text">converse<span class="subdued">.js</span></span>
${is_fullscreen
? html`
<p class="byline">messaging freedom</p>
`
: ''}
<span class="brand-name__text">Tchat Chapril</span>
</span>
</span>
</a>

View File

@ -28,6 +28,7 @@ export default class ConverseGIFElement extends CustomElement {
constructor () {
super();
this.src = null;
this.autoplay = false;
this.noloop = false;
this.fallback = 'url';
@ -90,8 +91,6 @@ export default class ConverseGIFElement extends CustomElement {
onControlsClicked (ev) {
ev.preventDefault();
if (this.supergif.playing) {
this.supergif.pause();
} else if (this.supergif.frames.length > 0) {

View File

@ -16,6 +16,14 @@ export default class Image extends CustomElement {
}
}
constructor () {
super();
this.src = null;
this.href = null;
this.onImgClick = null;
this.onImgLoad = null;
}
render () {
if (isGIFURL(this.src) && shouldRenderMediaFromURL(this.src, 'image')) {
return tplGif(filterQueryParamsFromURL(this.src), true);

View File

@ -1,22 +1,11 @@
/**
* @copyright Shachaf Ben-Kiki, JC Brand
* @description
* Started as a fork of Shachaf Ben-Kiki's jsgif library
* https://github.com/shachaf/jsgif
* @license MIT License
*/
import Stream from './stream.js';
import log from '@converse/headless/log.js';
import { getOpenPromise } from '@converse/openpromise';
import { parseGIF } from './utils.js';
const DELAY_FACTOR = 10;
import { parseGIF, decompressFrames } from 'gifuct-js';
export default class ConverseGif {
/**
* Creates a new ConverseGif instance
* @param { HTMLElement } el
* @param { import('lit').LitElement } el
* @param { Object } [options]
* @param { Number } [options.width] - The width, in pixels, of the canvas
* @param { Number } [options.height] - The height, in pixels, of the canvas
@ -30,7 +19,8 @@ export default class ConverseGif {
* @param { Number } [options.progress_bar_height=5]
*/
constructor (el, opts) {
this.options = Object.assign({
this.options = Object.assign(
{
width: null,
height: null,
autoplay: true,
@ -38,7 +28,7 @@ export default class ConverseGif {
show_progress_bar: true,
progress_bg_color: 'rgba(0,0,0,0.4)',
progress_color: 'rgba(255,0,22,.8)',
progress_bar_height: 5
progress_bar_height: 5,
},
opts
);
@ -47,25 +37,23 @@ export default class ConverseGif {
this.gif_el = el.querySelector('img');
this.canvas = el.querySelector('canvas');
this.ctx = this.canvas.getContext('2d');
// It's good practice to pre-render to an offscreen canvas
// Offscreen canvas with full gif
this.offscreenCanvas = document.createElement('canvas');
// Offscreen canvas for patches
this.patchCanvas = document.createElement('canvas');
this.ctx_scaled = false;
this.disposal_method = null;
this.disposal_restore_from_idx = null;
this.frame = null;
this.frame_offsets = []; // elements have .x and .y properties
this.frames = [];
this.last_disposal_method = null;
this.last_img = null;
this.load_error = null;
this.playing = this.options.autoplay;
this.transparency = null;
this.frame_delay = null;
this.frame_idx = 0;
this.iteration_count = 0;
this.start = null;
this.hovering = null;
this.frameImageData = null;
this.disposal_restore_from_idx = null;
this.initialize();
}
@ -75,7 +63,7 @@ export default class ConverseGif {
this.setSizes(this.options.width, this.options.height);
}
const data = await this.fetchGIF(this.gif_el.src);
requestAnimationFrame(() => this.startParsing(data));
requestAnimationFrame(() => this.handleGIFResponse(data));
}
initPlayer () {
@ -87,10 +75,10 @@ export default class ConverseGif {
// Show the first frame
this.frame_idx = 0;
this.putFrame(this.frame_idx);
this.renderImage();
if (this.options.autoplay) {
const delay = (this.frames[this.frame_idx]?.delay ?? 0) * DELAY_FACTOR;
const delay = this.frames[this.frame_idx]?.delay ?? 0;
setTimeout(() => this.play(), delay);
}
}
@ -127,18 +115,18 @@ export default class ConverseGif {
* `frame_delay` parameters can also be passed in. The `timestamp`
* parameter comes from `requestAnimationFrame`.
*
* The purpose of this method is to call `putFrame` with the right delay
* The purpose of this method is to call `renderImage` with the right delay
* in order to render the GIF animation.
*
* Note, this method will cause the *next* upcoming frame to be rendered,
* not the current one.
*
* This means `this.frame_idx` will be incremented before calling `this.putFrame`, so
* `putFrame(0)` needs to be called *before* this method, otherwise the
* This means `this.frame_idx` will be incremented before calling `this.renderImage`, so
* `renderImage(0)` needs to be called *before* this method, otherwise the
* animation will incorrectly start from frame #1 (this is done in `initPlayer`).
*
* @param { DOMHighRestTimestamp } timestamp - The timestamp as returned by `requestAnimationFrame`
* @param { DOMHighRestTimestamp } previous_timestamp - The timestamp from the previous iteration of this method.
* @param { DOMHighResTimeStamp } timestamp - The timestamp as returned by `requestAnimationFrame`
* @param { DOMHighResTimeStamp } previous_timestamp - The timestamp from the previous iteration of this method.
* We need this in order to calculate whether we have waited long enough to
* show the next frame.
* @param { Number } frame_delay - The delay (in 1/100th of a second)
@ -148,10 +136,10 @@ export default class ConverseGif {
if (!this.playing) {
return;
}
if ((timestamp - previous_timestamp) < frame_delay) {
this.hovering ? this.drawPauseIcon() : this.putFrame(this.frame_idx);
if (timestamp - previous_timestamp < frame_delay) {
this.hovering ? this.drawPauseIcon() : this.renderImage();
// We need to wait longer
requestAnimationFrame(ts => this.onAnimationFrame(ts, previous_timestamp, frame_delay));
requestAnimationFrame((ts) => this.onAnimationFrame(ts, previous_timestamp, frame_delay));
return;
}
const next_frame = this.getNextFrameNo();
@ -159,9 +147,9 @@ export default class ConverseGif {
return;
}
this.frame_idx = next_frame;
this.putFrame(this.frame_idx);
const delay = (this.frames[this.frame_idx]?.delay || 8) * DELAY_FACTOR;
requestAnimationFrame(ts => this.onAnimationFrame(ts, timestamp, delay));
this.renderImage();
const delay = this.frames[this.frame_idx]?.delay || 8;
requestAnimationFrame((ts) => this.onAnimationFrame(ts, timestamp, delay));
}
setSizes (w, h) {
@ -175,19 +163,6 @@ export default class ConverseGif {
this.offscreenCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
}
setFrameOffset (frame, offset) {
if (!this.frame_offsets[frame]) {
this.frame_offsets[frame] = offset;
return;
}
if (typeof offset.x !== 'undefined') {
this.frame_offsets[frame].x = offset.x;
}
if (typeof offset.y !== 'undefined') {
this.frame_offsets[frame].y = offset.y;
}
}
doShowProgress (pos, length, draw) {
if (draw && this.options.show_progress_bar) {
let height = this.options.progress_bar_height;
@ -207,56 +182,36 @@ export default class ConverseGif {
/**
* Starts parsing the GIF stream data by calling `parseGIF` and passing in
* a map of handler functions.
* @param { String } data - The GIF file data, as returned by the server
* @param {ArrayBuffer} data - The GIF file data, as returned by the server
*/
startParsing (data) {
const stream = new Stream(data);
/**
* @typedef { Object } GIFParserHandlers
* A map of callback functions passed `parseGIF`. These functions are
* called as various parts of the GIF file format are parsed.
* @property { Function } hdr - Callback to handle the GIF header data
* @property { Function } gce - Callback to handle the GIF Graphic Control Extension data
* @property { Function } com - Callback to handle the comment extension block
* @property { Function } img - Callback to handle image data
* @property { Function } eof - Callback once the end of file has been reached
*/
const handler = {
'hdr': this.withProgress(stream, header => this.handleHeader(header)),
'gce': this.withProgress(stream, gce => this.handleGCE(gce)),
'com': this.withProgress(stream, ),
'img': this.withProgress(stream, img => this.doImg(img), true),
'eof': () => this.handleEOF(stream)
};
handleGIFResponse (data) {
try {
parseGIF(stream, handler);
const gif = parseGIF(data);
this.hdr = gif.header;
this.lsd = gif.lsd;
this.setSizes(this.options.width ?? this.lsd.width, this.options.height ?? this.lsd.height);
this.frames = decompressFrames(gif, true);
} catch (err) {
this.showError('parse');
this.showError();
}
this.initPlayer();
!this.options.autoplay && this.drawPlayIcon();
}
drawError () {
this.ctx.fillStyle = 'black';
this.ctx.fillRect(
0,
0,
this.options.width ? this.options.width : this.hdr.width,
this.options.height ? this.options.height : this.hdr.height
);
this.ctx.fillRect(0, 0, this.options.width, this.options.height);
this.ctx.strokeStyle = 'red';
this.ctx.lineWidth = 3;
this.ctx.moveTo(0, 0);
this.ctx.lineTo(
this.options.width ? this.options.width : this.hdr.width,
this.options.height ? this.options.height : this.hdr.height
);
this.ctx.moveTo(0, this.options.height ? this.options.height : this.hdr.height);
this.ctx.lineTo(this.options.width ? this.options.width : this.hdr.width, 0);
this.ctx.lineTo(this.options.width, this.options.height);
this.ctx.moveTo(0, this.options.height);
this.ctx.lineTo(this.options.width, 0);
this.ctx.stroke();
}
showError (errtype) {
this.load_error = errtype;
showError () {
this.load_error = true;
this.hdr = {
width: this.gif_el.width,
height: this.gif_el.height,
@ -266,51 +221,11 @@ export default class ConverseGif {
this.el.requestUpdate();
}
handleHeader (header) {
this.hdr = header;
this.setSizes(
this.options.width ?? this.hdr.width,
this.options.height ?? this.hdr.height
);
}
/**
* Handler for GIF Graphic Control Extension (GCE) data
*/
handleGCE (gce) {
this.pushFrame();
this.clear();
this.frame_delay = gce.delayTime;
this.transparency = gce.transparencyGiven ? gce.transparencyIndex : null;
this.disposal_method = gce.disposalMethod;
}
/**
* Handler for when the end of the GIF's file has been reached
*/
handleEOF (stream) {
this.pushFrame();
this.doDecodeProgress(stream, false);
this.initPlayer();
!this.options.autoplay && this.drawPlayIcon();
}
pushFrame () {
if (!this.frame) return;
this.frames.push({
data: this.frame.getImageData(0, 0, this.hdr.width, this.hdr.height),
delay: this.frame_delay
});
this.frame_offsets.push({ x: 0, y: 0 });
}
doImg (img) {
this.frame = this.frame || this.offscreenCanvas.getContext('2d');
const currIdx = this.frames.length;
//ct = color table, gct = global color table
const ct = img.lctFlag ? img.lct : this.hdr.gct; // TODO: What if neither exists?
manageDisposal (i) {
if (i <= 0) return;
const offscreenContext = this.offscreenCanvas.getContext('2d');
const disposal = this.frames[i - 1].disposalType;
/*
* Disposal method indicates the way in which the graphic is to
* be treated after being displayed.
@ -328,94 +243,75 @@ export default class ConverseGif {
* Importantly, "previous" means the frame state
* after the last disposal of method 0, 1, or 2.
*/
if (currIdx > 0) {
if (this.last_disposal_method === 3) {
// Restore to previous
// If we disposed every frame including first frame up to this point, then we have
// no composited frame to restore to. In this case, restore to background instead.
if (this.disposal_restore_from_idx !== null) {
this.frame.putImageData(this.frames[this.disposal_restore_from_idx].data, 0, 0);
} else {
this.frame.clearRect(
this.last_img.leftPos,
this.last_img.topPos,
this.last_img.width,
this.last_img.height
);
if (i > 1) {
if (disposal === 3) {
// eslint-disable-next-line no-eq-null
if (this.disposal_restore_from_idx != null) {
offscreenContext.putImageData(this.frames[this.disposal_restore_from_idx].data, 0, 0);
}
} else {
this.disposal_restore_from_idx = currIdx - 1;
}
if (this.last_disposal_method === 2) {
// Restore to background color
// Browser implementations historically restore to transparent; we do the same.
// http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079
this.frame.clearRect(
this.last_img.leftPos,
this.last_img.topPos,
this.last_img.width,
this.last_img.height
);
this.disposal_restore_from_idx = i - 1;
}
}
// else, Undefined/Do not dispose.
// frame contains final pixel data from the last frame; do nothing
//Get existing pixels for img region after applying disposal method
const imgData = this.frame.getImageData(img.leftPos, img.topPos, img.width, img.height);
//apply color table colors
img.pixels.forEach((pixel, i) => {
// imgData.data === [R,G,B,A,R,G,B,A,...]
if (pixel !== this.transparency) {
imgData.data[i * 4 + 0] = ct[pixel][0];
imgData.data[i * 4 + 1] = ct[pixel][1];
imgData.data[i * 4 + 2] = ct[pixel][2];
imgData.data[i * 4 + 3] = 255; // Opaque.
}
});
this.frame.putImageData(imgData, img.leftPos, img.topPos);
if (!this.ctx_scaled) {
this.ctx.scale(this.getCanvasScale(), this.getCanvasScale());
this.ctx_scaled = true;
if (disposal === 2) {
// Restore to background color
// Browser implementations historically restore to transparent; we do the same.
// http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079
offscreenContext.clearRect(
this.last_frame.dims.left,
this.last_frame.dims.top,
this.last_frame.dims.width,
this.last_frame.dims.height
);
}
if (!this.last_img) {
// This is the first received image, so we draw it
this.ctx.drawImage(this.offscreenCanvas, 0, 0);
}
this.last_img = img;
}
/**
* Draws a gif frame at a specific index inside the canvas.
* @param { Number } i - The frame index
* @param {boolean} show_pause_on_hover - The frame index
*/
putFrame (i, show_pause_on_hover=true) {
if (!this.frames.length) return
renderImage (show_pause_on_hover = true) {
if (!this.frames.length) return;
i = parseInt(i, 10);
let i = this.frame_idx;
i = parseInt(i.toString(), 10);
if (i > this.frames.length - 1 || i < 0) {
i = 0;
}
const offset = this.frame_offsets[i];
this.offscreenCanvas.getContext('2d').putImageData(this.frames[i].data, offset.x, offset.y);
this.ctx.globalCompositeOperation = 'copy';
this.ctx.drawImage(this.offscreenCanvas, 0, 0);
this.manageDisposal(i);
const frame = this.frames[i];
const patchContext = this.patchCanvas.getContext('2d');
const offscreenContext = this.offscreenCanvas.getContext('2d');
const dims = frame.dims;
if (
!this.frameImageData ||
dims.width != this.frameImageData.width ||
dims.height != this.frameImageData.height
) {
this.patchCanvas.width = dims.width;
this.patchCanvas.height = dims.height;
this.frameImageData = patchContext.createImageData(dims.width, dims.height);
}
// set the patch data as an override
this.frameImageData.data.set(frame.patch);
// draw the patch back over the canvas
patchContext.putImageData(this.frameImageData, 0, 0);
offscreenContext.drawImage(this.patchCanvas, dims.left, dims.top);
const imageData = offscreenContext.getImageData(0, 0, this.offscreenCanvas.width, this.offscreenCanvas.height);
this.ctx.putImageData(imageData, 0, 0);
this.ctx.drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height);
if (show_pause_on_hover && this.hovering) {
this.drawPauseIcon();
}
}
clear () {
this.transparency = null;
this.last_disposal_method = this.disposal_method;
this.disposal_method = null;
this.frame = null;
this.last_frame = frame;
}
/**
@ -423,7 +319,7 @@ export default class ConverseGif {
*/
play () {
this.playing = true;
requestAnimationFrame(ts => this.onAnimationFrame(ts, 0, 0));
requestAnimationFrame((ts) => this.onAnimationFrame(ts, 0, 0));
}
/**
@ -431,113 +327,74 @@ export default class ConverseGif {
*/
pause () {
this.playing = false;
requestAnimationFrame(() => this.drawPlayIcon())
requestAnimationFrame(() => this.drawPlayIcon());
}
drawPauseIcon () {
if (!this.playing) {
return;
}
// Clear the potential play button by re-rendering the current frame
this.putFrame(this.frame_idx, false);
if (!this.playing) return;
this.ctx.globalCompositeOperation = 'source-over';
// Clear the potential play button by re-rendering the current frame
this.renderImage(false);
// Draw dark overlay
this.ctx.fillStyle = 'rgb(0, 0, 0, 0.25)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
const icon_size = this.canvas.height*0.1;
const icon_size = this.canvas.height * 0.1;
// Draw bars
this.ctx.lineWidth = this.canvas.height*0.04;
this.ctx.lineWidth = this.canvas.height * 0.04;
this.ctx.beginPath();
this.ctx.moveTo(this.canvas.width/2-icon_size/2, this.canvas.height/2-icon_size);
this.ctx.lineTo(this.canvas.width/2-icon_size/2, this.canvas.height/2+icon_size);
this.ctx.moveTo(this.canvas.width / 2 - icon_size / 2, this.canvas.height / 2 - icon_size);
this.ctx.lineTo(this.canvas.width / 2 - icon_size / 2, this.canvas.height / 2 + icon_size);
this.ctx.fillStyle = 'rgb(200, 200, 200, 0.75)';
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(this.canvas.width/2+icon_size/2, this.canvas.height/2-icon_size);
this.ctx.lineTo(this.canvas.width/2+icon_size/2, this.canvas.height/2+icon_size);
this.ctx.moveTo(this.canvas.width / 2 + icon_size / 2, this.canvas.height / 2 - icon_size);
this.ctx.lineTo(this.canvas.width / 2 + icon_size / 2, this.canvas.height / 2 + icon_size);
this.ctx.fillStyle = 'rgb(200, 200, 200, 0.75)';
this.ctx.stroke();
// Draw circle
this.ctx.lineWidth = this.canvas.height*0.02;
this.ctx.lineWidth = this.canvas.height * 0.02;
this.ctx.strokeStyle = 'rgb(200, 200, 200, 0.75)';
this.ctx.beginPath();
this.ctx.arc(
this.canvas.width/2,
this.canvas.height/2,
icon_size*1.5,
0,
2*Math.PI
);
this.ctx.arc(this.canvas.width / 2, this.canvas.height / 2, icon_size * 1.5, 0, 2 * Math.PI);
this.ctx.stroke();
}
drawPlayIcon () {
if (this.playing) {
return;
}
if (this.playing) return;
// Clear the potential pause button by re-rendering the current frame
this.putFrame(this.frame_idx, false);
this.ctx.globalCompositeOperation = 'source-over';
this.renderImage(false);
// Draw dark overlay
this.ctx.fillStyle = 'rgb(0, 0, 0, 0.25)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// Draw triangle
const triangle_size = this.canvas.height*0.1;
const triangle_size = this.canvas.height * 0.1;
const region = new Path2D();
region.moveTo(this.canvas.width/2+triangle_size, this.canvas.height/2); // start at the pointy end
region.lineTo(this.canvas.width/2-triangle_size/2, this.canvas.height/2+triangle_size);
region.lineTo(this.canvas.width/2-triangle_size/2, this.canvas.height/2-triangle_size);
region.moveTo(this.canvas.width / 2 + triangle_size, this.canvas.height / 2); // start at the pointy end
region.lineTo(this.canvas.width / 2 - triangle_size / 2, this.canvas.height / 2 + triangle_size);
region.lineTo(this.canvas.width / 2 - triangle_size / 2, this.canvas.height / 2 - triangle_size);
region.closePath();
this.ctx.fillStyle = 'rgb(200, 200, 200, 0.75)';
this.ctx.fill(region);
// Draw circle
const circle_size = triangle_size*1.5;
this.ctx.lineWidth = this.canvas.height*0.02;
const circle_size = triangle_size * 1.5;
this.ctx.lineWidth = this.canvas.height * 0.02;
this.ctx.strokeStyle = 'rgb(200, 200, 200, 0.75)';
this.ctx.beginPath();
this.ctx.arc(
this.canvas.width/2,
this.canvas.height/2,
circle_size,
0,
2*Math.PI
);
this.ctx.arc(this.canvas.width / 2, this.canvas.height / 2, circle_size, 0, 2 * Math.PI);
this.ctx.stroke();
}
doDecodeProgress (stream, draw) {
this.doShowProgress(stream.pos, stream.data.length, draw);
}
/**
* @param{boolean=} draw Whether to draw progress bar or not;
* this is not idempotent because of translucency.
* Note that this means that the text will be unsynchronized
* with the progress bar on non-frames;
* but those are typically so small (GCE etc.) that it doesn't really matter
*/
withProgress (stream, fn, draw) {
return block => {
fn?.(block);
this.doDecodeProgress(stream, draw);
};
}
getCanvasScale () {
let scale;
if (this.options.max_width && this.hdr && this.hdr.width > this.options.max_width) {
scale = this.options.max_width / this.hdr.width;
if (this.options.max_width && this.hdr && this.lsd.width > this.options.max_width) {
scale = this.options.max_width / this.lsd.width;
} else {
scale = 1;
}
@ -547,22 +404,28 @@ export default class ConverseGif {
/**
* Makes an HTTP request to fetch a GIF
* @param { String } url
* @returns { Promise<String> } Returns a promise which resolves with the response data.
* @returns { Promise<ArrayBuffer> } Returns a promise which resolves with the response data.
*/
fetchGIF (url) {
const promise = getOpenPromise();
const h = new XMLHttpRequest();
h.open('GET', url, true);
h.responseType = 'arraybuffer';
h?.overrideMimeType('text/plain; charset=x-user-defined');
h.onload = () => {
if (h.status != 200) {
this.showError('xhr - response');
this.showError();
return promise.reject();
}
promise.resolve(h.response);
};
h.onprogress = (e) => (e.lengthComputable && this.doShowProgress(e.loaded, e.total, true));
h.onerror = () => this.showError('xhr');
h.onprogress = (e) => e.lengthComputable && this.doShowProgress(e.loaded, e.total, true);
h.onerror = (e) => {
log.error(e);
this.showError();
};
h.send();
return promise;
}

View File

@ -1,319 +0,0 @@
/**
* @copyright Shachaf Ben-Kiki and the Converse.js contributors
* @description
* Started as a fork of Shachaf Ben-Kiki's jsgif library
* https://github.com/shachaf/jsgif
* @license MIT License
*/
function bitsToNum (ba) {
return ba.reduce(function (s, n) {
return s * 2 + n;
}, 0);
}
function byteToBitArr (bite) {
const a = [];
for (let i = 7; i >= 0; i--) {
a.push( !! (bite & (1 << i)));
}
return a;
}
function lzwDecode (minCodeSize, data) {
// TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String?
let pos = 0; // Maybe this streaming thing should be merged with the Stream?
function readCode (size) {
let code = 0;
for (let i = 0; i < size; i++) {
if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) {
code |= 1 << i;
}
pos++;
}
return code;
}
const output = [];
const clearCode = 1 << minCodeSize;
const eoiCode = clearCode + 1;
let codeSize = minCodeSize + 1;
let dict = [];
const clear = function () {
dict = [];
codeSize = minCodeSize + 1;
for (let i = 0; i < clearCode; i++) {
dict[i] = [i];
}
dict[clearCode] = [];
dict[eoiCode] = null;
};
let code = clearCode;
let last;
clear();
while (true) { // eslint-disable-line no-constant-condition
last = code;
code = readCode(codeSize);
if (code === clearCode) {
clear();
continue;
}
if (code === eoiCode) break;
if (code < dict.length) {
if (last !== clearCode) {
dict.push(dict[last].concat(dict[code][0]));
}
}
else {
if (code !== dict.length) throw new Error('Invalid LZW code.');
dict.push(dict[last].concat(dict[last][0]));
}
output.push.apply(output, dict[code]);
if (dict.length === (1 << codeSize) && codeSize < 12) {
// If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long.
codeSize++;
}
}
// I don't know if this is technically an error, but some GIFs do it.
//if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.');
return output;
}
function readSubBlocks (st) {
let size, data;
data = '';
do {
size = st.readByte();
data += st.read(size);
} while (size !== 0);
return data;
}
/**
* Parses GIF image color table information
* @param { Stream } st
* @param { Number } entries
*/
function parseCT (st, entries) { // Each entry is 3 bytes, for RGB.
const ct = [];
for (let i = 0; i < entries; i++) {
ct.push(st.readBytes(3));
}
return ct;
}
/**
* Parses GIF image information
* @param { Stream } st
* @param { ByteStream } img
* @param { Function } [callback]
*/
function parseImg (st, img, callback) {
function deinterlace (pixels, width) {
// Of course this defeats the purpose of interlacing. And it's *probably*
// the least efficient way it's ever been implemented. But nevertheless...
const newPixels = new Array(pixels.length);
const rows = pixels.length / width;
function cpRow (toRow, fromRow) {
const fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);
newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));
}
// See appendix E.
const offsets = [0, 4, 2, 1];
const steps = [8, 8, 4, 2];
let fromRow = 0;
for (let pass = 0; pass < 4; pass++) {
for (let toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
cpRow(toRow, fromRow)
fromRow++;
}
}
return newPixels;
}
img.leftPos = st.readUnsigned();
img.topPos = st.readUnsigned();
img.width = st.readUnsigned();
img.height = st.readUnsigned();
const bits = byteToBitArr(st.readByte());
img.lctFlag = bits.shift();
img.interlaced = bits.shift();
img.sorted = bits.shift();
img.reserved = bits.splice(0, 2);
img.lctSize = bitsToNum(bits.splice(0, 3));
if (img.lctFlag) {
img.lct = parseCT(st, 1 << (img.lctSize + 1));
}
img.lzwMinCodeSize = st.readByte();
const lzwData = readSubBlocks(st);
img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData);
if (img.interlaced) { // Move
img.pixels = deinterlace(img.pixels, img.width);
}
callback?.(img);
}
/**
* Parses GIF header information
* @param { Stream } st
* @param { Function } [callback]
*/
function parseHeader (st, callback) {
const hdr = {};
hdr.sig = st.read(3);
hdr.ver = st.read(3);
if (hdr.sig !== 'GIF') {
throw new Error('Not a GIF file.');
}
hdr.width = st.readUnsigned();
hdr.height = st.readUnsigned();
const bits = byteToBitArr(st.readByte());
hdr.gctFlag = bits.shift();
hdr.colorRes = bitsToNum(bits.splice(0, 3));
hdr.sorted = bits.shift();
hdr.gctSize = bitsToNum(bits.splice(0, 3));
hdr.bgColor = st.readByte();
hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64
if (hdr.gctFlag) {
hdr.gct = parseCT(st, 1 << (hdr.gctSize + 1));
}
callback?.(hdr);
}
function parseExt (st, block, handler) {
function parseGCExt (block) {
st.readByte(); // blocksize, always 4
const bits = byteToBitArr(st.readByte());
block.reserved = bits.splice(0, 3); // Reserved; should be 000.
block.disposalMethod = bitsToNum(bits.splice(0, 3));
block.userInput = bits.shift();
block.transparencyGiven = bits.shift();
block.delayTime = st.readUnsigned();
block.transparencyIndex = st.readByte();
block.terminator = st.readByte();
handler?.gce(block);
}
function parseComExt (block) {
block.comment = readSubBlocks(st);
handler.com && handler.com(block);
}
function parsePTExt (block) {
// No one *ever* uses this. If you use it, deal with parsing it yourself.
st.readByte(); // blocksize, always 12
block.ptHeader = st.readBytes(12);
block.ptData = readSubBlocks(st);
handler.pte && handler.pte(block);
}
function parseAppExt (block) {
function parseNetscapeExt (block) {
st.readByte(); // blocksize, always 3
block.unknown = st.readByte(); // ??? Always 1? What is this?
block.iterations = st.readUnsigned();
block.terminator = st.readByte();
handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block);
}
function parseUnknownAppExt (block) {
block.appData = readSubBlocks(st);
// FIXME: This won't work if a handler wants to match on any identifier.
handler.app && handler.app[block.identifier] && handler.app[block.identifier](block);
}
st.readByte(); // blocksize, always 11
block.identifier = st.read(8);
block.authCode = st.read(3);
switch (block.identifier) {
case 'NETSCAPE':
parseNetscapeExt(block);
break;
default:
parseUnknownAppExt(block);
break;
}
}
function parseUnknownExt (block) {
block.data = readSubBlocks(st);
handler.unknown && handler.unknown(block);
}
block.label = st.readByte();
switch (block.label) {
case 0xF9:
block.extType = 'gce';
parseGCExt(block);
break;
case 0xFE:
block.extType = 'com';
parseComExt(block);
break;
case 0x01:
block.extType = 'pte';
parsePTExt(block);
break;
case 0xFF:
block.extType = 'app';
parseAppExt(block);
break;
default:
block.extType = 'unknown';
parseUnknownExt(block);
break;
}
}
/**
* @param { Stream } st
* @param { GIFParserHandlers } handler
*/
function parseBlock (st, handler) {
const block = {}
block.sentinel = st.readByte();
switch (String.fromCharCode(block.sentinel)) { // For ease of matching
case '!':
block.type = 'ext';
parseExt(st, block, handler);
break;
case ',':
block.type = 'img';
parseImg(st, block, handler?.img);
break;
case ';':
block.type = 'eof';
handler?.eof(block);
break;
default:
throw new Error('Unknown block: 0x' + block.sentinel.toString(16)); // TODO: Pad this with a 0.
}
if (block.type !== 'eof') setTimeout(() => parseBlock(st, handler), 0);
}
/**
* Takes a Stream and parses it for GIF data, calling the relevant handler
* methods on the passed in `handler` object.
* @param { Stream } st
* @param { GIFParserHandlers } handler
*/
export function parseGIF (st, handler={}) {
parseHeader(st, handler?.hdr);
setTimeout(() => parseBlock(st, handler), 0);
}

View File

@ -283,11 +283,6 @@ export class RichText extends String {
/**
* Parse the text and add template references for rendering the "rich" parts.
*
* @param { RichText } text
* @param { Boolean } show_images - Should URLs of images be rendered as `<img>` tags?
* @param { Function } onImgLoad
* @param { Function } onImgClick
**/
async addTemplates () {
/**

View File

@ -50,8 +50,10 @@
.brand-heading {
display: inline-flex;
flex-direction: row;
align-items: flex-start;
flex-direction: column;
flex-wrap: wrap;
justify-content: center;
align-items: center;
font-family: var(--branding-font);
color: var(--link-color);
margin-bottom: 0.75em;
@ -67,7 +69,6 @@
display: flex;
flex-direction: column;
align-items: center;
margin-top: -0.25em;
.byline {
font-family: var(--heading-font);
@ -119,7 +120,7 @@
font-family: var(--heading-font);
font-size: 0.25em;
opacity: 0.55;
margin-left: -7em;
max-width: 350px;
word-spacing: 5px;
}
}

View File

@ -32,7 +32,6 @@
}
.badge-secondary {
color: white;
background-color: var(--secondary-color);
border-color: var(--secondary-color);
&:hover {

View File

@ -236,14 +236,20 @@ u.getLastChildElement = function (el, selector = '*') {
return last_el;
};
u.hasClass = function (className, el) {
return el instanceof Element && el.classList.contains(className);
};
u.toggleClass = function (className, el) {
u.hasClass(className, el) ? removeClass(className, el) : addClass(className, el);
};
/**
* Has an element a class?
* @method u#hasClass
* @param { string } className
* @param { Element } el
*/
export function hasClass (className, el) {
return el instanceof Element && el.classList.contains(className);
}
/**
* Add a class to an element.
* @method u#addClass
@ -615,6 +621,7 @@ u.xForm2TemplateResult = function (field, stanza, options={}) {
};
Object.assign(u, {
hasClass,
addClass,
ancestor,
getOOBURLMarkup,

View File

@ -11,6 +11,11 @@
"target": "es2016",
"module": "esnext",
"lib": [
"ES2020",
"dom"
],
"allowJs": true,
"checkJs": true,