From f730987da68fd741facf184c18d1e029e1ad27a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:49:38 +0100 Subject: [PATCH 1/7] Clarify format of string type for `m.login.terms_params` (#1979) --- changelogs/client_server/newsfragments/1979.clarification | 1 + data/api/client-server/definitions/m.login.terms_params.yaml | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelogs/client_server/newsfragments/1979.clarification diff --git a/changelogs/client_server/newsfragments/1979.clarification b/changelogs/client_server/newsfragments/1979.clarification new file mode 100644 index 00000000..bdcce777 --- /dev/null +++ b/changelogs/client_server/newsfragments/1979.clarification @@ -0,0 +1 @@ +Clarify formats of string types. diff --git a/data/api/client-server/definitions/m.login.terms_params.yaml b/data/api/client-server/definitions/m.login.terms_params.yaml index 67001c18..50c9da43 100644 --- a/data/api/client-server/definitions/m.login.terms_params.yaml +++ b/data/api/client-server/definitions/m.login.terms_params.yaml @@ -50,6 +50,7 @@ properties: arbitrary string with no specified maximum length. url: type: string + format: uri description: | A link to the text of this document, in the appropriate language. MUST be a valid URI with scheme `https://` or From e0bd0543739910cc78a7aca78a632487a0e3aa96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:14:24 +0100 Subject: [PATCH 2/7] Clarify formats of string types for the `POST /_matrix/client/v3/login` endpoint (#1980) Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- changelogs/client_server/newsfragments/1980.clarification | 1 + data/api/client-server/login.yaml | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 changelogs/client_server/newsfragments/1980.clarification diff --git a/changelogs/client_server/newsfragments/1980.clarification b/changelogs/client_server/newsfragments/1980.clarification new file mode 100644 index 00000000..bdcce777 --- /dev/null +++ b/changelogs/client_server/newsfragments/1980.clarification @@ -0,0 +1 @@ +Clarify formats of string types. diff --git a/data/api/client-server/login.yaml b/data/api/client-server/login.yaml index 385eb33b..28de0be1 100644 --- a/data/api/client-server/login.yaml +++ b/data/api/client-server/login.yaml @@ -172,6 +172,8 @@ paths: properties: user_id: type: string + format: mx-user-id + pattern: "^@" description: The fully-qualified Matrix ID for the account. access_token: type: string @@ -197,6 +199,7 @@ paths: x-addedInMatrixVersion: "1.3" home_server: type: string + format: mx-server-name deprecated: true description: |- The server_name of the homeserver on which the account has From 6cd7038d010f7c9369d5b3ca10c6d2089b03397c Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Wed, 6 Nov 2024 12:28:47 +0100 Subject: [PATCH 3/7] Clarify that the async upload endpoint will return 404 in some cases (#1983) --- .../newsfragments/1983.clarification | 1 + data/api/client-server/content-repo.yaml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 changelogs/client_server/newsfragments/1983.clarification diff --git a/changelogs/client_server/newsfragments/1983.clarification b/changelogs/client_server/newsfragments/1983.clarification new file mode 100644 index 00000000..764372f8 --- /dev/null +++ b/changelogs/client_server/newsfragments/1983.clarification @@ -0,0 +1 @@ +Clarify that the async upload endpoint will return 404 in some cases. diff --git a/data/api/client-server/content-repo.yaml b/data/api/client-server/content-repo.yaml index b6feba61..c64a914b 100644 --- a/data/api/client-server/content-repo.yaml +++ b/data/api/client-server/content-repo.yaml @@ -126,6 +126,25 @@ paths: "errcode": "M_FORBIDDEN", "error": "Cannot upload this content" } + "404": + description: |- + The user has provided an invalid MXC ID. Some reasons for this error include: + + - The MXC ID was not created with [POST /_matrix/media/v1/create](/client-server-api/#post_matrixmediav1create). + - The MXC ID has expired. + + A [standard error response](/client-server-api/#standard-error-response) + will be returned with the `errcode` `M_NOT_FOUND`. + content: + application/json: + schema: + $ref: definitions/errors/error.yaml + examples: + response: + value: { + "errcode": "M_NOT_FOUND", + "error": "Unknown media ID" + } "409": description: |- The endpoint was called with a media ID that already has content. A From 909c4614ac8edcb3a7b45d718ab8aa4f6de9cddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:16:34 +0100 Subject: [PATCH 4/7] Clarify formats of string types for the `GET /.well-known/matrix/support` endpoint (#1978) --- changelogs/client_server/newsfragments/1978.clarification | 1 + data/api/client-server/support.yaml | 4 ++++ data/string-formats.yaml | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 changelogs/client_server/newsfragments/1978.clarification diff --git a/changelogs/client_server/newsfragments/1978.clarification b/changelogs/client_server/newsfragments/1978.clarification new file mode 100644 index 00000000..bdcce777 --- /dev/null +++ b/changelogs/client_server/newsfragments/1978.clarification @@ -0,0 +1 @@ +Clarify formats of string types. diff --git a/data/api/client-server/support.yaml b/data/api/client-server/support.yaml index 1598d5d7..b9ca062e 100644 --- a/data/api/client-server/support.yaml +++ b/data/api/client-server/support.yaml @@ -54,6 +54,8 @@ paths: properties: matrix_id: type: string + format: mx-user-id + pattern: "^@" description: |- A [Matrix User ID](/appendices/#user-identifiers) representing the administrator. @@ -66,6 +68,7 @@ paths: required. email_address: type: string + format: email description: |- An email address to reach the administrator. @@ -95,6 +98,7 @@ paths: } support_page: type: string + format: uri description: |- The URL of a page to give users help specific to the homeserver, like extra login/registration steps. diff --git a/data/string-formats.yaml b/data/string-formats.yaml index e4ebc523..4ffe219c 100644 --- a/data/string-formats.yaml +++ b/data/string-formats.yaml @@ -64,3 +64,7 @@ mx-mxc-uri: uri: title: URI url: https://datatracker.ietf.org/doc/html/rfc3986 + +email: + title: Email Address + url: https://datatracker.ietf.org/doc/html/rfc5321#section-4.1.2 From 74e8be3fd9fbb2e978f0d0f829b528f6478cb4e2 Mon Sep 17 00:00:00 2001 From: Johannes Marbach Date: Thu, 7 Nov 2024 15:56:53 +0100 Subject: [PATCH 5/7] Clarify that pusher URLs have a fixed path (#1974) Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- changelogs/push_gateway/newsfragments/1974.clarification | 1 + data/api/push-gateway/push_notifier.yaml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 changelogs/push_gateway/newsfragments/1974.clarification diff --git a/changelogs/push_gateway/newsfragments/1974.clarification b/changelogs/push_gateway/newsfragments/1974.clarification new file mode 100644 index 00000000..46c086a9 --- /dev/null +++ b/changelogs/push_gateway/newsfragments/1974.clarification @@ -0,0 +1 @@ +The path of HTTP pusher URLs is fixed to `/_matrix/push/v1/notify`. diff --git a/data/api/push-gateway/push_notifier.yaml b/data/api/push-gateway/push_notifier.yaml index fda29da7..9f461a1c 100644 --- a/data/api/push-gateway/push_notifier.yaml +++ b/data/api/push-gateway/push_notifier.yaml @@ -35,9 +35,9 @@ paths: updating counts of unread notifications should be idempotent and therefore do not require duplicate suppression. - Notifications are sent to the URL configured when the pusher is created. - This means that the HTTP path may be different depending on the push - gateway. + Clients interested in receiving notifications via this endpoint MUST + configure its full URI when creating the associated pusher via + [`/_matrix/client/v3/pushers/set`](/client-server-api/#post_matrixclientv3pushersset). operationId: notify requestBody: content: From 9799b892de63cf8d762ff27548f681fc91635ea5 Mon Sep 17 00:00:00 2001 From: "DeepBlueV7.X" Date: Tue, 12 Nov 2024 23:24:20 +0100 Subject: [PATCH 6/7] Clarify parameter definition for third-party location lookups (#1947) While 14051847653383e432ebacae2cc430cc9ebce1e0 redefined most fields to be the appropriate object type, it missed one of them. Signed-off-by: Nicolas Werner --- changelogs/client_server/newsfragments/1947.clarification | 1 + data/api/client-server/third_party_lookup.yaml | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changelogs/client_server/newsfragments/1947.clarification diff --git a/changelogs/client_server/newsfragments/1947.clarification b/changelogs/client_server/newsfragments/1947.clarification new file mode 100644 index 00000000..3764243a --- /dev/null +++ b/changelogs/client_server/newsfragments/1947.clarification @@ -0,0 +1 @@ +Correct OpenAPI specification for query parameters to `GET /_matrix/client/v3/thirdparty/location/{protocol}` endpoint. diff --git a/data/api/client-server/third_party_lookup.yaml b/data/api/client-server/third_party_lookup.yaml index 97547a6f..3055b8ae 100644 --- a/data/api/client-server/third_party_lookup.yaml +++ b/data/api/client-server/third_party_lookup.yaml @@ -98,12 +98,14 @@ paths: schema: type: string - in: query - name: searchFields + name: fields description: |- One or more custom fields to help identify the third-party location. schema: - type: string + type: object + additionalProperties: + type: string responses: "200": description: At least one portal room was found. From b1f66d1b71157b93f0fe418ed9cd732eb91185d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= <76261501+zecakeh@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:53:46 +0100 Subject: [PATCH 7/7] Improve the JS script to highlight the current ToC entry (#1991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code relied on an IntersectionOberver, so the ToC was only updated when a heading was in the viewport. It meant that if we jumped to a part of the text that has no heading, the ToC would still point to the old entry. The new code looks for the correct heading when the view is scrolled so the correct entry is always selected. Signed-off-by: Kévin Commaille --- .../internal/newsfragments/1991.clarification | 1 + layouts/partials/hooks/body-end.html | 13 +- static/js/toc.js | 235 +++++++++--------- 3 files changed, 128 insertions(+), 121 deletions(-) create mode 100644 changelogs/internal/newsfragments/1991.clarification diff --git a/changelogs/internal/newsfragments/1991.clarification b/changelogs/internal/newsfragments/1991.clarification new file mode 100644 index 00000000..5f641bff --- /dev/null +++ b/changelogs/internal/newsfragments/1991.clarification @@ -0,0 +1 @@ +Improve the JS script to highlight the current ToC entry. diff --git a/layouts/partials/hooks/body-end.html b/layouts/partials/hooks/body-end.html index 377470d9..f975eddf 100644 --- a/layouts/partials/hooks/body-end.html +++ b/layouts/partials/hooks/body-end.html @@ -2,16 +2,9 @@ This template is included at the end of each page's ``. - We're using it here to: - - 1) include the JS that generates the table of contents. It would be better - to generate the table of contents as part of the Hugo build process, but - that doesn't work nicely with the way we want to author client-server modules - as separate files. - - 2) highlight and scroll the ToC in the sidebar to match the place we are at - in the document. + We're using it here to highlight and scroll the ToC in the sidebar to match + the place we are at in the document. */}} - + diff --git a/static/js/toc.js b/static/js/toc.js index 786ec6c6..af8682b3 100644 --- a/static/js/toc.js +++ b/static/js/toc.js @@ -15,18 +15,122 @@ limitations under the License. */ /* -Set a new ToC entry. -Clear any previously highlighted ToC items, set the new one, -and adjust the ToC scroll position. + Only call the given function once every 250 milliseconds to avoid impacting + the performance of the browser. + Source: https://remysharp.com/2010/07/21/throttling-function-calls */ -function setTocEntry(newEntry) { - const activeEntries = document.querySelectorAll("#toc a.active"); +function throttle(fn) { + const threshold = 250; + let last = null; + let deferTimer = null; + + return function (...args) { + const now = new Date(); + + if (last && now < last + threshold) { + // Hold on to it. + clearTimeout(deferTimer); + deferTimer = setTimeout(() => { + last = now; + fn.apply(this, args); + }, threshold); + } else { + last = now; + fn.apply(this, args); + } + } +} + +/* + Get the list of headings that appear in the ToC. + This is not as simple as querying all the headings in the content, because + some headings are not rendered in the ToC (e.g. in the endpoint definitions). +*/ +function getHeadings() { + let headings = []; + + // First get the anchors in the ToC. + const toc_anchors = document.querySelectorAll("#toc nav a"); + + for (const anchor of toc_anchors) { + // Then get the heading from its selector in the anchor's href. + const selector = anchor.getAttribute("href"); + if (!selector) { + console.error("Got ToC anchor without href"); + continue; + } + + const heading = document.querySelector(selector); + if (!heading) { + console.error("Heading not found for selector:", selector); + continue; + } + + headings.push(heading); + } + + return headings; +} + +/* + Get the heading of the text visible at the top of the viewport. + This is the first heading above or at the top of the viewport. +*/ +function getCurrentHeading(headings, headerOffset) { + const scrollTop = document.documentElement.scrollTop; + let prevHeading = null; + let currentHeading = null; + let index = 0; + + for (const heading of headings) { + // Compute the position compared to the viewport. + const rect = heading.getBoundingClientRect(); + + if (rect.top >= headerOffset && rect.top <= headerOffset + 30) { + // This heading is at the top of the viewport, this is the current heading. + currentHeading = heading; + break; + } + if (rect.top >= headerOffset) { + // This is in or below the viewport, the current heading should be the + // previous one. + if (prevHeading) { + currentHeading = prevHeading; + } else { + // The first heading does not have a prevHeading. + currentHeading = heading; + } + break; + } + + prevHeading = heading; + index += 1; + } + + return currentHeading; +} + +/* + Select the ToC entry that points to the given ID. + Clear any previously highlighted ToC items, select the new one, + and adjust the ToC scroll position. +*/ +function selectTocEntry(id) { + // Deselect previously selected entries. + const activeEntries = document.querySelectorAll("#toc nav a.active"); for (const activeEntry of activeEntries) { activeEntry.classList.remove('active'); } + // Find the new entry and select it. + const newEntry = document.querySelector(`#toc nav a[href="#${id}"]`); + if (!newEntry) { + console.error("ToC entry not found for ID:", id); + return; + } newEntry.classList.add('active'); - // don't scroll the sidebar nav if the main content is not scrolled + + // Don't scroll the sidebar nav if the main content is not scrolled const nav = document.querySelector("#td-section-nav"); const content = document.querySelector("html"); if (content.scrollTop !== 0) { @@ -37,115 +141,24 @@ function setTocEntry(newEntry) { } /* -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) - ); -} - -/* -The callback we pass to the IntersectionObserver constructor. - -Called when any of our observed nodes starts or stops intersecting -with the viewport. -*/ -function handleIntersectionUpdate(entries) { - - /* - Special case: If the current URL hash matches a ToC entry, and - the corresponding heading is visible in the viewport, then that is - made the current ToC entry, and we don't even look at the intersection - observer data. - This means that if the user has clicked on a ToC entry, - we won't unselect it through the intersection observer. - */ - const hash = document.location.hash; - if (hash) { - let tocEntryForHash = document.querySelector(`nav li a[href="${hash}"]`); - // if the hash isn't a direct match for a ToC item, check the data attributes - if (!tocEntryForHash) { - const fragment = hash.substring(1); - tocEntryForHash = document.querySelector(`nav li a[data-${fragment}]`); - } - if (tocEntryForHash) { - const headingForHash = document.querySelector(hash); - if (headingForHash && isInViewport(headingForHash)) { - setTocEntry(tocEntryForHash); - return; - } - } - } - - let newEntry = null; - - for (const entry of entries) { - if (entry.intersectionRatio > 0) { - const heading = entry.target; - /* - This sidebar nav consists of two sections: - * at the top, a sitenav containing links to other pages - * under that, the ToC for the current page - - Since the sidebar scrolls to match the document position, - the sitenav will tend to scroll off the screen. - - If the user has scrolled up to (or near) the top of the page, - we want to show the sitenav so. - - So: if the H1 (title) for the current page has started - intersecting, then always scroll the sidebar back to the top. - */ - if (heading.tagName === "H1" && heading.parentNode.tagName === "DIV") { - const nav = document.querySelector("#td-section-nav"); - nav.scrollTop = 0; - return; - } - /* - Otherwise, get the ToC entry for the first entry that - entered the viewport, if there was one. - */ - const id = entry.target.getAttribute('id'); - let tocEntry = document.querySelector(`nav li a[href="#${id}"]`); - // if the id isn't a direct match for a ToC item, - // check the ToC entry's `data-*` attributes - if (!tocEntry) { - tocEntry = document.querySelector(`nav li a[data-${id}]`); - } - if (tocEntry && !newEntry) { - newEntry = tocEntry; - } - } - } - - if (newEntry) { - setTocEntry(newEntry); - return; - } -} - -/* -Track when headings enter the viewport, and use this to update the highlight -for the corresponding ToC entry. + Track when the view is scrolled, and use this to update the highlight for the + corresponding ToC entry. */ window.addEventListener('DOMContentLoaded', () => { + // Part of the viewport is below the header so we should take it into account. + const headerOffset = document.querySelector("body > header > nav").clientHeight; + const headings = getHeadings(); - const toc = document.querySelector("#toc"); - toc.addEventListener("click", event => { - if (event.target.tagName === "A") { - setTocEntry(event.target); - } + const onScroll = throttle((_e) => { + // Update the ToC. + let heading = getCurrentHeading(headings, headerOffset); + selectTocEntry(heading.id); }); - const observer = new IntersectionObserver(handleIntersectionUpdate); - - document.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach((section) => { - observer.observe(section); - }); + // Initialize the state of the ToC. + onScroll(); + // Listen to scroll and resizing changes. + document.addEventListener('scroll', onScroll, false); + document.addEventListener('resize', onScroll, false); });