Skip to content

Commit 65be21e

Browse files
committed
Fix previewing items
1 parent 039d27c commit 65be21e

File tree

3 files changed

+307
-2
lines changed

3 files changed

+307
-2
lines changed

OpenSilver.Samples.TelerikUI/OpenSilver.Samples.TelerikUI/OpenSilver.Samples.TelerikUI.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<ItemGroup>
2626
<None Remove="EmptyOpenSilverMigrationApplication.csproj.vspscc" />
2727
<None Remove="MyTemplate_rename_me_after_export.vstemplate" />
28+
<None Remove="Other\embed.js" />
2829
<None Remove="Other\Styles.xaml" />
2930
<None Remove="Samples\Controls\RadCalendar\RadCalendar_Demo.xaml" />
3031
<None Remove="Samples\Controls\RadCartesianChart\RadCartesianChart_Demo.xaml" />
@@ -77,6 +78,7 @@
7778
<SubType>Designer</SubType>
7879
<Generator>MSBuild:Compile</Generator>
7980
</Content>
81+
<Content Include="Other\embed.js" />
8082
<Content Include="Other\Styles.xaml">
8183
<Generator>MSBuild:Compile</Generator>
8284
</Content>

OpenSilver.Samples.TelerikUI/OpenSilver.Samples.TelerikUI/Other/Internal/ControlToDisplayCodeHostedOnGitHub.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
using System.Collections.Generic;
33
using System.Text;
44
using System.Windows;
5+
using System.Windows.Browser;
56
using System.Windows.Controls;
7+
using CSHTML5.Internal;
68

79
namespace OpenSilver.Samples.TelerikUI
810
{
@@ -19,11 +21,20 @@ public ControlToDisplayCodeHostedOnGitHub()
1921
HorizontalContentAlignment = HorizontalAlignment.Stretch;
2022
}
2123

24+
string GetHtmlString(string filePath)
25+
{
26+
var embedJs =
27+
INTERNAL_UriHelper.ConvertToHtml5Path("ms-appx:/Other/embed.js");
28+
return string.Format(
29+
"<script src=\"{0}?target={1}&style=github&showBorder=on&showLineNumbers=on&showCopy=on\"></script>",
30+
embedJs, HttpUtility.UrlEncode("https://github.com" + filePath.Substring(6)));
31+
}
32+
2233
void OnLoaded(object sender, RoutedEventArgs e)
2334
{
2435
if (!string.IsNullOrEmpty(_filePathOnGitHub))
2536
{
26-
string htmlString = string.Format("<script src='https://gist-it.appspot.com/%7B0%7D?footer=no'></script>", _filePathOnGitHub);
37+
string htmlString = GetHtmlString(_filePathOnGitHub);
2738
DisplayHtmlString(htmlString);
2839
}
2940
}
@@ -48,7 +59,7 @@ public string FilePathOnGitHub
4859

