Skip to content

Commit b5f4f10

Browse files
Test page: Added "Share" option (#2575)
This adds a link and a small popup to share the current state of the test page via a compact link.
1 parent 0604793 commit b5f4f10

File tree

2 files changed

+143
-12
lines changed

2 files changed

+143
-12
lines changed

.github/ISSUE_TEMPLATE/highlighting-bug-report.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ assignees: ''
1313
- Plugins: [a list of plugins you are using or 'none']
1414

1515
<!--
16-
Does the problem still occur in the latest version of Prism?
17-
You can check using the [test page](https://prismjs.com/test.html) or get the latest version at the [download page](https://prismjs.com/download.html).
16+
Please verify that the problem still occurs in the latest version of Prism.
17+
18+
You can check this using the [test page](https://prismjs.com/test.html) or by getting the latest version at our [download page](https://prismjs.com/download.html).
1819
-->
1920

2021
**Description**
2122
A clear and concise description of what is being highlighted incorrectly and how it should be highlighted instead. Add screenshots to illustrate the problem.
2223

2324
**Code snippet**
2425

26+
<!--
27+
Please add a link to the [test page](https://prismjs.com/test.html) that reproduces your issue (hover over "Share" and insert the link below).
28+
-->
29+
[Test page]()
30+
2531
<details>
2632
<summary>The code being highlighted incorrectly.</summary>
2733

test.html

+135-10
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,44 @@
9191
margin: 0 1px;
9292
}
9393

94+
#options {
95+
position: relative;
96+
}
97+
98+
.share-wrapper {
99+
position: absolute;
100+
top: 0;
101+
right: 0;
102+
background-color: white;
103+
}
104+
.share-wrapper .hidden-wrapper {
105+
display: none;
106+
}
107+
108+
.share-wrapper:hover {
109+
top: -.5em;
110+
right: -1em;
111+
width: 300px;
112+
padding: .5em 1em;
113+
outline: 1px solid #888;
114+
}
115+
.share-wrapper:hover .hidden-wrapper {
116+
display: block;
117+
}
118+
119+
.share-wrapper input {
120+
width: 100%;
121+
box-sizing: border-box;
122+
}
123+
124+
.share-wrapper button {
125+
border: none;
126+
background: none;
127+
font: inherit;
128+
text-decoration: underline;
129+
cursor: pointer;
130+
}
131+
94132
</style>
95133
<script src="assets/prefixfree.min.js"></script>
96134

@@ -115,9 +153,16 @@ <h2>Test drive</h2>
115153
<p>Result:</p>
116154
<pre><code></code></pre>
117155

118-
<p id="options">
156+
<div id="options" style="margin: 1em 0">
119157
<label><input type="checkbox" id="option-show-tokens"> Show tokens</label>
120-
</p>
158+
<div class="share-wrapper">
159+
<a id="share-link" href="" style="float: right;">Share</a>
160+
<div class="hidden-wrapper">
161+
<input id="share-link-input" type="text" readonly onClick="this.select();"/>
162+
<button type="button" id="copy-share-link" onclick="copyShare();">Copy to clipboard</button>
163+
</div>
164+
</div>
165+
</div>
121166
<p id="language">
122167
<strong>Language:</strong>
123168
</p>
@@ -151,18 +196,41 @@ <h2>Test drive</h2>
151196
code = newCode;
152197
};
153198

154-
199+
function getHashParams() {
200+
return parseUrlParams((location.hash || '').substr(1));
201+
}
202+
function setHashParams(params) {
203+
location.hash = stringifyUrlParams(params);
204+
}
155205
function updateHashLanguage(lang) {
156-
location.hash = lang ? 'language=' + lang : '';
206+
var params = getHashParams();
207+
params.language = lang;
208+
setHashParams(params);
157209
}
158210
function getHashLanguage() {
159-
var match = /[#&]language=([^&]+)/.exec(location.hash);
160-
return match ? match[1] : null;
211+
return getHashParams().language;
161212
}
162213
function getRadio(lang) {
163214
return $('input[name=language][value="' + lang + '"]');
164215
}
165216

217+
function copyShare() {
218+
const link = $('#share-link').href;
219+
try {
220+
navigator.clipboard.writeText(link).then(function () {
221+
$('#copy-share-link').textContent = 'Copied!';
222+
}, function () {
223+
$('#copy-share-link').textContent = 'Failed to copy!';
224+
});
225+
} catch (e) {
226+
$('#copy-share-link').textContent = 'Failed to copy!';
227+
}
228+
setTimeout(function () {
229+
$('#copy-share-link').textContent = 'Copy to clipboard';
230+
}, 5000);
231+
}
232+
window.copyShare = copyShare;
233+
166234
window.onhashchange = function () {
167235
var input = getRadio(getHashLanguage());
168236

@@ -196,6 +264,7 @@ <h2>Test drive</h2>
196264
code.className = 'language-' + lang;
197265
code.textContent = code.textContent;
198266
updateHashLanguage(lang);
267+
updateShareLink();
199268

200269
// loadLanguage() returns a promise, so we use highlightCode()
201270
// as resolve callback. The promise will be immediately
@@ -277,9 +346,14 @@ <h2>Test drive</h2>
277346
var textarea = $('textarea', form);
278347

279348
try {
280-
var lastCode = sessionStorage.getItem('test-code');
281-
if (lastCode) {
282-
textarea.value = lastCode;
349+
var hashText = getHashParams().text;
350+
if (hashText) {
351+
textarea.value = hashText;
352+
} else {
353+
var lastCode = sessionStorage.getItem('test-code');
354+
if (lastCode) {
355+
textarea.value = lastCode;
356+
}
283357
}
284358
} catch (e) {
285359
// ignore sessionStorage errors
@@ -290,6 +364,8 @@ <h2>Test drive</h2>
290364
code.textContent = codeText;
291365
highlightCode();
292366

367+
updateShareLink();
368+
293369
try {
294370
sessionStorage.setItem('test-code', codeText);
295371
} catch (error) {
@@ -308,8 +384,57 @@ <h2>Test drive</h2>
308384
};
309385
$('#option-show-tokens').onchange();
310386

311-
})();
387+
function updateShareLink() {
388+
var params = {
389+
language: /\blang(?:uage)?-([\w-]+)\b/i.exec(code.className)[1],
390+
text: code.textContent,
391+
};
312392

393+
$('#share-link').href = '#' + stringifyUrlParams(params);
394+
$('#share-link-input').value = $('#share-link').href;
395+
}
396+
397+
398+
/**
399+
* @param {Record<string, string | number | boolean>} params
400+
* @returns {string}
401+
*/
402+
function stringifyUrlParams(params) {
403+
var parts = [];
404+
for (var name in params) {
405+
if (params.hasOwnProperty(name)) {
406+
var value = params[name];
407+
if (typeof value === 'boolean') {
408+
if (value) {
409+
parts.push(name);
410+
}
411+
} else {
412+
parts.push(name + '=' + encodeURIComponent(value));
413+
}
414+
}
415+
}
416+
return parts.join('&');
417+
}
418+
/**
419+
* @param {string} str
420+
* @returns {Record<string, string | boolean>}
421+
*/
422+
function parseUrlParams(str) {
423+
/** @type {Record<string, string | boolean>} */
424+
var params = {};
425+
str.split(/&/g).filter(Boolean).forEach(function (part) {
426+
var parts = part.split(/=/);
427+
var name = parts[0];
428+
if (parts.length === 1) {
429+
params[name] = true;
430+
} else {
431+
params[name] = decodeURIComponent(parts[1]);
432+
}
433+
});
434+
return params;
435+
}
436+
437+
})();
313438
</script>
314439

315440
</body>

0 commit comments

Comments
 (0)