Compile and render Synapse's docs into a browsable, mobile-friendly and searchable website (#10086)
This commit is contained in:
parent
9eea4646be
commit
fd9856e4a9
|
@ -0,0 +1,31 @@
|
||||||
|
name: Deploy the documentation
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pages:
|
||||||
|
name: GitHub Pages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup mdbook
|
||||||
|
uses: peaceiris/actions-mdbook@4b5ef36b314c2599664ca107bb8c02412548d79d # v1.1.14
|
||||||
|
with:
|
||||||
|
mdbook-version: '0.4.9'
|
||||||
|
|
||||||
|
- name: Build the documentation
|
||||||
|
run: mdbook build
|
||||||
|
|
||||||
|
- name: Deploy latest documentation
|
||||||
|
uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
keep_files: true
|
||||||
|
publish_dir: ./book
|
||||||
|
destination_dir: ./develop
|
|
@ -46,3 +46,6 @@ __pycache__/
|
||||||
/docs/build/
|
/docs/build/
|
||||||
/htmlcov
|
/htmlcov
|
||||||
/pip-wheel-metadata/
|
/pip-wheel-metadata/
|
||||||
|
|
||||||
|
# docs
|
||||||
|
book/
|
||||||
|
|
|
@ -40,6 +40,7 @@ exclude mypy.ini
|
||||||
exclude sytest-blacklist
|
exclude sytest-blacklist
|
||||||
exclude test_postgresql.sh
|
exclude test_postgresql.sh
|
||||||
|
|
||||||
|
include book.toml
|
||||||
include pyproject.toml
|
include pyproject.toml
|
||||||
recursive-include changelog.d *
|
recursive-include changelog.d *
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Documentation for possible options in this file is at
|
||||||
|
# https://rust-lang.github.io/mdBook/format/config.html
|
||||||
|
[book]
|
||||||
|
title = "Synapse"
|
||||||
|
authors = ["The Matrix.org Foundation C.I.C."]
|
||||||
|
language = "en"
|
||||||
|
multilingual = false
|
||||||
|
|
||||||
|
# The directory that documentation files are stored in
|
||||||
|
src = "docs"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# Prevent markdown pages from being automatically generated when they're
|
||||||
|
# linked to in SUMMARY.md
|
||||||
|
create-missing = false
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
# The URL visitors will be directed to when they try to edit a page
|
||||||
|
edit-url-template = "https://github.com/matrix-org/synapse/edit/develop/{path}"
|
||||||
|
|
||||||
|
# Remove the numbers that appear before each item in the sidebar, as they can
|
||||||
|
# get quite messy as we nest deeper
|
||||||
|
no-section-label = true
|
||||||
|
|
||||||
|
# The source code URL of the repository
|
||||||
|
git-repository-url = "https://github.com/matrix-org/synapse"
|
||||||
|
|
||||||
|
# The path that the docs are hosted on
|
||||||
|
site-url = "/synapse/"
|
||||||
|
|
||||||
|
# Additional HTML, JS, CSS that's injected into each page of the book.
|
||||||
|
# More information available in docs/website_files/README.md
|
||||||
|
additional-css = [
|
||||||
|
"docs/website_files/table-of-contents.css",
|
||||||
|
"docs/website_files/remove-nav-buttons.css",
|
||||||
|
"docs/website_files/indent-section-headers.css",
|
||||||
|
]
|
||||||
|
additional-js = ["docs/website_files/table-of-contents.js"]
|
||||||
|
theme = "docs/website_files/theme"
|
|
@ -0,0 +1 @@
|
||||||
|
Add initial infrastructure for rendering Synapse documentation with mdbook.
|
|
@ -1,7 +1,72 @@
|
||||||
# Synapse Documentation
|
# Synapse Documentation
|
||||||
|
|
||||||
This directory contains documentation specific to the `synapse` homeserver.
|
**The documentation is currently hosted [here](https://matrix-org.github.io/synapse).**
|
||||||
|
Please update any links to point to the new website instead.
|
||||||
|
|
||||||
All matrix-generic documentation now lives in its own project, located at [matrix-org/matrix-doc](https://github.com/matrix-org/matrix-doc)
|
## About
|
||||||
|
|
||||||
(Note: some items here may be moved to [matrix-org/matrix-doc](https://github.com/matrix-org/matrix-doc) at some point in the future.)
|
This directory currently holds a series of markdown files documenting how to install, use
|
||||||
|
and develop Synapse, the reference Matrix homeserver. The documentation is readable directly
|
||||||
|
from this repository, but it is recommended to instead browse through the
|
||||||
|
[website](https://matrix-org.github.io/synapse) for easier discoverability.
|
||||||
|
|
||||||
|
## Adding to the documentation
|
||||||
|
|
||||||
|
Most of the documentation currently exists as top-level files, as when organising them into
|
||||||
|
a structured website, these files were kept in place so that existing links would not break.
|
||||||
|
The rest of the documentation is stored in folders, such as `setup`, `usage`, and `development`
|
||||||
|
etc. **All new documentation files should be placed in structured folders.** For example:
|
||||||
|
|
||||||
|
To create a new user-facing documentation page about a new Single Sign-On protocol named
|
||||||
|
"MyCoolProtocol", one should create a new file with a relevant name, such as "my_cool_protocol.md".
|
||||||
|
This file might fit into the documentation structure at:
|
||||||
|
|
||||||
|
- Usage
|
||||||
|
- Configuration
|
||||||
|
- User Authentication
|
||||||
|
- Single Sign-On
|
||||||
|
- **My Cool Protocol**
|
||||||
|
|
||||||
|
Given that, one would place the new file under
|
||||||
|
`usage/configuration/user_authentication/single_sign_on/my_cool_protocol.md`.
|
||||||
|
|
||||||
|
Note that the structure of the documentation (and thus the left sidebar on the website) is determined
|
||||||
|
by the list in [SUMMARY.md](SUMMARY.md). The final thing to do when adding a new page is to add a new
|
||||||
|
line linking to the new documentation file:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
- [My Cool Protocol](usage/configuration/user_authentication/single_sign_on/my_cool_protocol.md)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building the documentation
|
||||||
|
|
||||||
|
The documentation is built with [mdbook](https://rust-lang.github.io/mdBook/), and the outline of the
|
||||||
|
documentation is determined by the structure of [SUMMARY.md](SUMMARY.md).
|
||||||
|
|
||||||
|
First, [get mdbook](https://github.com/rust-lang/mdBook#installation). Then, **from the root of the repository**,
|
||||||
|
build the documentation with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdbook build
|
||||||
|
```
|
||||||
|
|
||||||
|
The rendered contents will be outputted to a new `book/` directory at the root of the repository. You can
|
||||||
|
browse the book by opening `book/index.html` in a web browser.
|
||||||
|
|
||||||
|
You can also have mdbook host the docs on a local webserver with hot-reload functionality via:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdbook serve
|
||||||
|
```
|
||||||
|
|
||||||
|
The URL at which the docs can be viewed at will be logged.
|
||||||
|
|
||||||
|
## Configuration and theming
|
||||||
|
|
||||||
|
The look and behaviour of the website is configured by the [book.toml](../book.toml) file
|
||||||
|
at the root of the repository. See
|
||||||
|
[mdbook's documentation on configuration](https://rust-lang.github.io/mdBook/format/config.html)
|
||||||
|
for available options.
|
||||||
|
|
||||||
|
The site can be themed and additionally extended with extra UI and features. See
|
||||||
|
[website_files/README.md](website_files/README.md) for details.
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
- [Welcome and Overview](welcome_and_overview.md)
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
- [Installation](setup/installation.md)
|
||||||
|
- [Using Postgres](postgres.md)
|
||||||
|
- [Configuring a Reverse Proxy](reverse_proxy.md)
|
||||||
|
- [Configuring a Turn Server](turn-howto.md)
|
||||||
|
- [Delegation](delegate.md)
|
||||||
|
|
||||||
|
# Upgrading
|
||||||
|
- [Upgrading between Synapse Versions](upgrading/README.md)
|
||||||
|
- [Upgrading from pre-Synapse 1.0](MSC1711_certificates_FAQ.md)
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
- [Federation](federate.md)
|
||||||
|
- [Configuration](usage/configuration/README.md)
|
||||||
|
- [Homeserver Sample Config File](usage/configuration/homeserver_sample_config.md)
|
||||||
|
- [Logging Sample Config File](usage/configuration/logging_sample_config.md)
|
||||||
|
- [Structured Logging](structured_logging.md)
|
||||||
|
- [User Authentication](usage/configuration/user_authentication/README.md)
|
||||||
|
- [Single-Sign On]()
|
||||||
|
- [OpenID Connect](openid.md)
|
||||||
|
- [SAML]()
|
||||||
|
- [CAS]()
|
||||||
|
- [SSO Mapping Providers](sso_mapping_providers.md)
|
||||||
|
- [Password Auth Providers](password_auth_providers.md)
|
||||||
|
- [JSON Web Tokens](jwt.md)
|
||||||
|
- [Registration Captcha](CAPTCHA_SETUP.md)
|
||||||
|
- [Application Services](application_services.md)
|
||||||
|
- [Server Notices](server_notices.md)
|
||||||
|
- [Consent Tracking](consent_tracking.md)
|
||||||
|
- [URL Previews](url_previews.md)
|
||||||
|
- [User Directory](user_directory.md)
|
||||||
|
- [Message Retention Policies](message_retention_policies.md)
|
||||||
|
- [Pluggable Modules]()
|
||||||
|
- [Third Party Rules]()
|
||||||
|
- [Spam Checker](spam_checker.md)
|
||||||
|
- [Presence Router](presence_router_module.md)
|
||||||
|
- [Media Storage Providers]()
|
||||||
|
- [Workers](workers.md)
|
||||||
|
- [Using `synctl` with Workers](synctl_workers.md)
|
||||||
|
- [Systemd](systemd-with-workers/README.md)
|
||||||
|
- [Administration](usage/administration/README.md)
|
||||||
|
- [Admin API](usage/administration/admin_api/README.md)
|
||||||
|
- [Account Validity](admin_api/account_validity.md)
|
||||||
|
- [Delete Group](admin_api/delete_group.md)
|
||||||
|
- [Event Reports](admin_api/event_reports.md)
|
||||||
|
- [Media](admin_api/media_admin_api.md)
|
||||||
|
- [Purge History](admin_api/purge_history_api.md)
|
||||||
|
- [Purge Rooms](admin_api/purge_room.md)
|
||||||
|
- [Register Users](admin_api/register_api.md)
|
||||||
|
- [Manipulate Room Membership](admin_api/room_membership.md)
|
||||||
|
- [Rooms](admin_api/rooms.md)
|
||||||
|
- [Server Notices](admin_api/server_notices.md)
|
||||||
|
- [Shutdown Room](admin_api/shutdown_room.md)
|
||||||
|
- [Statistics](admin_api/statistics.md)
|
||||||
|
- [Users](admin_api/user_admin_api.md)
|
||||||
|
- [Server Version](admin_api/version_api.md)
|
||||||
|
- [Manhole](manhole.md)
|
||||||
|
- [Monitoring](metrics-howto.md)
|
||||||
|
- [Scripts]()
|
||||||
|
|
||||||
|
# Development
|
||||||
|
- [Contributing Guide](development/contributing_guide.md)
|
||||||
|
- [Code Style](code_style.md)
|
||||||
|
- [Git Usage](dev/git.md)
|
||||||
|
- [Testing]()
|
||||||
|
- [OpenTracing](opentracing.md)
|
||||||
|
- [Synapse Architecture]()
|
||||||
|
- [Log Contexts](log_contexts.md)
|
||||||
|
- [Replication](replication.md)
|
||||||
|
- [TCP Replication](tcp_replication.md)
|
||||||
|
- [Internal Documentation](development/internal_documentation/README.md)
|
||||||
|
- [Single Sign-On]()
|
||||||
|
- [SAML](dev/saml.md)
|
||||||
|
- [CAS](dev/cas.md)
|
||||||
|
- [State Resolution]()
|
||||||
|
- [The Auth Chain Difference Algorithm](auth_chain_difference_algorithm.md)
|
||||||
|
- [Media Repository](media_repository.md)
|
||||||
|
- [Room and User Statistics](room_and_user_statistics.md)
|
||||||
|
- [Scripts]()
|
||||||
|
|
||||||
|
# Other
|
||||||
|
- [Dependency Deprecation Policy](deprecation_policy.md)
|
|
@ -1,28 +1,14 @@
|
||||||
Admin APIs
|
Admin APIs
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
**Note**: The latest documentation can be viewed `here <https://matrix-org.github.io/synapse>`_.
|
||||||
|
See `docs/README.md <../docs/README.md>`_ for more information.
|
||||||
|
|
||||||
|
**Please update links to point to the website instead.** Existing files in this directory
|
||||||
|
are preserved to maintain historical links, but may be moved in the future.
|
||||||
|
|
||||||
This directory includes documentation for the various synapse specific admin
|
This directory includes documentation for the various synapse specific admin
|
||||||
APIs available.
|
APIs available. Updates to the existing Admin API documentation should still
|
||||||
|
be made to these files, but any new documentation files should instead be placed under
|
||||||
|
`docs/usage/administration/admin_api <../docs/usage/administration/admin_api>`_.
|
||||||
|
|
||||||
Authenticating as a server admin
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Many of the API calls in the admin api will require an `access_token` for a
|
|
||||||
server admin. (Note that a server admin is distinct from a room admin.)
|
|
||||||
|
|
||||||
A user can be marked as a server admin by updating the database directly, e.g.:
|
|
||||||
|
|
||||||
.. code-block:: sql
|
|
||||||
|
|
||||||
UPDATE users SET admin = 1 WHERE name = '@foo:bar.com';
|
|
||||||
|
|
||||||
A new server admin user can also be created using the
|
|
||||||
``register_new_matrix_user`` script.
|
|
||||||
|
|
||||||
Finding your user's `access_token` is client-dependent, but will usually be shown in the client's settings.
|
|
||||||
|
|
||||||
Once you have your `access_token`, to include it in a request, the best option is to add the token to a request header:
|
|
||||||
|
|
||||||
``curl --header "Authorization: Bearer <access_token>" <the_rest_of_your_API_request>``
|
|
||||||
|
|
||||||
Fore more details, please refer to the complete `matrix spec documentation <https://matrix.org/docs/spec/client_server/r0.5.0#using-access-tokens>`_.
|
|
||||||
|
|
|
@ -11,4 +11,4 @@ POST /_synapse/admin/v1/delete_group/<group_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
|
@ -7,7 +7,7 @@ The api is:
|
||||||
GET /_synapse/admin/v1/event_reports?from=0&limit=10
|
GET /_synapse/admin/v1/event_reports?from=0&limit=10
|
||||||
```
|
```
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ The api is:
|
||||||
GET /_synapse/admin/v1/event_reports/<report_id>
|
GET /_synapse/admin/v1/event_reports/<report_id>
|
||||||
```
|
```
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ The API is:
|
||||||
GET /_synapse/admin/v1/room/<room_id>/media
|
GET /_synapse/admin/v1/room/<room_id>/media
|
||||||
```
|
```
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
The API returns a JSON body like the following:
|
The API returns a JSON body like the following:
|
||||||
```json
|
```json
|
||||||
|
@ -311,7 +311,7 @@ The following fields are returned in the JSON response body:
|
||||||
* `deleted`: integer - The number of media items successfully deleted
|
* `deleted`: integer - The number of media items successfully deleted
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
If the user re-requests purged remote media, synapse will re-request the media
|
If the user re-requests purged remote media, synapse will re-request the media
|
||||||
from the originating server.
|
from the originating server.
|
||||||
|
|
|
@ -17,7 +17,7 @@ POST /_synapse/admin/v1/purge_history/<room_id>[/<event_id>]
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
By default, events sent by local users are not deleted, as they may represent
|
By default, events sent by local users are not deleted, as they may represent
|
||||||
the only copies of this content in existence. (Events sent by remote users are
|
the only copies of this content in existence. (Events sent by remote users are
|
||||||
|
|
|
@ -24,7 +24,7 @@ POST /_synapse/admin/v1/join/<room_id_or_alias>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
|
|
||||||
|
|
|
@ -443,7 +443,7 @@ with a body of:
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an ``access_token`` for a
|
To use it, you will need to authenticate by providing an ``access_token`` for a
|
||||||
server admin: see [README.rst](README.rst).
|
server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ GET /_synapse/admin/v1/statistics/users/media
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token`
|
To use it, you will need to authenticate by providing an `access_token`
|
||||||
for a server admin: see [README.rst](README.rst).
|
for a server admin: see [Admin API](../../usage/administration/admin_api).
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ GET /_synapse/admin/v2/users/<user_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ with a body of:
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
URL parameters:
|
URL parameters:
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ See also: [Client Server
|
||||||
API Whois](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid).
|
API Whois](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid).
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
It returns a JSON body like the following:
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ with a body of:
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
The erase parameter is optional and defaults to `false`.
|
The erase parameter is optional and defaults to `false`.
|
||||||
An empty body may be passed for backwards compatibility.
|
An empty body may be passed for backwards compatibility.
|
||||||
|
@ -339,7 +339,7 @@ with a body of:
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
The parameter `new_password` is required.
|
The parameter `new_password` is required.
|
||||||
The parameter `logout_devices` is optional and defaults to `true`.
|
The parameter `logout_devices` is optional and defaults to `true`.
|
||||||
|
@ -354,7 +354,7 @@ GET /_synapse/admin/v1/users/<user_id>/admin
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ with a body of:
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
|
|
||||||
## List room memberships of a user
|
## List room memberships of a user
|
||||||
|
@ -398,7 +398,7 @@ GET /_synapse/admin/v1/users/<user_id>/joined_rooms
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -443,7 +443,7 @@ GET /_synapse/admin/v1/users/<user_id>/media
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ GET /_synapse/admin/v2/users/<user_id>/devices
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -659,7 +659,7 @@ POST /_synapse/admin/v2/users/<user_id>/delete_devices
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
|
@ -683,7 +683,7 @@ GET /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -731,7 +731,7 @@ PUT /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
|
@ -760,7 +760,7 @@ DELETE /_synapse/admin/v2/users/<user_id>/devices/<device_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
|
@ -781,7 +781,7 @@ GET /_synapse/admin/v1/users/<user_id>/pushers
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -872,7 +872,7 @@ POST /_synapse/admin/v1/users/<user_id>/shadow_ban
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
|
@ -897,7 +897,7 @@ GET /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -939,7 +939,7 @@ POST /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
A response body like the following is returned:
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
@ -984,7 +984,7 @@ DELETE /_synapse/admin/v1/users/<user_id>/override_ratelimit
|
||||||
```
|
```
|
||||||
|
|
||||||
To use it, you will need to authenticate by providing an `access_token` for a
|
To use it, you will need to authenticate by providing an `access_token` for a
|
||||||
server admin: [Admin API](README.rst)
|
server admin: [Admin API](../../usage/administration/admin_api)
|
||||||
|
|
||||||
An empty JSON dict is returned.
|
An empty JSON dict is returned.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<!--
|
||||||
|
Include the contents of CONTRIBUTING.md from the project root (where GitHub likes it
|
||||||
|
to be)
|
||||||
|
-->
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
{{#include ../../CONTRIBUTING.md}}
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Internal Documentation
|
||||||
|
|
||||||
|
This section covers implementation documentation for various parts of Synapse.
|
||||||
|
|
||||||
|
If a developer is planning to make a change to a feature of Synapse, it can be useful for
|
||||||
|
general documentation of how that feature is implemented to be available. This saves the
|
||||||
|
developer time in place of needing to understand how the feature works by reading the
|
||||||
|
code.
|
||||||
|
|
||||||
|
Documentation that would be more useful for the perspective of a system administrator,
|
||||||
|
rather than a developer who's intending to change to code, should instead be placed
|
||||||
|
under the Usage section of the documentation.
|
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
|
@ -0,0 +1,58 @@
|
||||||
|
<?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"
|
||||||
|
viewBox="0 0 199.7 184.2"
|
||||||
|
version="1.1"
|
||||||
|
id="svg62"
|
||||||
|
sodipodi:docname="mdbook-favicon.svg"
|
||||||
|
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)">
|
||||||
|
<metadata
|
||||||
|
id="metadata68">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs66" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1026"
|
||||||
|
id="namedview64"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="3.2245912"
|
||||||
|
inkscape:cx="84.790185"
|
||||||
|
inkscape:cy="117.96478"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg62" />
|
||||||
|
<style
|
||||||
|
id="style58">
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
svg { fill: white; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<path
|
||||||
|
d="m 189.5,36.8 c 0.2,2.8 0,5.1 -0.6,6.8 L 153,162 c -0.6,2.1 -2,3.7 -4.2,5 -2.2,1.2 -4.4,1.9 -6.7,1.9 H 31.4 c -9.6,0 -15.3,-2.8 -17.3,-8.4 -0.8,-2.2 -0.8,-3.9 0.1,-5.2 0.9,-1.2 2.4,-1.8 4.6,-1.8 H 123 c 7.4,0 12.6,-1.4 15.4,-4.1 2.8,-2.7 5.7,-8.9 8.6,-18.4 L 179.9,22.4 c 1.8,-5.9 1,-11.1 -2.2,-15.6 C 174.5,2.3 169.9,0 164,0 H 72.7 c -1,0 -3.1,0.4 -6.1,1.1 L 66.7,0.7 C 64.5,0.2 62.6,0 61,0.1 c -1.6,0.1 -3,0.5 -4.3,1.4 -1.3,0.9 -2.4,1.8 -3.2,2.8 -0.8,1 -1.5,2.2 -2.3,3.8 -0.8,1.6 -1.4,3 -1.9,4.3 -0.5,1.3 -1.1,2.7 -1.8,4.2 -0.7,1.5 -1.3,2.7 -2,3.7 -0.5,0.6 -1.2,1.5 -2,2.5 -0.8,1 -1.6,2 -2.2,2.8 -0.6,0.8 -0.9,1.5 -1.1,2.2 -0.2,0.7 -0.1,1.8 0.2,3.2 0.3,1.4 0.4,2.4 0.4,3.1 -0.3,3 -1.4,6.9 -3.3,11.6 -1.9,4.7 -3.6,8.1 -5.1,10.1 -0.3,0.4 -1.2,1.3 -2.6,2.7 -1.4,1.4 -2.3,2.6 -2.6,3.7 -0.3,0.4 -0.3,1.5 -0.1,3.4 0.3,1.8 0.4,3.1 0.3,3.8 -0.3,2.7 -1.3,6.3 -3,10.8 -2.406801,6.370944 -3.4,8.2 -5,11 -0.2,0.5 -0.9,1.4 -2,2.8 -1.1,1.4 -1.8,2.5 -2,3.4 -0.2,0.6 -0.1,1.8 0.1,3.4 0.2,1.6 0.2,2.8 -0.1,3.6 -0.6,3 -1.8,6.7 -3.6,11 -1.8,4.3 -3.6,7.9 -5.4,11 -0.5,0.8 -1.1,1.7 -2,2.8 -0.8,1.1 -1.5,2 -2,2.8 -0.5,0.8 -0.8,1.6 -1,2.5 -0.1,0.5 0,1.3 0.4,2.3 0.3,1.1 0.4,1.9 0.4,2.6 -0.1,1.1 -0.2,2.6 -0.5,4.4 -0.2,1.8 -0.4,2.9 -0.4,3.2 -1.8,4.8 -1.7,9.9 0.2,15.2 2.2,6.2 6.2,11.5 11.9,15.8 5.7,4.3 11.7,6.4 17.8,6.4 h 110.7 c 5.2,0 10.1,-1.7 14.7,-5.2 4.6,-3.5 7.7,-7.8 9.2,-12.9 l 33,-108.6 c 1.8,-5.8 1,-10.9 -2.2,-15.5 -1.7,-2.5 -4,-4.2 -7.1,-5.4 z M 38.14858,105.59813 60.882735,41.992545 h 10.8 c 6.340631,0 33.351895,0.778957 70.804135,0.970479 -18.18245,63.254766 0,0 -18.18245,63.254766 -23.00947,-0.10382 -63.362955,-0.6218 -72.55584,-0.51966 -18,0.2 -13.6,-0.1 -13.6,-0.1 z m 80.621,-5.891206 c 15.19043,-50.034423 0,1e-5 15.19043,-50.034423 l -11.90624,-0.13228 2.73304,-9.302941 -44.32863,0.07339 -2.532953,8.036036 -11.321128,-0.18864 -17.955519,51.440073 c 0.02698,0.027 4.954586,0.0514 12.187488,0.0717 l -2.997994,9.804886 c 11.36463,0.0271 1.219679,-0.0736 46.117666,-0.31499 l 2.65246,-9.571696 c 7.08021,0.14819 11.59705,0.13117 12.16138,0.1189 z m -56.149615,-3.855606 13.7,-42.5 h 9.8 l 1.194896,32.99936 23.205109,-32.99936 h 9.9 l -13.6,42.5 h -7.099996 l 12.499996,-35.4 -24.50001,35.4 h -6.799995 l -0.8,-35 -10.8,35 z"
|
||||||
|
id="path60"
|
||||||
|
sodipodi:nodetypes="ccccssccsssccsssccsssssscsssscssscccscscscsccsccccccssssccccccsccsccccccccccccccccccccccccccccc" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
<!--
|
||||||
|
Include the contents of INSTALL.md from the project root without moving it, which may
|
||||||
|
break links around the internet. Additionally, note that SUMMARY.md is unable to
|
||||||
|
directly link to content outside of the docs/ directory. So we use this file as a
|
||||||
|
redirection.
|
||||||
|
-->
|
||||||
|
{{#include ../../INSTALL.md}}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<!--
|
||||||
|
Include the contents of UPGRADE.rst from the project root without moving it, which may
|
||||||
|
break links around the internet. Additionally, note that SUMMARY.md is unable to
|
||||||
|
directly link to content outside of the docs/ directory. So we use this file as a
|
||||||
|
redirection.
|
||||||
|
-->
|
||||||
|
{{#include ../../UPGRADE.rst}}
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Administration
|
||||||
|
|
||||||
|
This section contains information on managing your Synapse homeserver. This includes:
|
||||||
|
|
||||||
|
* Managing users, rooms and media via the Admin API.
|
||||||
|
* Setting up metrics and monitoring to give you insight into your homeserver's health.
|
||||||
|
* Configuring structured logging.
|
|
@ -0,0 +1,29 @@
|
||||||
|
# The Admin API
|
||||||
|
|
||||||
|
## Authenticate as a server admin
|
||||||
|
|
||||||
|
Many of the API calls in the admin api will require an `access_token` for a
|
||||||
|
server admin. (Note that a server admin is distinct from a room admin.)
|
||||||
|
|
||||||
|
A user can be marked as a server admin by updating the database directly, e.g.:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
UPDATE users SET admin = 1 WHERE name = '@foo:bar.com';
|
||||||
|
```
|
||||||
|
|
||||||
|
A new server admin user can also be created using the `register_new_matrix_user`
|
||||||
|
command. This is a script that is located in the `scripts/` directory, or possibly
|
||||||
|
already on your `$PATH` depending on how Synapse was installed.
|
||||||
|
|
||||||
|
Finding your user's `access_token` is client-dependent, but will usually be shown in the client's settings.
|
||||||
|
|
||||||
|
## Making an Admin API request
|
||||||
|
Once you have your `access_token`, you will need to authenticate each request to an Admin API endpoint by
|
||||||
|
providing the token as either a query parameter or a request header. To add it as a request header in cURL:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl --header "Authorization: Bearer <access_token>" <the_rest_of_your_API_request>
|
||||||
|
```
|
||||||
|
|
||||||
|
For more details on access tokens in Matrix, please refer to the complete
|
||||||
|
[matrix spec documentation](https://matrix.org/docs/spec/client_server/r0.6.1#using-access-tokens).
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
This section contains information on tweaking Synapse via the various options in the configuration file. A configuration
|
||||||
|
file should have been generated when you [installed Synapse](../../setup/installation.html).
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Homeserver Sample Configuration File
|
||||||
|
|
||||||
|
Below is a sample homeserver configuration file. The homeserver configuration file
|
||||||
|
can be tweaked to change the behaviour of your homeserver. A restart of the server is
|
||||||
|
generally required to apply any changes made to this file.
|
||||||
|
|
||||||
|
Note that the contents below are *not* intended to be copied and used as the basis for
|
||||||
|
a real homeserver.yaml. Instead, if you are starting from scratch, please generate
|
||||||
|
a fresh config using Synapse by following the instructions in
|
||||||
|
[Installation](../../setup/installation.md).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
{{#include ../../sample_config.yaml}}
|
||||||
|
```
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Logging Sample Configuration File
|
||||||
|
|
||||||
|
Below is a sample logging configuration file. This file can be tweaked to control how your
|
||||||
|
homeserver will output logs. A restart of the server is generally required to apply any
|
||||||
|
changes made to this file.
|
||||||
|
|
||||||
|
Note that the contents below are *not* intended to be copied and used as the basis for
|
||||||
|
a real homeserver.yaml. Instead, if you are starting from scratch, please generate
|
||||||
|
a fresh config using Synapse by following the instructions in
|
||||||
|
[Installation](../../setup/installation.md).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
{{#include ../../sample_log_config.yaml}}
|
||||||
|
``__`
|
|
@ -0,0 +1,15 @@
|
||||||
|
# User Authentication
|
||||||
|
|
||||||
|
Synapse supports multiple methods of authenticating users, either out-of-the-box or through custom pluggable
|
||||||
|
authentication modules.
|
||||||
|
|
||||||
|
Included in Synapse is support for authenticating users via:
|
||||||
|
|
||||||
|
* A username and password.
|
||||||
|
* An email address and password.
|
||||||
|
* Single Sign-On through the SAML, Open ID Connect or CAS protocols.
|
||||||
|
* JSON Web Tokens.
|
||||||
|
* An administrator's shared secret.
|
||||||
|
|
||||||
|
Synapse can additionally be extended to support custom authentication schemes through optional "password auth provider"
|
||||||
|
modules.
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Documentation Website Files and Assets
|
||||||
|
|
||||||
|
This directory contains extra files for modifying the look and functionality of
|
||||||
|
[mdbook](https://github.com/rust-lang/mdBook), the documentation software that's
|
||||||
|
used to generate Synapse's documentation website.
|
||||||
|
|
||||||
|
The configuration options in the `output.html` section of [book.toml](../../book.toml)
|
||||||
|
point to additional JS/CSS in this directory that are added on each page load. In
|
||||||
|
addition, the `theme` directory contains files that overwrite their counterparts in
|
||||||
|
each of the default themes included with mdbook.
|
||||||
|
|
||||||
|
Currently we use these files to generate a floating Table of Contents panel. The code for
|
||||||
|
which was partially taken from
|
||||||
|
[JorelAli/mdBook-pagetoc](https://github.com/JorelAli/mdBook-pagetoc/)
|
||||||
|
before being modified such that it scrolls with the content of the page. This is handled
|
||||||
|
by the `table-of-contents.js/css` files. The table of contents panel only appears on pages
|
||||||
|
that have more than one header, as well as only appearing on desktop-sized monitors.
|
||||||
|
|
||||||
|
We remove the navigation arrows which typically appear on the left and right side of the
|
||||||
|
screen on desktop as they interfere with the table of contents. This is handled by
|
||||||
|
the `remove-nav-buttons.css` file.
|
||||||
|
|
||||||
|
Finally, we also stylise the chapter titles in the left sidebar by indenting them
|
||||||
|
slightly so that they are more visually distinguishable from the section headers
|
||||||
|
(the bold titles). This is done through the `indent-section-headers.css` file.
|
||||||
|
|
||||||
|
More information can be found in mdbook's official documentation for
|
||||||
|
[injecting page JS/CSS](https://rust-lang.github.io/mdBook/format/config.html)
|
||||||
|
and
|
||||||
|
[customising the default themes](https://rust-lang.github.io/mdBook/format/theme/index.html).
|
|
@ -0,0 +1,7 @@
|
||||||
|
/*
|
||||||
|
* Indents each chapter title in the left sidebar so that they aren't
|
||||||
|
* at the same level as the section headers.
|
||||||
|
*/
|
||||||
|
.chapter-item {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
/* Remove the prev, next chapter buttons as they interfere with the
|
||||||
|
* table of contents.
|
||||||
|
* Note that the table of contents only appears on desktop, thus we
|
||||||
|
* only remove the desktop (wide) chapter buttons.
|
||||||
|
*/
|
||||||
|
.nav-wide-wrapper {
|
||||||
|
display: none
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
@media only screen and (max-width:1439px) {
|
||||||
|
.sidetoc {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width:1440px) {
|
||||||
|
main {
|
||||||
|
position: relative;
|
||||||
|
margin-left: 100px !important;
|
||||||
|
}
|
||||||
|
.sidetoc {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
left: calc(100% + (var(--content-max-width))/4 - 140px);
|
||||||
|
position: absolute;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.pagetoc {
|
||||||
|
position: fixed;
|
||||||
|
width: 250px;
|
||||||
|
overflow: auto;
|
||||||
|
right: 20px;
|
||||||
|
height: calc(100% - var(--menu-bar-height));
|
||||||
|
}
|
||||||
|
.pagetoc a {
|
||||||
|
color: var(--fg) !important;
|
||||||
|
display: block;
|
||||||
|
padding: 5px 15px 5px 10px;
|
||||||
|
text-align: left;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.pagetoc a:hover,
|
||||||
|
.pagetoc a.active {
|
||||||
|
background: var(--sidebar-bg) !important;
|
||||||
|
color: var(--sidebar-fg) !important;
|
||||||
|
}
|
||||||
|
.pagetoc .active {
|
||||||
|
background: var(--sidebar-bg);
|
||||||
|
color: var(--sidebar-fg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
const getPageToc = () => document.getElementsByClassName('pagetoc')[0];
|
||||||
|
|
||||||
|
const pageToc = getPageToc();
|
||||||
|
const pageTocChildren = [...pageToc.children];
|
||||||
|
const headers = [...document.getElementsByClassName('header')];
|
||||||
|
|
||||||
|
|
||||||
|
// Select highlighted item in ToC when clicking an item
|
||||||
|
pageTocChildren.forEach(child => {
|
||||||
|
child.addEventHandler('click', () => {
|
||||||
|
pageTocChildren.forEach(child => {
|
||||||
|
child.classList.remove('active');
|
||||||
|
});
|
||||||
|
child.classList.add('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether a node is in the viewport
|
||||||
|
*/
|
||||||
|
function isInViewport(node) {
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a new ToC entry.
|
||||||
|
* Clear any previously highlighted ToC items, set the new one,
|
||||||
|
* and adjust the ToC scroll position.
|
||||||
|
*/
|
||||||
|
function setTocEntry() {
|
||||||
|
let activeEntry;
|
||||||
|
const pageTocChildren = [...getPageToc().children];
|
||||||
|
|
||||||
|
// Calculate which header is the current one at the top of screen
|
||||||
|
headers.forEach(header => {
|
||||||
|
if (window.pageYOffset >= header.offsetTop) {
|
||||||
|
activeEntry = header;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update selected item in ToC when scrolling
|
||||||
|
pageTocChildren.forEach(child => {
|
||||||
|
if (activeEntry.href.localeCompare(child.href) === 0) {
|
||||||
|
child.classList.add('active');
|
||||||
|
} else {
|
||||||
|
child.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let tocEntryForLocation = document.querySelector(`nav a[href="${activeEntry.href}"]`);
|
||||||
|
if (tocEntryForLocation) {
|
||||||
|
const headingForLocation = document.querySelector(activeEntry.hash);
|
||||||
|
if (headingForLocation && isInViewport(headingForLocation)) {
|
||||||
|
// Update ToC scroll
|
||||||
|
const nav = getPageToc();
|
||||||
|
const content = document.querySelector('html');
|
||||||
|
if (content.scrollTop !== 0) {
|
||||||
|
nav.scrollTo({
|
||||||
|
top: tocEntryForLocation.offsetTop - 100,
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
nav.scrollTop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate sidebar on load
|
||||||
|
*/
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
// Only create table of contents if there is more than one header on the page
|
||||||
|
if (headers.length <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an entry in the page table of contents for each header in the document
|
||||||
|
headers.forEach((header, index) => {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
|
||||||
|
// Indent shows hierarchy
|
||||||
|
let indent = '0px';
|
||||||
|
switch (header.parentElement.tagName) {
|
||||||
|
case 'H1':
|
||||||
|
indent = '5px';
|
||||||
|
break;
|
||||||
|
case 'H2':
|
||||||
|
indent = '20px';
|
||||||
|
break;
|
||||||
|
case 'H3':
|
||||||
|
indent = '30px';
|
||||||
|
break;
|
||||||
|
case 'H4':
|
||||||
|
indent = '40px';
|
||||||
|
break;
|
||||||
|
case 'H5':
|
||||||
|
indent = '50px';
|
||||||
|
break;
|
||||||
|
case 'H6':
|
||||||
|
indent = '60px';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tocEntry;
|
||||||
|
if (index == 0) {
|
||||||
|
// Create a bolded title for the first element
|
||||||
|
tocEntry = document.createElement("strong");
|
||||||
|
tocEntry.innerHTML = header.text;
|
||||||
|
} else {
|
||||||
|
// All other elements are non-bold
|
||||||
|
tocEntry = document.createTextNode(header.text);
|
||||||
|
}
|
||||||
|
link.appendChild(tocEntry);
|
||||||
|
|
||||||
|
link.style.paddingLeft = indent;
|
||||||
|
link.href = header.href;
|
||||||
|
pageToc.appendChild(link);
|
||||||
|
});
|
||||||
|
setTocEntry.call();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Handle active headers on scroll, if there is more than one header on the page
|
||||||
|
if (headers.length > 1) {
|
||||||
|
window.addEventListener('scroll', setTocEntry);
|
||||||
|
}
|
|
@ -0,0 +1,312 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
|
||||||
|
<head>
|
||||||
|
<!-- Book generated using mdBook -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
{{#if is_print }}
|
||||||
|
<meta name="robots" content="noindex" />
|
||||||
|
{{/if}}
|
||||||
|
{{#if base_url}}
|
||||||
|
<base href="{{ base_url }}">
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Custom HTML head -->
|
||||||
|
{{> head}}
|
||||||
|
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="description" content="{{ description }}">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
{{#if favicon_svg}}
|
||||||
|
<link rel="icon" href="{{ path_to_root }}favicon.svg">
|
||||||
|
{{/if}}
|
||||||
|
{{#if favicon_png}}
|
||||||
|
<link rel="shortcut icon" href="{{ path_to_root }}favicon.png">
|
||||||
|
{{/if}}
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}css/general.css">
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
|
||||||
|
{{#if print_enable}}
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
|
||||||
|
{{#if copy_fonts}}
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<!-- Highlight.js Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}highlight.css">
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}tomorrow-night.css">
|
||||||
|
<link rel="stylesheet" href="{{ path_to_root }}ayu-highlight.css">
|
||||||
|
|
||||||
|
<!-- Custom theme stylesheets -->
|
||||||
|
{{#each additional_css}}
|
||||||
|
<link rel="stylesheet" href="{{ ../path_to_root }}{{ this }}">
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if mathjax_support}}
|
||||||
|
<!-- MathJax -->
|
||||||
|
<script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||||
|
{{/if}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Provide site root to javascript -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var path_to_root = "{{ path_to_root }}";
|
||||||
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
try {
|
||||||
|
var theme = localStorage.getItem('mdbook-theme');
|
||||||
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||||||
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||||||
|
}
|
||||||
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||||||
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var theme;
|
||||||
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||||||
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
html.classList.remove('no-js')
|
||||||
|
html.classList.remove('{{ default_theme }}')
|
||||||
|
html.classList.add(theme);
|
||||||
|
html.classList.add('js');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Hide / unhide sidebar before it is displayed -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var html = document.querySelector('html');
|
||||||
|
var sidebar = 'hidden';
|
||||||
|
if (document.body.clientWidth >= 1080) {
|
||||||
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||||||
|
sidebar = sidebar || 'visible';
|
||||||
|
}
|
||||||
|
html.classList.remove('sidebar-visible');
|
||||||
|
html.classList.add("sidebar-" + sidebar);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||||||
|
<div class="sidebar-scrollbox">
|
||||||
|
{{#toc}}{{/toc}}
|
||||||
|
</div>
|
||||||
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="page-wrapper" class="page-wrapper">
|
||||||
|
|
||||||
|
<div class="page">
|
||||||
|
{{> header}}
|
||||||
|
<div id="menu-bar-hover-placeholder"></div>
|
||||||
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
||||||
|
<div class="left-buttons">
|
||||||
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||||||
|
<i class="fa fa-paint-brush"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
|
||||||
|
<li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
|
||||||
|
</ul>
|
||||||
|
{{#if search_enabled}}
|
||||||
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="menu-title">{{ book_title }}</h1>
|
||||||
|
|
||||||
|
<div class="right-buttons">
|
||||||
|
{{#if print_enable}}
|
||||||
|
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
|
||||||
|
<i id="print-button" class="fa fa-print"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{#if git_repository_url}}
|
||||||
|
<a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
|
||||||
|
<i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
{{#if git_repository_edit_url}}
|
||||||
|
<a href="{{git_repository_edit_url}}" title="Suggest an edit" aria-label="Suggest an edit">
|
||||||
|
<i id="git-edit-button" class="fa fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if search_enabled}}
|
||||||
|
<div id="search-wrapper" class="hidden">
|
||||||
|
<form id="searchbar-outer" class="searchbar-outer">
|
||||||
|
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||||||
|
</form>
|
||||||
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||||||
|
<div id="searchresults-header" class="searchresults-header"></div>
|
||||||
|
<ul id="searchresults">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||||||
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||||||
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||||||
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="content" class="content">
|
||||||
|
<main>
|
||||||
|
<!-- Page table of contents -->
|
||||||
|
<div class="sidetoc">
|
||||||
|
<nav class="pagetoc"></nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{{ content }}}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
||||||
|
<!-- Mobile navigation buttons -->
|
||||||
|
{{#previous}}
|
||||||
|
<a rel="prev" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
{{/previous}}
|
||||||
|
|
||||||
|
{{#next}}
|
||||||
|
<a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
{{/next}}
|
||||||
|
|
||||||
|
<div style="clear: both"></div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||||||
|
{{#previous}}
|
||||||
|
<a rel="prev" href="{{ path_to_root }}{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||||||
|
<i class="fa fa-angle-left"></i>
|
||||||
|
</a>
|
||||||
|
{{/previous}}
|
||||||
|
|
||||||
|
{{#next}}
|
||||||
|
<a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||||||
|
<i class="fa fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
{{/next}}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if livereload}}
|
||||||
|
<!-- Livereload script (if served using the cli tool) -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var socket = new WebSocket("{{{livereload}}}");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
if (event.data === "reload") {
|
||||||
|
socket.close();
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if google_analytics}}
|
||||||
|
<!-- Google Analytics Tag -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
var localAddrs = ["localhost", "127.0.0.1", ""];
|
||||||
|
// make sure we don't activate google analytics if the developer is
|
||||||
|
// inspecting the book locally...
|
||||||
|
if (localAddrs.indexOf(document.location.hostname) === -1) {
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||||
|
ga('create', '{{google_analytics}}', 'auto');
|
||||||
|
ga('send', 'pageview');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if playground_line_numbers}}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_line_numbers = true;
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if playground_copyable}}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.playground_copyable = true;
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if playground_js}}
|
||||||
|
<script src="{{ path_to_root }}ace.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}editor.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}mode-rust.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}theme-dawn.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if search_js}}
|
||||||
|
<script src="{{ path_to_root }}elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}mark.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}searcher.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<script src="{{ path_to_root }}clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}highlight.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{{ path_to_root }}book.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<!-- Custom JS scripts -->
|
||||||
|
{{#each additional_js}}
|
||||||
|
<script type="text/javascript" src="{{ ../path_to_root }}{{this}}"></script>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#if is_print}}
|
||||||
|
{{#if mathjax_support}}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
MathJax.Hub.Register.StartupHook('End', function() {
|
||||||
|
window.setTimeout(window.print, 100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{else}}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
window.setTimeout(window.print, 100);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Welcome to the documentation repository for Synapse, the reference
|
||||||
|
[Matrix](https://matrix.org) homeserver implementation.
|
Loading…
Reference in New Issue