4960
if (this.IsLoaded)
5061
{
51-
string htmlString = string.Format("<script src='https://gist-it.appspot.com/%7B0%7D?footer=no'></script>", FilePathOnGitHub);
62+
string htmlString = GetHtmlString(FilePathOnGitHub);
5263
if (htmlString != _displayedHtmlString)
5364
{
5465
DisplayHtmlString(htmlString);
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
embed();
2+
3+
function embed() {
4+
const sourceURL = new URL(document.currentScript.src);
5+
const params = sourceURL.searchParams;
6+
const target = new URL(params.get("target"));
7+
const style = params.get("style");
8+
const trickyDarkStyle = ["an-old-hope", "androidstudio", "arta", "codepen-embed", "darcula", "dracula", "far", "gml", "hopscotch", "hybrid", "monokai", "monokai-sublime", "nord", "obsidian", "ocean", "railscasts", "rainbow", "shades-of-purple", "sunburst", "vs2015", "xt256", "zenburn"]; // dark styles without 'dark', 'black' or 'night' in its name
9+
const isDarkStyle = style.includes("dark") || style.includes("black") || style.includes("night") || trickyDarkStyle.includes(style);
10+
const showBorder = params.get("showBorder") === "on";
11+
const showLineNumbers = params.get("showLineNumbers") === "on";
12+
const showFileMeta = params.get("showFileMeta") === "on";
13+
const showCopy = params.get("showCopy") === "on";
14+
const lineSplit = target.hash.split("-");
15+
const startLine = target.hash !== "" && lineSplit[0].replace("#L", "") || -1;
16+
const endLine = target.hash !== "" && lineSplit.length > 1 && lineSplit[1].replace("L", "") || startLine;
17+
const tabSize = target.searchParams.get("ts") || 8;
18+
const pathSplit = target.pathname.split("/");
19+
const user = pathSplit[1];
20+
const repository = pathSplit[2];
21+
const branch = pathSplit[4];
22+
const file = pathSplit.slice(5, pathSplit.length).join("/");
23+
const fileExtension = file.split('.').length > 1 ? file.split('.')[file.split('.').length - 1] : 'txt';
24+
const rawFileURL = `https://raw.githubusercontent.com/${user}/${repository}/${branch}/${file}`;
25+
// The id where code will be embeded. In order to support a single `target` embedded for multiple times,
26+
// we use a random string to avoid duplicated id.
27+
const containerId = Math.random().toString(36).substring(2);
28+
29+
// Reserving space for code area should be done in early time
30+
// or the div may not be found later
31+
document.write(`
32+
<style>.lds-ring{margin:1rem auto;position:relative;width:60px;height:60px}.lds-ring div{box-sizing:border-box;display:block;position:absolute;width:48px;height:48px;margin:6px;border:6px solid #fff;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(0.5,0,0.5,1) infinite;border-color:#888 transparent transparent transparent}.lds-ring div:nth-child(1){animation-delay:-.45s}.lds-ring div:nth-child(2){animation-delay:-.3s}.lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style>
33+
<div id="${containerId}" class="emgithub-container"><div class="lds-ring"><div></div><div></div><div></div><div></div></div></div>
34+
<style>.hljs-ln-numbers{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:right;color:#ccc;vertical-align:top}.hljs-ln td.hljs-ln-numbers{padding-right:1.25rem}</style>
35+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/${style}.min.css">
36+
<style>
37+
.emgithub-container .file-meta {
38+
padding: 0.75rem;
39+
border-radius: 0 0 0.3rem 0.3rem;
40+
font: 12px -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
41+
sans-serif, Apple Color Emoji, Segoe UI Emoji;
42+
}
43+
44+
.emgithub-container .file-meta-light {
45+
color: #586069;
46+
background-color: #f7f7f7;
47+
}
48+
49+
.emgithub-container .file-meta-dark {
50+
color: #f7f7f7;
51+
background-color: #586069;
52+
}
53+
54+
.emgithub-container .file-meta a {
55+
font-weight: 600;
56+
text-decoration: none;
57+
border: 0;
58+
}
59+
60+
.emgithub-container .file-meta-light a {
61+
color: #666;
62+
}
63+
64+
.emgithub-container .file-meta-dark a {
65+
color: #fff;
66+
}
67+
68+
/* hide content for small device */
69+
@media (max-width: 575.98px) {
70+
.emgithub-container .hide-in-phone {
71+
display: none;
72+
}
73+
}
74+
75+
.emgithub-container {
76+
position: relative;
77+
}
78+
79+
.emgithub-container .toolbar {
80+
position: absolute;
81+
right: 0px;
82+
padding: 0.3rem;
83+
}
84+
85+
.emgithub-container .copy-btn {
86+
display: none;
87+
border: 1px solid black;
88+
border-radius: 3px;
89+
padding: 0.4rem;
90+
font: bold 1em monospace;
91+
text-decoration: none;
92+
}
93+
94+
.emgithub-container .copy-btn-light {
95+
color: #586069;
96+
background-color: #f7f7f7;
97+
}
98+
99+
.emgithub-container .copy-btn-dark {
100+
color: #f7f7f7;
101+
background-color: #586069;
102+
}
103+
104+
.emgithub-container:hover .copy-btn {
105+
display: block;
106+
}
107+
108+
.emgithub-container .copy-btn-light:hover {
109+
color: #f7f7f7;
110+
background-color: #586069;
111+
}
112+
113+
.emgithub-container .copy-btn-dark:hover {
114+
color: #586069;
115+
background-color: #f7f7f7;
116+
}
117+
118+
.emgithub-container .copy-btn-light:active {
119+
/* darken #586069 by 20% https://www.cssfontstack.com/oldsites/hexcolortool/ */
120+
background-color: #252d36;
121+
}
122+
123+
.emgithub-container .copy-btn-dark:active {
124+
/* darken #f7f7f7 by 20% */
125+
background-color: #c4c4c4;
126+
}
127+
</style>
128+
`);
129+
130+
const HLJSURL = "https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js";
131+
const HLJSNumURL = "https://cdn.jsdelivr.net/npm/[email protected]/dist/highlightjs-line-numbers.min.js";
132+
const loadHLJS = (typeof hljs != "undefined" && typeof hljs.highlightBlock != "undefined") ?
133+
Promise.resolve() : loadScript(HLJSURL);
134+
let loadHLJSNum;
135+
if (showLineNumbers) {
136+
// hljs-num should be loaded only after hljs is loaded
137+
loadHLJSNum = loadHLJS.then(() =>
138+
(typeof hljs != "undefined" && typeof hljs.lineNumbersBlock != "undefined") ?
139+
Promise.resolve() : loadScript(HLJSNumURL)
140+
)
141+
}
142+
143+
const fetchFile = fetch(rawFileURL).then((response) => {
144+
if (response.ok) {
145+
return response.text();
146+
} else {
147+
return Promise.reject(`${response.status} ${response.statusText}`);
148+
}
149+
});
150+
151+
Promise.all(showLineNumbers ? [fetchFile, loadHLJS, loadHLJSNum] : [fetchFile, loadHLJS]).then((result) => {
152+
const targetDiv = document.getElementById(containerId);
153+
embedCodeToTarget(targetDiv, result[0], showBorder, showLineNumbers, showFileMeta, showCopy, isDarkStyle, target.href, rawFileURL, fileExtension, startLine, endLine, tabSize, sourceURL.origin);
154+
}).catch((error) => {
155+
const errorMsg = `Failed to process ${rawFileURL}
156+
${error}`;
157+
const targetDiv = document.getElementById(containerId);
158+
embedCodeToTarget(targetDiv, errorMsg, showBorder, showLineNumbers, showFileMeta, showCopy, isDarkStyle, target.href, rawFileURL, 'plaintext', -1, -1, tabSize, sourceURL.origin);
159+
});
160+
}
161+
162+
function loadScript(src) {
163+
return new Promise((resolve, reject) => {
164+
const script = document.createElement('script');
165+
script.src = src;
166+
script.onload = resolve;
167+
script.onerror = reject;
168+
document.head.appendChild(script);
169+
});
170+
}
171+
172+
173+
function embedCodeToTarget(targetDiv, codeText, showBorder, showLineNumbers, showFileMeta, showCopy, isDarkStyle, fileURL, rawFileURL, lang, startLine, endLine, tabSize, serviceProvider) {
174+
targetDiv.innerHTML = "";
175+
targetDiv.style.margin = "1em 0";
176+
177+
const code = document.createElement("code");
178+
code.style.padding = "1rem";
179+
180+
if (showFileMeta) {
181+
code.style.borderRadius = "0.3rem 0.3rem 0 0";
182+
} else {
183+
code.style.borderRadius = "0.3rem";
184+
}
185+
if (showBorder) {
186+
if (!isDarkStyle) {
187+
code.style.border = "1px solid #ddd";
188+
} else {
189+
code.style.border = "1px solid #555";
190+
}
191+
}
192+
code.classList.add(lang);
193+
if (codeText[codeText.length -1] === "\n") {
194+
// First remove the ending newline
195+
codeText = codeText.slice(0,-1);
196+
}
197+
if (startLine > 0) {
198+
codeTextSplit = codeText.split("\n");
199+
codeText = codeTextSplit.slice(startLine - 1, endLine).join("\n");
200+
}
201+
// Then add the newline back
202+
codeText = codeText + "\n";
203+
code.textContent = codeText;
204+
if (typeof hljs != "undefined" && typeof hljs.highlightBlock != "undefined") {
205+
hljs.highlightBlock(code);
206+
}
207+
if (typeof hljs != "undefined" && typeof hljs.lineNumbersBlock != "undefined" && showLineNumbers) {
208+
hljs.lineNumbersBlock(code, {
209+
singleLine: true,
210+
startFrom: startLine > 0 ? Number.parseInt(startLine) : 1
211+
});
212+
}
213+
214+
if(showCopy) {
215+
const toolbar = document.createElement('div');
216+
toolbar.classList.add('toolbar');
217+
218+
const copyButton = document.createElement('a');
219+
copyButton.classList.add('copy-btn');
220+
if(isDarkStyle) {
221+
copyButton.classList.add('copy-btn-dark');
222+
} else {
223+
copyButton.classList.add('copy-btn-light');
224+
}
225+
copyButton.href = 'javascript:void(0);'
226+
copyButton.innerHTML = 'Copy';
227+
copyButton.addEventListener('click', function(e) {
228+
e.preventDefault();
229+
e.cancelBubble = true;
230+
copyTextToClipboard(codeText);
231+
});
232+
233+
toolbar.appendChild(copyButton);
234+
targetDiv.appendChild(toolbar);
235+
}
236+
237+
// Not use a real `pre` to avoid style being overwritten
238+
// Simulate a real one by using its default style
239+
const customPre = document.createElement("div");
240+
customPre.style.whiteSpace = "pre";
241+
customPre.style.tabSize = tabSize;
242+
customPre.appendChild(code);
243+
targetDiv.appendChild(customPre);
244+
245+
if (showFileMeta) {
246+
const meta = document.createElement("div");
247+
const rawFileURLSplit = rawFileURL.split("/");
248+
meta.innerHTML = `<a target="_blank" href="${rawFileURL}" style="float:right">view raw</a>
249+
<a target="_blank" href="${fileURL}">${rawFileURLSplit[rawFileURLSplit.length - 1]}</a>
250+
delivered <span class="hide-in-phone">with ❤ </span>by <a target="_blank" href="${serviceProvider}">EmGithub</a>`;
251+
meta.classList.add("file-meta");
252+
if (!isDarkStyle) {
253+
meta.classList.add("file-meta-light");
254+
if (showBorder) {
255+
meta.style.border = "1px solid #ddd";
256+
meta.style.borderTop = "0";
257+
}
258+
} else {
259+
meta.classList.add("file-meta-dark");
260+
if (showBorder) {
261+
meta.style.border = "1px solid #555";
262+
meta.style.borderTop = "0";
263+
}
264+
}
265+
targetDiv.appendChild(meta);
266+
}
267+
}
268+
269+
// https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
270+
function copyTextToClipboard(text) {
271+
if (!navigator.clipboard) {
272+
fallbackCopyTextToClipboard(text);
273+
return;
274+
}
275+
navigator.clipboard.writeText(text)
276+
}
277+
278+
function fallbackCopyTextToClipboard(text) {
279+
const textArea = document.createElement("textarea");
280+
textArea.value = text;
281+
textArea.style.position = "fixed"; //avoid scrolling to bottom
282+
document.body.appendChild(textArea);
283+
textArea.focus();
284+
textArea.select();
285+
286+
try {
287+
document.execCommand('copy');
288+
} catch (err) {
289+
console.error('fallbackCopyTextToClipboard: Oops, unable to copy', err);
290+
}
291+
document.body.removeChild(textArea);
292+
}

0 commit comments

Comments
 (0)