Skip to content

Commit 6125d80

Browse files
Resolve relative urls for blob stylesheets - fixes #279
- Don't prefix data: & blob: urls - Handle path-absolute urls correctly
1 parent 9b56353 commit 6125d80

File tree

7 files changed

+92
-8
lines changed

7 files changed

+92
-8
lines changed
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<script src="../../dist/scroll-timeline.js"></script>
3+
4+
<link rel="stylesheet" href="styles.css">
5+
<body>
6+
<div id="container">
7+
<div class="big-spacer"></div>
8+
<div id="subject"></div>
9+
<div class="big-spacer"></div>
10+
<div id=box></div>
11+
</div>
12+
</body>
13+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#container {
2+
overflow-y: scroll;
3+
height: 300px;
4+
width: 300px;
5+
border: 1px solid black;
6+
timeline-scope: --foo;
7+
}
8+
.big-spacer {
9+
height: 800px;
10+
}
11+
#subject {
12+
background: url(asset/green.png), blue;
13+
height: 100px;
14+
width: 100px;
15+
view-timeline-name: --foo;
16+
}
17+
#box {
18+
position: fixed;
19+
top: 0;
20+
background: url("../view-timeline-external-css-with-url/asset/red.png"), yellow;
21+
width: 50px;
22+
height: 50px;
23+
/* Please don't delete the following comments */
24+
/* This comment has been added to make sure css parser ignores it */
25+
/* animation-range: entry 0% 100%; */
26+
animation: linear anim forwards;
27+
animation-timeline: --foo;
28+
}
29+
30+
/* Please don't delete the following comments */
31+
/* This comment has been added to make sure css parser ignores it */
32+
/*
33+
#box {
34+
position: fixed;
35+
top: 0;
36+
background-color: red;
37+
width: 50px;
38+
height: 50px;
39+
animation-timeline: foo;
40+
animation-range: entry 0% 100%;
41+
animation: linear anim;
42+
}
43+
*/
44+
45+
@keyframes anim {
46+
from { top: 0px; left: 0px; }
47+
to { top: 100px; left: 200px; }
48+
}

index.html

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
<li>
3434
<a href="demo/view-timeline-external-css/">demo/view-timeline-external-css</a>
3535
</li>
36+
<li>
37+
<a href="demo/view-timeline-external-css-with-url/">demo/view-timeline-external-css-with-url</a>
38+
</li>
3639
<li>
3740
<a href="demo/basic/anonymous-scroll-timeline.html">demo/basic/anonymous-scroll-timeline.html</a>
3841
</li>

src/scroll-timeline-css-parser.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,30 @@ export class StyleParser {
8383
this.handleScrollTimelineProps(rule, p);
8484
}
8585

86-
// If this sheet has no srcURL (like from a <style> tag), we are done.
87-
// TODO: Otherwise, we have to find `url()` functions and resolve
88-
// relative and path-absolute URLs to absolute URLs.
89-
return p.sheetSrc;
86+
return this.replaceUrlFunctions(p.sheetSrc, srcUrl);
87+
}
88+
89+
90+
// If this sheet has no srcURL (like from a <style> tag), we are done.
91+
// Otherwise, we have to find `url()` functions and resolve
92+
// relative and path-absolute URLs to absolute URLs.
93+
replaceUrlFunctions(sheetSrc, srcUrl) {
94+
if (!srcUrl) {
95+
return sheetSrc;
96+
}
97+
98+
const srcUrlOrigin = new URL(srcUrl).origin
99+
const srcUrlDir = srcUrl.lastIndexOf('/') > srcUrlOrigin.length
100+
? srcUrl.substring(0, srcUrl.lastIndexOf('/'))
101+
: srcUrlOrigin;
102+
103+
// replace relative paths
104+
sheetSrc = sheetSrc.replace(/url\((?:(['"])(?!https?:\/\/|data:|blob:|\/)|(?!['"]?(?:https?:\/\/|data:|blob:|\/)))(?:\.\/)?/gm, `url($1${srcUrlDir}/`)
105+
106+
// replace path-absolute paths
107+
sheetSrc = sheetSrc.replace(/url\((['"])?\//gm, `url($1${srcUrlOrigin}/`)
108+
109+
return sheetSrc;
90110
}
91111

92112
getAnimationTimelineOptions(animationName, target) {
@@ -107,7 +127,7 @@ export class StyleParser {
107127
}
108128
} catch {
109129
// TODO: handle nested at-rules
110-
}
130+
}
111131
}
112132

113133
return null;
@@ -154,10 +174,10 @@ export class StyleParser {
154174
findPreviousSiblingOrAncestorMatchingSelector(target, selector) {
155175
// Target self
156176
let candidate = target;
157-
177+
158178
// Walk the DOM tree: preceding siblings and ancestors
159179
while (candidate) {
160-
if (candidate.matches(selector))
180+
if (candidate.matches(selector))
161181
return candidate;
162182
candidate = candidate.previousElementSibling || candidate.parentElement;
163183
}

src/scroll-timeline-css.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function initMutationObserver() {
5656
fetch(linkElement.getAttribute('href')).then(async (response) => {
5757
const result = await response.text();
5858
let newSrc = parser.transpileStyleSheet(result, true);
59-
newSrc = parser.transpileStyleSheet(result, false);
59+
newSrc = parser.transpileStyleSheet(result, false, response.url);
6060
if (newSrc != result) {
6161
const blob = new Blob([newSrc], { type: 'text/css' });
6262
const url = URL.createObjectURL(blob);

0 commit comments

Comments
 (0)