Completely rearchitect the code renderer

This commit is contained in:
tarikjaber
2023-04-06 15:49:41 -04:00
parent 46981c68e9
commit dde86cf964
3 changed files with 123 additions and 76 deletions

View File

@@ -83,16 +83,17 @@
</select> </select>
<button id="print">Print</button> <button id="print">Print</button>
</div> </div>
<textarea placeholder="Enter code ..."></textarea> <textarea spellcheck="false" placeholder="Enter code ..."></textarea>
</div> </div>
<div id="print-area"> <div id="print-area">
<h1 id="document-title">Code</h1>
<div id="code-container"> <div id="code-container">
<div id="line-nums" class="hljs"> <div class="code-line">
<pre>1 </pre> <span class="line-number">1</span>
<pre class="code-pre"><code id="code">console.log("Hello World!");</code></pre>
</div> </div>
<div id="code-div"> <div class="code-line">
<pre><code id="code">console.log("Hello World!");</code></pre> <span class="line-number">2</span>
<pre class="code-pre"><code id="code">console.log("Hello World!");</code></pre>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,11 +2,11 @@ const printBtn = document.getElementById('print');
const codeTextArea = document.getElementsByTagName('textarea')[0]; const codeTextArea = document.getElementsByTagName('textarea')[0];
const code = document.getElementById('code'); const code = document.getElementById('code');
const documentNameInput = document.getElementById('document-name-input'); const documentNameInput = document.getElementById('document-name-input');
const documentTitle = document.getElementById('document-title');
const languageSelector = document.getElementById('languages'); const languageSelector = document.getElementById('languages');
const codeLines = document.getElementById('line-nums'); const codeLines = document.getElementById('line-nums');
const themeStylesheet = document.getElementById('theme-style'); const themeStylesheet = document.getElementById('theme-style');
const themeSelector = document.getElementById('themes'); const themeSelector = document.getElementById('themes');
const codeContainer = document.getElementById('code-container');
let selectedLanguage = localStorage.getItem('language') || 'javascript'; let selectedLanguage = localStorage.getItem('language') || 'javascript';
let selectedTheme = localStorage.getItem('theme') || 'github-dark'; let selectedTheme = localStorage.getItem('theme') || 'github-dark';
let codeText = localStorage.getItem('code') || 'console.log("Hello World")'; let codeText = localStorage.getItem('code') || 'console.log("Hello World")';
@@ -15,34 +15,42 @@ let codeText = localStorage.getItem('code') || 'console.log("Hello World")';
themeStylesheet.setAttribute('href', getStylesheet(selectedTheme)); themeStylesheet.setAttribute('href', getStylesheet(selectedTheme));
themeSelector.value = selectedTheme; themeSelector.value = selectedTheme;
code.classList.add('hljs', `language-${selectedLanguage}`); code.classList.add('hljs', `language-${selectedLanguage}`);
code.innerHTML = escape(codeText); escaped = escapeHtml(codeText);
code.innerHTML = escaped;
codeTextArea.value = codeText; codeTextArea.value = codeText;
languageSelector.value = selectedLanguage; languageSelector.value = selectedLanguage;
documentTitle.innerHTML = documentNameInput.value || 'Untitled';
updateLineNumbers();
hljs.configure({ hljs.configure({
languages: ['java', 'javascript', 'html', 'typescript', 'cpp'] languages: ['java', 'javascript', 'html', 'typescript', 'cpp']
}); });
hljs.highlightElement(code);
updateCode();
// Attach event listeners // Attach event listeners
documentNameInput.addEventListener('input', () => {
documentTitle.innerHTML = documentNameInput.value || 'Untitled';
});
printBtn.addEventListener('click', () => { printBtn.addEventListener('click', () => {
console.log('Print button clicked.'); updateCode();
document.title = documentTitle.textContent || 'code.pdf'; let optGroup = themeSelector.options[themeSelector.selectedIndex].parentNode;
const lineNumbers = document.querySelectorAll('.line-number');
if (optGroup.label === 'Dark') {
for (let i = 0; i < lineNumbers.length; i++) {
lineNumbers[i].style.backgroundColor = '#353b48';
lineNumbers[i].style.color = '#dfe6e9';
}
} else {
for (let i = 0; i < lineNumbers.length; i++) {
lineNumbers[i].style.backgroundColor = '#dcdde1';
lineNumbers[i].style.color = '#2d3436';
}
}
document.title = documentNameInput.value || 'Code';
window.print(); window.print();
document.title = 'Code Formatter'; document.title = 'Convert Code to PDF Online: Free Tool for Programming Languages';
}); });
codeTextArea.addEventListener('input', () => { codeTextArea.addEventListener('input', () => {
codeText = codeTextArea.value; codeText = codeTextArea.value;
localStorage.setItem('code', codeText); localStorage.setItem('code', codeText);
code.innerHTML = escape(codeText); code.innerHTML = escapeHtml(codeText);
updateLineNumbers();
hljs.highlightElement(code);
}); });
languageSelector.addEventListener('change', () => { languageSelector.addEventListener('change', () => {
@@ -50,44 +58,50 @@ languageSelector.addEventListener('change', () => {
selectedLanguage = languageSelector.value; selectedLanguage = languageSelector.value;
localStorage.setItem('language', selectedLanguage); localStorage.setItem('language', selectedLanguage);
code.classList.add(`language-${selectedLanguage}`); code.classList.add(`language-${selectedLanguage}`);
hljs.highlightElement(code);
}); });
themeSelector.addEventListener('change', () => { themeSelector.addEventListener('change', () => {
selectedTheme = themeSelector.value; selectedTheme = themeSelector.value;
themeStylesheet.href = getStylesheet(selectedTheme); themeStylesheet.href = getStylesheet(selectedTheme);
localStorage.setItem('theme', selectedTheme); localStorage.setItem('theme', selectedTheme);
hljs.highlightElement(code);
documentTitle.innerHTML = documentNameInput.value || 'Untitled';
});
window.addEventListener('beforeprint', event => {
document.body.classList.add('hljs');
});
window.addEventListener('afterprint', event => {
document.body.classList.remove('hljs');
}); });
// Helper functions // Helper functions
function escape(s) { function escapeHtml(text) {
return s.replace(/[^0-9A-Za-z ]/g, c => `&#${c.charCodeAt(0)};`); return text
} .replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
function updateLineNumbers() { .replace(/>/g, "&gt;")
const lines = codeTextArea.value.split('\n'); .replace(/"/g, "&quot;")
const numLines = lines.length; .replace(/'/g, "&#039;");
const numLinesDigits = numLines.toString().length;
let html = '';
for (let i = 0; i < numLines; i++) {
html += `<pre>${(i + 1).toString().padStart(numLinesDigits)} </pre>`;
for (let j = 0; j < lines[i].length / 98 - 1; j++) {
html += `<pre>${''.padStart(numLinesDigits)} </pre>`;
}
}
codeLines.innerHTML = html;
} }
function getStylesheet(style) { function getStylesheet(style) {
return `//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/${style}.min.css`; return `//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/${style}.min.css`;
} }
function createCodeLine(lineNumber, lineContent) {
lineContent = lineContent || ' ';
const code = `<code id="code" class="hljs language-${selectedLanguage}">${lineContent}</code>`;
return `<div class="code-line"><span class="line-number">${lineNumber}</span><pre class="code-pre">${code}</pre></div>`;
}
function updateCode() {
const lines = codeTextArea.value.split('\n');
const numLines = lines.length;
let formattedCode = '';
for (let i = 0; i < lines.length; i++) {
const lineNumber = (i + 1).toString().padStart(Math.floor(Math.log10(numLines)) + 1, ' ');
const lineContent = escapeHtml(lines[i]);
const codeLine = createCodeLine(lineNumber, lineContent);
formattedCode += codeLine;
}
codeContainer.innerHTML = formattedCode;
hljs.highlightAll();
}

View File

@@ -38,17 +38,27 @@ input {
button { button {
border-width: 0; border-width: 0;
background-color: #006ed9; background-color: #487eb0;
color: white; color: white;
max-width: 100px;
font-weight: bold;
padding: 6px; padding: 6px;
min-width: 120px; min-width: 120px;
border-radius: 5px; border-radius: 5px;
transition: background-color 0.2s ease-in-out, transform 0.2s ease-in-out;
}
button:hover {
background-color: #40739e;
cursor: pointer;
} }
button:active { button:active {
background-color: #5584ac; transform: scale(0.95);
background-color: #0077b6;
} }
textarea { textarea {
padding: 10px; padding: 10px;
margin-top: 20px; margin-top: 20px;
@@ -74,27 +84,41 @@ pre {
} }
#code-container { #code-container {
display: flex; margin: 0;
margin: 0 -20px; max-width: 100%;
}
#code-container .code-line:first-of-type .line-number {
padding-top: 10px;
border-top-left-radius: 10px;
}
#code-container .code-line:last-of-type .line-number {
padding-bottom: 10px;
border-bottom-left-radius: 10px;
}
#code-container .code-line:first-of-type #code {
padding-top: 10px;
border-top-right-radius: 10px;
}
#code-container .code-line:last-of-type #code {
padding-bottom: 10px;
border-bottom-right-radius: 10px;
}
#code {
font-size: 14px;
font-family: 'Fira Code', monospace; font-family: 'Fira Code', monospace;
}
#document-title {
display: none;
}
code {
font-size: 14px;
white-space: pre-wrap; white-space: pre-wrap;
padding: 0px 11px;
flex-grow: 1;
} }
#line-nums { .code-pre {
width: auto;
font-size: 14px;
padding-left: 11px;
padding-top: 13px;
padding-bottom: 4px;
display: inline-block; display: inline-block;
flex-grow: 1;
} }
#code-div { #code-div {
@@ -104,13 +128,23 @@ code {
display: inline-block; display: inline-block;
} }
#code { .code-line {
margin-left: 2px; font-family: 'Fira Code', monospace;
padding-bottom: 22px; font-size: 14px;
display: flex;
}
.line-number {
padding: 0px 11px;
user-select: none;
background-color: #454545;
color: white;
white-space: pre;
} }
#print-area { #print-area {
padding: 20px; padding: 0;
padding-top: 20px;
display: none; display: none;
} }
@@ -125,6 +159,10 @@ a {
-webkit-print-color-adjust: exact; -webkit-print-color-adjust: exact;
} }
.line-number {
user-select: none;
}
#document-title { #document-title {
margin-bottom: 20px; margin-bottom: 20px;
} }
@@ -133,10 +171,6 @@ a {
display: block; display: block;
} }
#code-container {
margin-top: -20px;
}
.hide-from-print { .hide-from-print {
display: none; display: none;
} }
@@ -161,12 +195,10 @@ p {
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: #f1f1f1; background: #f1f1f1;
border-radius: 5px;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background: #888; background: #888;
border-radius: 5px;
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {