vendor(editor): pin Prism v1.29.0 + CodeJar v4.0.0
Self-host the editor dependencies under /static/vendor/ since the strict CSP forbids CDN loading. README records source URLs, versions, and SHA256s for each file.
This commit is contained in:
parent
1ec5e80a73
commit
6ade91b870
4 changed files with 516 additions and 0 deletions
22
l4d2web/l4d2web/static/vendor/README.md
vendored
Normal file
22
l4d2web/l4d2web/static/vendor/README.md
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Vendored static assets
|
||||||
|
|
||||||
|
All third-party JS/CSS shipped under `/static/vendor/` is committed
|
||||||
|
verbatim from the upstream releases below. The strict CSP
|
||||||
|
(`default-src 'self'`) means we cannot load these from CDNs.
|
||||||
|
|
||||||
|
| File | Upstream | Version | SHA256 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `prism.js` | jsdelivr concat: prism-core.min.js + prism-clike.min.js + prism-bash.min.js | v1.29.0 | `636b6ce9db1eddd5b60992bb34e3fbc1c3364bce7c312f798f20a16011d7681c` |
|
||||||
|
| `prism.css` | https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css | v1.29.0 | `928e23e6b9fcef82c5f1d1f05b6f7fc5a6e187c60195e59fbf16fc9d071ee057` |
|
||||||
|
| `codejar.js` | https://cdn.jsdelivr.net/npm/codejar@4.0.0/dist/codejar.js + ESM-strip + browser-global shim | v4.0.0 | `c13c2df70a0712acb6440ff5a19ec0afe46d3e811fcb6c4fecd1fde73ae94486` |
|
||||||
|
|
||||||
|
## Regenerating
|
||||||
|
|
||||||
|
- **Prism:** Re-run the three-component concat in Task 1 Step 1 of
|
||||||
|
`docs/superpowers/plans/2026-05-16-textarea-code-editor.md` with
|
||||||
|
an updated `VER`, then re-download the theme CSS.
|
||||||
|
- **CodeJar:** Re-download from jsdelivr per the same plan's Task 1
|
||||||
|
Step 2 (`dist/codejar.js`, not the bare `codejar.js` which does not
|
||||||
|
exist in v4.x), strip ESM exports, re-append the `window.CodeJar` shim.
|
||||||
|
|
||||||
|
Bump the version + SHA columns in this table after any update.
|
||||||
489
l4d2web/l4d2web/static/vendor/codejar.js
vendored
Normal file
489
l4d2web/l4d2web/static/vendor/codejar.js
vendored
Normal file
|
|
@ -0,0 +1,489 @@
|
||||||
|
const globalWindow = window;
|
||||||
|
function CodeJar(editor, highlight, opt = {}) {
|
||||||
|
const options = {
|
||||||
|
tab: '\t',
|
||||||
|
indentOn: /[({\[]$/,
|
||||||
|
moveToNewLine: /^[)}\]]/,
|
||||||
|
spellcheck: false,
|
||||||
|
catchTab: true,
|
||||||
|
preserveIdent: true,
|
||||||
|
addClosing: true,
|
||||||
|
history: true,
|
||||||
|
window: globalWindow,
|
||||||
|
...opt
|
||||||
|
};
|
||||||
|
const window = options.window;
|
||||||
|
const document = window.document;
|
||||||
|
let listeners = [];
|
||||||
|
let history = [];
|
||||||
|
let at = -1;
|
||||||
|
let focus = false;
|
||||||
|
let callback;
|
||||||
|
let prev; // code content prior keydown event
|
||||||
|
editor.setAttribute('contenteditable', 'plaintext-only');
|
||||||
|
editor.setAttribute('spellcheck', options.spellcheck ? 'true' : 'false');
|
||||||
|
editor.style.outline = 'none';
|
||||||
|
editor.style.overflowWrap = 'break-word';
|
||||||
|
editor.style.overflowY = 'auto';
|
||||||
|
editor.style.whiteSpace = 'pre-wrap';
|
||||||
|
let isLegacy = false; // true if plaintext-only is not supported
|
||||||
|
highlight(editor);
|
||||||
|
if (editor.contentEditable !== 'plaintext-only')
|
||||||
|
isLegacy = true;
|
||||||
|
if (isLegacy)
|
||||||
|
editor.setAttribute('contenteditable', 'true');
|
||||||
|
const debounceHighlight = debounce(() => {
|
||||||
|
const pos = save();
|
||||||
|
highlight(editor, pos);
|
||||||
|
restore(pos);
|
||||||
|
}, 30);
|
||||||
|
let recording = false;
|
||||||
|
const shouldRecord = (event) => {
|
||||||
|
return !isUndo(event) && !isRedo(event)
|
||||||
|
&& event.key !== 'Meta'
|
||||||
|
&& event.key !== 'Control'
|
||||||
|
&& event.key !== 'Alt'
|
||||||
|
&& !event.key.startsWith('Arrow');
|
||||||
|
};
|
||||||
|
const debounceRecordHistory = debounce((event) => {
|
||||||
|
if (shouldRecord(event)) {
|
||||||
|
recordHistory();
|
||||||
|
recording = false;
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
const on = (type, fn) => {
|
||||||
|
listeners.push([type, fn]);
|
||||||
|
editor.addEventListener(type, fn);
|
||||||
|
};
|
||||||
|
on('keydown', event => {
|
||||||
|
if (event.defaultPrevented)
|
||||||
|
return;
|
||||||
|
prev = toString();
|
||||||
|
if (options.preserveIdent)
|
||||||
|
handleNewLine(event);
|
||||||
|
else
|
||||||
|
legacyNewLineFix(event);
|
||||||
|
if (options.catchTab)
|
||||||
|
handleTabCharacters(event);
|
||||||
|
if (options.addClosing)
|
||||||
|
handleSelfClosingCharacters(event);
|
||||||
|
if (options.history) {
|
||||||
|
handleUndoRedo(event);
|
||||||
|
if (shouldRecord(event) && !recording) {
|
||||||
|
recordHistory();
|
||||||
|
recording = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isLegacy && !isCopy(event))
|
||||||
|
restore(save());
|
||||||
|
});
|
||||||
|
on('keyup', event => {
|
||||||
|
if (event.defaultPrevented)
|
||||||
|
return;
|
||||||
|
if (event.isComposing)
|
||||||
|
return;
|
||||||
|
if (prev !== toString())
|
||||||
|
debounceHighlight();
|
||||||
|
debounceRecordHistory(event);
|
||||||
|
if (callback)
|
||||||
|
callback(toString());
|
||||||
|
});
|
||||||
|
on('focus', _event => {
|
||||||
|
focus = true;
|
||||||
|
});
|
||||||
|
on('blur', _event => {
|
||||||
|
focus = false;
|
||||||
|
});
|
||||||
|
on('paste', event => {
|
||||||
|
recordHistory();
|
||||||
|
handlePaste(event);
|
||||||
|
recordHistory();
|
||||||
|
if (callback)
|
||||||
|
callback(toString());
|
||||||
|
});
|
||||||
|
on('cut', event => {
|
||||||
|
recordHistory();
|
||||||
|
handleCut(event);
|
||||||
|
recordHistory();
|
||||||
|
if (callback)
|
||||||
|
callback(toString());
|
||||||
|
});
|
||||||
|
function save() {
|
||||||
|
const s = getSelection();
|
||||||
|
const pos = { start: 0, end: 0, dir: undefined };
|
||||||
|
let { anchorNode, anchorOffset, focusNode, focusOffset } = s;
|
||||||
|
if (!anchorNode || !focusNode)
|
||||||
|
throw 'error1';
|
||||||
|
// If the anchor and focus are the editor element, return either a full
|
||||||
|
// highlight or a start/end cursor position depending on the selection
|
||||||
|
if (anchorNode === editor && focusNode === editor) {
|
||||||
|
pos.start = (anchorOffset > 0 && editor.textContent) ? editor.textContent.length : 0;
|
||||||
|
pos.end = (focusOffset > 0 && editor.textContent) ? editor.textContent.length : 0;
|
||||||
|
pos.dir = (focusOffset >= anchorOffset) ? '->' : '<-';
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
// Selection anchor and focus are expected to be text nodes,
|
||||||
|
// so normalize them.
|
||||||
|
if (anchorNode.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
const node = document.createTextNode('');
|
||||||
|
anchorNode.insertBefore(node, anchorNode.childNodes[anchorOffset]);
|
||||||
|
anchorNode = node;
|
||||||
|
anchorOffset = 0;
|
||||||
|
}
|
||||||
|
if (focusNode.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
const node = document.createTextNode('');
|
||||||
|
focusNode.insertBefore(node, focusNode.childNodes[focusOffset]);
|
||||||
|
focusNode = node;
|
||||||
|
focusOffset = 0;
|
||||||
|
}
|
||||||
|
visit(editor, el => {
|
||||||
|
if (el === anchorNode && el === focusNode) {
|
||||||
|
pos.start += anchorOffset;
|
||||||
|
pos.end += focusOffset;
|
||||||
|
pos.dir = anchorOffset <= focusOffset ? '->' : '<-';
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
if (el === anchorNode) {
|
||||||
|
pos.start += anchorOffset;
|
||||||
|
if (!pos.dir) {
|
||||||
|
pos.dir = '->';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (el === focusNode) {
|
||||||
|
pos.end += focusOffset;
|
||||||
|
if (!pos.dir) {
|
||||||
|
pos.dir = '<-';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (el.nodeType === Node.TEXT_NODE) {
|
||||||
|
if (pos.dir != '->')
|
||||||
|
pos.start += el.nodeValue.length;
|
||||||
|
if (pos.dir != '<-')
|
||||||
|
pos.end += el.nodeValue.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// collapse empty text nodes
|
||||||
|
editor.normalize();
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
function restore(pos) {
|
||||||
|
const s = getSelection();
|
||||||
|
let startNode, startOffset = 0;
|
||||||
|
let endNode, endOffset = 0;
|
||||||
|
if (!pos.dir)
|
||||||
|
pos.dir = '->';
|
||||||
|
if (pos.start < 0)
|
||||||
|
pos.start = 0;
|
||||||
|
if (pos.end < 0)
|
||||||
|
pos.end = 0;
|
||||||
|
// Flip start and end if the direction reversed
|
||||||
|
if (pos.dir == '<-') {
|
||||||
|
const { start, end } = pos;
|
||||||
|
pos.start = end;
|
||||||
|
pos.end = start;
|
||||||
|
}
|
||||||
|
let current = 0;
|
||||||
|
visit(editor, el => {
|
||||||
|
if (el.nodeType !== Node.TEXT_NODE)
|
||||||
|
return;
|
||||||
|
const len = (el.nodeValue || '').length;
|
||||||
|
if (current + len > pos.start) {
|
||||||
|
if (!startNode) {
|
||||||
|
startNode = el;
|
||||||
|
startOffset = pos.start - current;
|
||||||
|
}
|
||||||
|
if (current + len > pos.end) {
|
||||||
|
endNode = el;
|
||||||
|
endOffset = pos.end - current;
|
||||||
|
return 'stop';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current += len;
|
||||||
|
});
|
||||||
|
if (!startNode)
|
||||||
|
startNode = editor, startOffset = editor.childNodes.length;
|
||||||
|
if (!endNode)
|
||||||
|
endNode = editor, endOffset = editor.childNodes.length;
|
||||||
|
// Flip back the selection
|
||||||
|
if (pos.dir == '<-') {
|
||||||
|
[startNode, startOffset, endNode, endOffset] = [endNode, endOffset, startNode, startOffset];
|
||||||
|
}
|
||||||
|
s.setBaseAndExtent(startNode, startOffset, endNode, endOffset);
|
||||||
|
}
|
||||||
|
function beforeCursor() {
|
||||||
|
const s = getSelection();
|
||||||
|
const r0 = s.getRangeAt(0);
|
||||||
|
const r = document.createRange();
|
||||||
|
r.selectNodeContents(editor);
|
||||||
|
r.setEnd(r0.startContainer, r0.startOffset);
|
||||||
|
return r.toString();
|
||||||
|
}
|
||||||
|
function afterCursor() {
|
||||||
|
const s = getSelection();
|
||||||
|
const r0 = s.getRangeAt(0);
|
||||||
|
const r = document.createRange();
|
||||||
|
r.selectNodeContents(editor);
|
||||||
|
r.setStart(r0.endContainer, r0.endOffset);
|
||||||
|
return r.toString();
|
||||||
|
}
|
||||||
|
function handleNewLine(event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
const before = beforeCursor();
|
||||||
|
const after = afterCursor();
|
||||||
|
let [padding] = findPadding(before);
|
||||||
|
let newLinePadding = padding;
|
||||||
|
// If last symbol is "{" ident new line
|
||||||
|
if (options.indentOn.test(before)) {
|
||||||
|
newLinePadding += options.tab;
|
||||||
|
}
|
||||||
|
// Preserve padding
|
||||||
|
if (newLinePadding.length > 0) {
|
||||||
|
preventDefault(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
insert('\n' + newLinePadding);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
legacyNewLineFix(event);
|
||||||
|
}
|
||||||
|
// Place adjacent "}" on next line
|
||||||
|
if (newLinePadding !== padding && options.moveToNewLine.test(after)) {
|
||||||
|
const pos = save();
|
||||||
|
insert('\n' + padding);
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function legacyNewLineFix(event) {
|
||||||
|
// Firefox does not support plaintext-only mode
|
||||||
|
// and puts <div><br></div> on Enter. Let's help.
|
||||||
|
if (isLegacy && event.key === 'Enter') {
|
||||||
|
preventDefault(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
if (afterCursor() == '') {
|
||||||
|
insert('\n ');
|
||||||
|
const pos = save();
|
||||||
|
pos.start = --pos.end;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insert('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleSelfClosingCharacters(event) {
|
||||||
|
const open = `([{'"`;
|
||||||
|
const close = `)]}'"`;
|
||||||
|
if (open.includes(event.key)) {
|
||||||
|
preventDefault(event);
|
||||||
|
const pos = save();
|
||||||
|
const wrapText = pos.start == pos.end ? '' : getSelection().toString();
|
||||||
|
const text = event.key + wrapText + close[open.indexOf(event.key)];
|
||||||
|
insert(text);
|
||||||
|
pos.start++;
|
||||||
|
pos.end++;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleTabCharacters(event) {
|
||||||
|
if (event.key === 'Tab') {
|
||||||
|
preventDefault(event);
|
||||||
|
if (event.shiftKey) {
|
||||||
|
const before = beforeCursor();
|
||||||
|
let [padding, start,] = findPadding(before);
|
||||||
|
if (padding.length > 0) {
|
||||||
|
const pos = save();
|
||||||
|
// Remove full length tab or just remaining padding
|
||||||
|
const len = Math.min(options.tab.length, padding.length);
|
||||||
|
restore({ start, end: start + len });
|
||||||
|
document.execCommand('delete');
|
||||||
|
pos.start -= len;
|
||||||
|
pos.end -= len;
|
||||||
|
restore(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insert(options.tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleUndoRedo(event) {
|
||||||
|
if (isUndo(event)) {
|
||||||
|
preventDefault(event);
|
||||||
|
at--;
|
||||||
|
const record = history[at];
|
||||||
|
if (record) {
|
||||||
|
editor.innerHTML = record.html;
|
||||||
|
restore(record.pos);
|
||||||
|
}
|
||||||
|
if (at < 0)
|
||||||
|
at = 0;
|
||||||
|
}
|
||||||
|
if (isRedo(event)) {
|
||||||
|
preventDefault(event);
|
||||||
|
at++;
|
||||||
|
const record = history[at];
|
||||||
|
if (record) {
|
||||||
|
editor.innerHTML = record.html;
|
||||||
|
restore(record.pos);
|
||||||
|
}
|
||||||
|
if (at >= history.length)
|
||||||
|
at--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function recordHistory() {
|
||||||
|
if (!focus)
|
||||||
|
return;
|
||||||
|
const html = editor.innerHTML;
|
||||||
|
const pos = save();
|
||||||
|
const lastRecord = history[at];
|
||||||
|
if (lastRecord) {
|
||||||
|
if (lastRecord.html === html
|
||||||
|
&& lastRecord.pos.start === pos.start
|
||||||
|
&& lastRecord.pos.end === pos.end)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
at++;
|
||||||
|
history[at] = { html, pos };
|
||||||
|
history.splice(at + 1);
|
||||||
|
const maxHistory = 300;
|
||||||
|
if (at > maxHistory) {
|
||||||
|
at = maxHistory;
|
||||||
|
history.splice(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handlePaste(event) {
|
||||||
|
preventDefault(event);
|
||||||
|
const text = (event.originalEvent || event)
|
||||||
|
.clipboardData
|
||||||
|
.getData('text/plain')
|
||||||
|
.replace(/\r\n?/g, '\n');
|
||||||
|
const pos = save();
|
||||||
|
insert(text);
|
||||||
|
highlight(editor);
|
||||||
|
restore({
|
||||||
|
start: Math.min(pos.start, pos.end) + text.length,
|
||||||
|
end: Math.min(pos.start, pos.end) + text.length,
|
||||||
|
dir: '<-',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function handleCut(event) {
|
||||||
|
const pos = save();
|
||||||
|
const selection = getSelection();
|
||||||
|
const originalEvent = event.originalEvent ?? event;
|
||||||
|
originalEvent.clipboardData.setData("text/plain", selection.toString());
|
||||||
|
document.execCommand('delete');
|
||||||
|
highlight(editor);
|
||||||
|
restore({
|
||||||
|
start: pos.start,
|
||||||
|
end: pos.start,
|
||||||
|
dir: '->',
|
||||||
|
});
|
||||||
|
preventDefault(event);
|
||||||
|
}
|
||||||
|
function visit(editor, visitor) {
|
||||||
|
const queue = [];
|
||||||
|
if (editor.firstChild)
|
||||||
|
queue.push(editor.firstChild);
|
||||||
|
let el = queue.pop();
|
||||||
|
while (el) {
|
||||||
|
if (visitor(el) === 'stop')
|
||||||
|
break;
|
||||||
|
if (el.nextSibling)
|
||||||
|
queue.push(el.nextSibling);
|
||||||
|
if (el.firstChild)
|
||||||
|
queue.push(el.firstChild);
|
||||||
|
el = queue.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function isCtrl(event) {
|
||||||
|
return event.metaKey || event.ctrlKey;
|
||||||
|
}
|
||||||
|
function isUndo(event) {
|
||||||
|
return isCtrl(event) && !event.shiftKey && getKeyCode(event) === 'Z';
|
||||||
|
}
|
||||||
|
function isRedo(event) {
|
||||||
|
return isCtrl(event) && event.shiftKey && getKeyCode(event) === 'Z';
|
||||||
|
}
|
||||||
|
function isCopy(event) {
|
||||||
|
return isCtrl(event) && getKeyCode(event) === 'C';
|
||||||
|
}
|
||||||
|
function getKeyCode(event) {
|
||||||
|
let key = event.key || event.keyCode || event.which;
|
||||||
|
if (!key)
|
||||||
|
return undefined;
|
||||||
|
return (typeof key === 'string' ? key : String.fromCharCode(key)).toUpperCase();
|
||||||
|
}
|
||||||
|
function insert(text) {
|
||||||
|
text = text
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
document.execCommand('insertHTML', false, text);
|
||||||
|
}
|
||||||
|
function debounce(cb, wait) {
|
||||||
|
let timeout = 0;
|
||||||
|
return (...args) => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = window.setTimeout(() => cb(...args), wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function findPadding(text) {
|
||||||
|
// Find beginning of previous line.
|
||||||
|
let i = text.length - 1;
|
||||||
|
while (i >= 0 && text[i] !== '\n')
|
||||||
|
i--;
|
||||||
|
i++;
|
||||||
|
// Find padding of the line.
|
||||||
|
let j = i;
|
||||||
|
while (j < text.length && /[ \t]/.test(text[j]))
|
||||||
|
j++;
|
||||||
|
return [text.substring(i, j) || '', i, j];
|
||||||
|
}
|
||||||
|
function toString() {
|
||||||
|
return editor.textContent || '';
|
||||||
|
}
|
||||||
|
function preventDefault(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
function getSelection() {
|
||||||
|
if (editor.parentNode?.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
|
||||||
|
return editor.parentNode.getSelection();
|
||||||
|
}
|
||||||
|
return window.getSelection();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
updateOptions(newOptions) {
|
||||||
|
Object.assign(options, newOptions);
|
||||||
|
},
|
||||||
|
updateCode(code) {
|
||||||
|
editor.textContent = code;
|
||||||
|
highlight(editor);
|
||||||
|
if (callback)
|
||||||
|
callback(code);
|
||||||
|
},
|
||||||
|
onUpdate(cb) {
|
||||||
|
callback = cb;
|
||||||
|
},
|
||||||
|
toString,
|
||||||
|
save,
|
||||||
|
restore,
|
||||||
|
recordHistory,
|
||||||
|
destroy() {
|
||||||
|
for (let [type, fn] of listeners) {
|
||||||
|
editor.removeEventListener(type, fn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browser global shim: surface CodeJar on window so non-module
|
||||||
|
// <script> tags can call it.
|
||||||
|
window.CodeJar = CodeJar;
|
||||||
1
l4d2web/l4d2web/static/vendor/prism.css
vendored
Normal file
1
l4d2web/l4d2web/static/vendor/prism.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
||||||
4
l4d2web/l4d2web/static/vendor/prism.js
vendored
Normal file
4
l4d2web/l4d2web/static/vendor/prism.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue