Skip to content

Commit 283b3f9

Browse files
authored
Merge pull request #1149 from Patternslib/fix--scroll-marker--unescaped
Fix scroll marker unescaped
2 parents 082c233 + 79ffc9c commit 283b3f9

File tree

8 files changed

+66
-3
lines changed

8 files changed

+66
-3
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@patternslib/pat-tiptap": "^4.8.2",
4545
"@patternslib/pat-upload": "^3.1.1",
4646
"copy-webpack-plugin": "^11.0.0",
47+
"css.escape": "^1.5.1",
4748
"modernizr": "^3.12.0",
4849
"pegjs": "0.11.0-master.b7b87ea"
4950
},

src/core/dom.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,29 @@ const get_visible_ratio = (el, container) => {
410410
return visible_ratio;
411411
};
412412

413+
/**
414+
* Get an escaped CSS selector for a given id string.
415+
*
416+
* id selectors should - but don't have to - start with a letter.
417+
* If the id starts with a number or a dash, it should be escaped.
418+
* This method does that for you.
419+
*
420+
* Alse see:
421+
* - https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id
422+
* - https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape
423+
*
424+
* @param {String} id - The id to escape.
425+
*
426+
* @returns {String} - The escaped CSS selector.
427+
*
428+
* @example
429+
* escape_css_id_selector("#123"); // returns "#\\31 23""
430+
* escape_css_id_selector("#-123"); // returns "#-\\31 23"
431+
*/
432+
const escape_css_id = (id) => {
433+
return `#${CSS.escape(id.split("#")[1])}`;
434+
};
435+
413436
const dom = {
414437
toNodeArray: toNodeArray,
415438
querySelectorAllAndMe: querySelectorAllAndMe,
@@ -432,6 +455,7 @@ const dom = {
432455
delete_data: delete_data,
433456
template: template,
434457
get_visible_ratio: get_visible_ratio,
458+
escape_css_id: escape_css_id,
435459
add_event_listener: events.add_event_listener, // BBB export. TODO: Remove in an upcoming version.
436460
remove_event_listener: events.remove_event_listener, // BBB export. TODO: Remove in an upcoming version.
437461
};

src/core/dom.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,3 +856,21 @@ describe("core.dom tests", () => {
856856
});
857857
});
858858
});
859+
860+
describe("escape_css_id", function () {
861+
it("returns a standard id selector as-is", function () {
862+
expect(dom.escape_css_id("#foo")).toBe("#foo");
863+
});
864+
865+
it("returns an escaped version when the id is a number", function () {
866+
expect(dom.escape_css_id("#123")).toBe("#\\31 23");
867+
});
868+
869+
it("returns an escaped version when the id starts with a number", function () {
870+
expect(dom.escape_css_id("#1foo")).toBe("#\\31 foo");
871+
});
872+
873+
it("returns an escaped version when the id starts with a dash", function () {
874+
expect(dom.escape_css_id("#-1-2-3")).toBe("#-\\31 -2-3");
875+
});
876+
});

src/pat/navigation/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ <h3>Example 3 - nested nav, but no injection</h3>
113113
<a href="#2">Tab 2</a>
114114
</li>
115115
</ul>
116+
117+
<section id="10">Content for tab 1</section>
118+
<section id="11">Content for tab 1.1</section>
119+
<section id="12">Content for tab 1.2</section>
120+
<section id="2">Content for tab 2</section>
121+
116122
</section>
117123

118124
<template id="inject-tab-1">Content for tab 1</template>

src/pat/navigation/navigation.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import $ from "jquery";
22
import { BasePattern } from "../../core/basepattern";
33
import Parser from "../../core/parser";
44
import ScrollMarker from "../scroll-marker/scroll-marker";
5+
import dom from "../../core/dom";
56
import logging from "../../core/logging";
67
import events from "../../core/events";
78
import registry from "../../core/registry";
@@ -180,7 +181,9 @@ class Pattern extends BasePattern {
180181
}
181182
// Mark the current content item, if it is a hash link.
182183
if (item.matches("a[href^='#']")) {
183-
const content_item = document.querySelector(item.getAttribute("href"));
184+
const content_item = document.querySelector(
185+
dom.escape_css_id(item.hash)
186+
);
184187
if (content_item) {
185188
content_item.classList.add(this.options["current-content-class"]);
186189
}

src/pat/scroll-marker/scroll-marker.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Pattern extends BasePattern {
3131
// differently, e.g. by clicking in a pat-navigation menu.
3232
set_current_disabled = false;
3333

34-
async init() {
34+
init() {
3535
// Get all elements that are referenced by links in the current page.
3636
this.observables = new Map(
3737
[...dom.querySelectorAllAndMe(this.el, "a[href^='#']")]
@@ -41,7 +41,10 @@ class Pattern extends BasePattern {
4141
// to create the resulting Map holding all necessary information.
4242
(it) => [
4343
it.hash.split("#")[1],
44-
{ link: it, target: document.querySelector(it.hash) },
44+
{
45+
link: it,
46+
target: document.querySelector(dom.escape_css_id(it.hash)),
47+
},
4548
]
4649
)
4750
.filter(

src/setup-tests.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ import dom from "./core/dom";
1919
dom.is_visible = (el) => {
2020
return !el.hidden && el.style.display !== "none";
2121
};
22+
23+
// polyfill css.escape for jsdom
24+
import("css.escape");

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3774,6 +3774,11 @@ css-loader@^6.7.3:
37743774
postcss-value-parser "^4.2.0"
37753775
semver "^7.3.8"
37763776

3777+
css.escape@^1.5.1:
3778+
version "1.5.1"
3779+
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
3780+
integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
3781+
37773782
cssesc@^3.0.0:
37783783
version "3.0.0"
37793784
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"

0 commit comments

Comments
 (0)