Claude-Session: https://claude.ai/code/session_01GGe7kUhooMFuzY6GaDb2w9
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
[{"type":"page","title":"Forside","url":"/"},{"type":"page","title":"CV","url":"/cv"},{"type":"page","title":"CV (English)","url":"/en/cv"},{"type":"page","title":"Home (English)","url":"/en"},{"type":"page","title":"Ask my CV (English)","url":"/en/chat"},{"type":"page","title":"Projekter","url":"/projekter"},
|
||||
{%- for p in pages %}{% if p.components[0] == "projekter" %}{"type":"page","title":{{ ("Projekt: " ~ p.title) | json_encode | safe }},"url":"{{ p.path | trim_end(pat="/") }}","extra":{{ [p.extra.sprog, ...p.extra.aur, ...p.extra.tags] | join(sep=" ") | json_encode | safe }}},{% elif p.components[0] == "en" %}{"type":"page","title":{{ ("Project: " ~ p.title ~ " (English)") | json_encode | safe }},"url":"{{ p.path | trim_end(pat="/") }}","extra":{{ [p.extra.sprog, ...p.extra.aur, ...p.extra.tags] | join(sep=" ") | json_encode | safe }}},{% endif %}{% endfor -%}
|
||||
{"type":"page","title":"Færdigbyggede pakker (tarballz)","url":"/tarballz/"},{"type":"page","title":"Blog","url":"/blog"},{"type":"page","title":"Tags","url":"/tags"},{"type":"page","title":"Profil-opslag (Nemhandel & Peppol)","url":"/profiler"},{"type":"page","title":"UBL-tjek & identifikator-afkoder","url":"/ubl"},{"type":"page","title":"Spørg mit CV (AI-chat)","url":"/chat"},{"type":"page","title":"Status (homelab)","url":"/status"},{"type":"page","title":"Now","url":"/now"},{"type":"page","title":"Uses","url":"/uses"},{"type":"page","title":"Kolofon","url":"/colophon"},{"type":"page","title":"Cookies","url":"/cookies"}
|
||||
{"type":"page","title":"Færdigbyggede pakker (tarballz)","url":"/tarballz/"},{"type":"page","title":"Blog","url":"/blog"},{"type":"page","title":"Tags","url":"/tags"},{"type":"page","title":"Spørg mit CV (AI-chat)","url":"/chat"},{"type":"page","title":"Status (homelab)","url":"/status"},{"type":"page","title":"Now","url":"/now"},{"type":"page","title":"Uses","url":"/uses"},{"type":"page","title":"Kolofon","url":"/colophon"},{"type":"page","title":"Cookies","url":"/cookies"}
|
||||
{%- for p in pages %}{% if p.components[0] == "blog" %},{"type":"post","title":{{ p.title | json_encode | safe }},"url":"{{ p.path | trim_end(pat="/") }}","extra":{{ p.taxonomies.tags | default(value=[]) | join(sep=" ") | json_encode | safe }}}{% endif %}{% endfor %}]
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
{% set d = load_data(path="data/profiles.json") %}
|
||||
<h1 class="text-4xl font-bold tracking-tight">Profil-opslag</h1>
|
||||
<p class="mt-4 max-w-2xl text-muted">
|
||||
Browse og søg i e-dokumentprofilerne for <strong class="text-text">Nemhandel OIOUBL</strong> og
|
||||
<strong class="text-text">Peppol BIS/PINT</strong>: profil-/proces-id, customization-id, hvilke
|
||||
dokumenter profilen indeholder og typisk anvendelse. Klik på et id for at kopiere det.
|
||||
</p>
|
||||
<p class="mt-3 max-w-2xl text-sm text-muted">
|
||||
De danske profiler står i samme rækkefølge og under samme gruppenavne som i
|
||||
<strong class="text-text">Nemhandelsregistrets</strong> profil-dropdown (“Profiler for: …”), så du kan
|
||||
slå direkte op mellem registrering og dokumentindhold.
|
||||
</p>
|
||||
|
||||
<div class="mt-8 flex flex-col gap-4 sm:flex-row sm:items-center">
|
||||
<div class="relative flex-1">
|
||||
<span class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted">⌕</span>
|
||||
<input
|
||||
id="p-search"
|
||||
type="search"
|
||||
placeholder="Søg profil, id, dokument…"
|
||||
autocomplete="off"
|
||||
aria-label="Søg profiler"
|
||||
class="w-full wt-input wt-input--lg pl-9"
|
||||
/>
|
||||
</div>
|
||||
<span id="p-count" class="text-sm text-muted">{{ d.profiles | length }} profiler</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
<button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-std="" aria-pressed="true">Alle</button>
|
||||
{% for s in d.standarder %}<button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-std="{{ s }}" aria-pressed="false">{{ s }}</button>{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="mr-2 text-xs text-muted">Nemhandelsregistrets kategori:</span>
|
||||
<span class="mt-1 inline-flex flex-wrap gap-2 align-middle">
|
||||
<button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-kat="" aria-pressed="true">Alle</button>
|
||||
{% for k in d.kategorier %}<button type="button" class="wt-btn wt-btn--ghost wt-btn--sm" data-kat="{{ k }}" aria-pressed="false">{{ k }}</button>{% endfor %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 space-y-3">
|
||||
{%- for p in d.profiles %}
|
||||
<article
|
||||
data-profile
|
||||
data-standard="{{ p.standard }}"
|
||||
data-kategori="{{ p.kategori }}"
|
||||
data-search="{{ (p.standard ~ " " ~ p.kategori ~ " " ~ p.navn ~ " " ~ p.id ~ " " ~ p.customization ~ " " ~ (p.dokumenter | join(sep=" ")) ~ " " ~ p.anvendelse ~ " " ~ p.bemaerkninger) | lower }}"
|
||||
class="wt-card wt-card--hover"
|
||||
>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="wt-tag wt-tag--accent">
|
||||
{{ p.standard }}
|
||||
</span>
|
||||
{% if p.kategori %}
|
||||
<span
|
||||
class="wt-tag wt-muted"
|
||||
title="Gruppen profilen står under i Nemhandelsregistrets dropdown"
|
||||
>
|
||||
Register: {{ p.kategori }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h2 class="mt-2 text-lg font-semibold tracking-tight">{{ p.navn }}</h2>
|
||||
|
||||
<dl class="mt-3 grid gap-1 text-xs sm:grid-cols-[10rem_1fr]">
|
||||
<dt class="text-muted">Profil/proces-id</dt>
|
||||
<dd>
|
||||
<button type="button" data-copy="{{ p.id }}" title="Klik for at kopiere" class="copy break-all text-left font-mono">
|
||||
{{ p.id }}
|
||||
</button>
|
||||
</dd>
|
||||
<dt class="text-muted">Customization-id</dt>
|
||||
<dd>
|
||||
<button type="button" data-copy="{{ p.customization }}" title="Klik for at kopiere" class="copy break-all text-left font-mono">
|
||||
{{ p.customization }}
|
||||
</button>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<div class="mt-3 flex flex-wrap gap-1.5">
|
||||
{% for doc in p.dokumenter %}
|
||||
<span class="wt-tag">{{ doc }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<p class="mt-3 text-sm text-muted">{{ p.anvendelse }}</p>
|
||||
<p class="mt-2 text-xs text-muted">
|
||||
<span class="font-semibold text-muted">Bemærk:</span> {{ p.bemaerkninger }}
|
||||
</p>
|
||||
<p class="mt-3 text-xs"><a href="{{ p.kilde.url | safe }}" target="_blank" rel="noopener" class="text-accent/80 transition-colors hover:text-accent">Kilde: {{ p.kilde.label }} ↗</a></p>
|
||||
</article>
|
||||
{%- endfor %}
|
||||
</div>
|
||||
|
||||
<p id="p-none" class="mt-6 text-sm text-muted" hidden>Ingen profiler matcher.</p>
|
||||
|
||||
<p class="mt-10 text-xs text-muted">
|
||||
Kilder: OIOUBL Profiler-guiden (G26) v1.3 (dokumentlister, tabel 1-3), Nemhandelsregistret
|
||||
(gruppering og profilnavne) og Peppol BIS/PINT (docs.peppol.eu). * = ApplicationResponse bruges kun
|
||||
til afvisning; det forretningsmæssige svar på en ordre er altid OrderResponse/OrderResponseSimple.
|
||||
Øjebliksbillede.. verificér altid id'er mod den officielle dokumentation før brug.
|
||||
</p>
|
||||
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var cards = [].slice.call(document.querySelectorAll('[data-profile]'));
|
||||
var search = document.getElementById('p-search');
|
||||
var stdChips = [].slice.call(document.querySelectorAll('button[data-std]'));
|
||||
var katChips = [].slice.call(document.querySelectorAll('button[data-kat]'));
|
||||
var count = document.getElementById('p-count');
|
||||
var none = document.getElementById('p-none');
|
||||
var q = '', std = '', kat = '';
|
||||
function apply() {
|
||||
var shown = 0;
|
||||
cards.forEach(function (c) {
|
||||
var okS = !std || c.getAttribute('data-standard') === std;
|
||||
var okK = !kat || c.getAttribute('data-kategori') === kat;
|
||||
var okQ = !q || c.getAttribute('data-search').indexOf(q) > -1;
|
||||
var hit = okS && okK && okQ;
|
||||
c.hidden = !hit;
|
||||
if (hit) shown++;
|
||||
});
|
||||
count.textContent = shown + (shown === 1 ? ' profil' : ' profiler');
|
||||
none.hidden = shown > 0;
|
||||
}
|
||||
search.addEventListener('input', function () { q = search.value.trim().toLowerCase(); apply(); });
|
||||
function wire(group, attr, set) {
|
||||
group.forEach(function (b) {
|
||||
b.addEventListener('click', function () {
|
||||
set(b.getAttribute(attr) || '');
|
||||
group.forEach(function (x) { x.setAttribute('aria-pressed', x === b ? 'true' : 'false'); });
|
||||
apply();
|
||||
});
|
||||
});
|
||||
}
|
||||
wire(stdChips, 'data-std', function (v) { std = v; });
|
||||
wire(katChips, 'data-kat', function (v) { kat = v; });
|
||||
document.addEventListener('click', function (e) {
|
||||
var btn = e.target.closest && e.target.closest('[data-copy]');
|
||||
if (!btn || !navigator.clipboard) return;
|
||||
navigator.clipboard.writeText(btn.getAttribute('data-copy')).then(function () {
|
||||
var orig = btn.textContent;
|
||||
btn.textContent = 'kopieret ✓';
|
||||
setTimeout(function () { btn.textContent = orig; }, 1200);
|
||||
}).catch(function () {});
|
||||
});
|
||||
var qp = new URLSearchParams(location.search).get('q');
|
||||
if (qp) { search.value = qp; q = qp.trim().toLowerCase(); }
|
||||
apply();
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,184 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% block main %}
|
||||
{% set d = load_data(path="data/profiles.json") %}
|
||||
<h1 class="text-4xl font-bold tracking-tight">UBL-tjek</h1>
|
||||
<p class="mt-4 max-w-2xl text-muted">
|
||||
Træk en <strong class="text-text">UBL/OIOUBL-faktura</strong> (eller andet UBL-dokument) ind, eller indsæt en
|
||||
<strong class="text-text">CustomizationID/ProfileID</strong>, så afkoder den profilen, syntaksen og
|
||||
EN 16931-status og kobler til <a href="/profiler" class="text-accent">profil-opslaget</a>.
|
||||
Alt sker <strong class="text-text">lokalt i din browser</strong>; intet sendes nogen steder.
|
||||
</p>
|
||||
<p class="mt-3 max-w-2xl text-muted">
|
||||
Vil du læse hele fakturaen eller have den vedhæftede PDF ud, så har jeg skrevet
|
||||
<a href="/projekter/ubl-tools" class="text-accent hover:underline">ubl-tools</a> til terminalen,
|
||||
også på Windows og macOS.
|
||||
</p>
|
||||
|
||||
<div id="drop" class="mt-8 wt-dropzone">
|
||||
<p class="text-muted">Træk en <code class="rounded bg-surface-2 px-1.5 py-0.5">.xml</code>-fil hertil, eller
|
||||
<label class="cursor-pointer text-accent hover:underline">vælg en fil<input id="file" type="file" accept=".xml,text/xml,application/xml" class="hidden" /></label>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<details class="mt-3">
|
||||
<summary class="cursor-pointer text-sm text-muted">…eller indsæt XML / en identifikator manuelt</summary>
|
||||
<textarea id="paste" rows="6" placeholder="Indsæt UBL-XML, eller bare en CustomizationID/ProfileID…"
|
||||
class="mt-2 w-full wt-input wt-input--lg font-mono text-xs"></textarea>
|
||||
<p class="mt-2"><button id="analyze" type="button" class="wt-btn wt-btn--primary">Afkod</button></p>
|
||||
</details>
|
||||
|
||||
<div id="result" class="mt-6" hidden></div>
|
||||
<p id="err" class="mt-6 text-sm" hidden></p>
|
||||
|
||||
<p class="mt-10 text-xs text-muted/80">
|
||||
Heuristik mod kendte profiler (samme datagrundlag som <a href="/profiler" class="text-accent">/profiler</a>) +
|
||||
EN 16931-/Peppol-/OIOUBL-mønstre. Privat: ingen upload, ingen sporing af indholdet.
|
||||
</p>
|
||||
|
||||
<script type="application/json" id="profiles-data" >[{% for p in d.profiles %}{"standard":{{ p.standard | json_encode | safe }},"navn":{{ p.navn | json_encode | safe }},"id":{{ p.id | json_encode | safe }},"customization":{{ p.customization | json_encode | safe }},"dokumenter":{{ p.dokumenter | json_encode | safe }}}{% if not loop.last %},{% endif %}{% endfor %}]</script>
|
||||
<script>
|
||||
(function () {
|
||||
var PROFILES = JSON.parse(document.getElementById('profiles-data').textContent || '[]');
|
||||
var drop = document.getElementById('drop'), fileInput = document.getElementById('file'),
|
||||
paste = document.getElementById('paste'), result = document.getElementById('result'),
|
||||
err = document.getElementById('err');
|
||||
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) {
|
||||
return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); };
|
||||
|
||||
// Electronic Address Scheme (ISO 6523): de gængse, DK/Norden i fokus.
|
||||
var EAS = {
|
||||
'0088': 'GLN (GS1 Global Location Number)',
|
||||
'0184': 'DK:CVR (dansk CVR-nummer)',
|
||||
'0198': 'DK:SE (dansk SE-nummer)',
|
||||
'0096': 'DK:P (dansk P-nummer)',
|
||||
'0192': 'NO:ORG (norsk organisasjonsnummer)',
|
||||
'0007': 'SE:ORG (svensk organisationsnummer)',
|
||||
'0208': 'BE:CBE (belgisk virksomhedsnr.)',
|
||||
'0151': 'AU:ABN', '0060': 'DUNS', '0235': 'JP', '0211': 'IT:PA',
|
||||
'9915': 'Peppol test-deltager', '9930': 'DE:LWID (Leitweg-ID)',
|
||||
};
|
||||
|
||||
function findEl(doc, name) {
|
||||
var all = doc.getElementsByTagName('*');
|
||||
for (var i = 0; i < all.length; i++) if (all[i].localName === name) return all[i];
|
||||
return null;
|
||||
}
|
||||
function txt(doc, name) { var e = findEl(doc, name); return e ? (e.textContent || '').trim() : ''; }
|
||||
|
||||
// afkod en CustomizationID/ProfileID-streng til menneskesprog
|
||||
function decode(custom, profile) {
|
||||
var notes = [], standard = null, match = null;
|
||||
var c = (custom || '').trim(), p = (profile || '').trim();
|
||||
|
||||
// 1) eksakt match mod kendte profiler
|
||||
match = PROFILES.find(function (x) { return c && x.customization === c; })
|
||||
|| PROFILES.find(function (x) { return p && x.id === p; })
|
||||
|| PROFILES.find(function (x) { return c && x.id === c; });
|
||||
|
||||
// 2) mønster-heuristik (også når der ikke er fuldt match)
|
||||
var blob = (c + ' ' + p).toLowerCase();
|
||||
if (blob.indexOf('en16931') > -1) notes.push('EN 16931-kompatibel (CIUS af den europæiske kernefaktura)');
|
||||
if (blob.indexOf('peppol.eu') > -1 || blob.indexOf('fdc:peppol') > -1) { standard = 'Peppol BIS'; notes.push('Peppol-netværket'); }
|
||||
if (blob.indexOf('pint') > -1) { standard = 'Peppol PINT'; notes.push('PINT (Peppol International)'); }
|
||||
if (blob.indexOf('billing:3.0') > -1) notes.push('Billing 3.0-proces');
|
||||
if (blob.indexOf('selfbilling') > -1) notes.push('Selvfakturering (køber udsteder)');
|
||||
if (blob.indexOf('oioubl') > -1) { standard = standard || 'OIOUBL (NemHandel)'; notes.push('OIOUBL, dansk UBL-tilpasning'); }
|
||||
if (/procurement-/i.test(p)) { standard = standard || 'OIOUBL (NemHandel)'; if (/r-|r$|simr|advr/i.test(p)) notes.push("'R' = svar påkrævet"); }
|
||||
|
||||
return { match: match, standard: match ? match.standard : standard, notes: notes };
|
||||
}
|
||||
|
||||
function badge(text, kind) {
|
||||
return '<span class="wt-tag' + (kind === 'ok' ? ' wt-tag--accent' : '') + '">' + esc(text) + '</span>';
|
||||
}
|
||||
function row(dt, dd) {
|
||||
return '<div class="grid gap-1 sm:grid-cols-[10rem_1fr]"><dt class="text-muted">' + esc(dt) +
|
||||
'</dt><dd class="break-all font-mono">' + (dd || '<span class="text-muted">—</span>') + '</dd></div>';
|
||||
}
|
||||
|
||||
function renderXml(doc) {
|
||||
var root = doc.documentElement;
|
||||
var docType = root ? root.localName : '?';
|
||||
var ublv = txt(doc, 'UBLVersionID');
|
||||
var custom = txt(doc, 'CustomizationID');
|
||||
var profile = txt(doc, 'ProfileID');
|
||||
var id = txt(doc, 'ID');
|
||||
var dec = decode(custom, profile);
|
||||
|
||||
// EAS på parter
|
||||
var endpoints = [];
|
||||
var eps = doc.getElementsByTagName('*');
|
||||
for (var i = 0; i < eps.length; i++) {
|
||||
if (eps[i].localName === 'EndpointID') {
|
||||
var scheme = eps[i].getAttribute('schemeID') || '';
|
||||
endpoints.push({ scheme: scheme, val: (eps[i].textContent || '').trim() });
|
||||
}
|
||||
}
|
||||
var epHtml = endpoints.slice(0, 4).map(function (e) {
|
||||
return '<div>' + badge((EAS[e.scheme] || ('EAS ' + e.scheme || 'ukendt')), '') +
|
||||
' <span class="font-mono text-xs">' + esc(e.val) + '</span></div>';
|
||||
}).join('');
|
||||
|
||||
var head = dec.match
|
||||
? '<div class="flex flex-wrap items-center gap-2">' + badge(dec.match.standard, 'ok') +
|
||||
'</div><h2 class="mt-2 text-xl font-semibold tracking-tight">' + esc(dec.match.navn) + '</h2>'
|
||||
: '<h2 class="text-xl font-semibold tracking-tight">' + esc(docType) +
|
||||
(dec.standard ? ' <span class="text-muted text-base font-normal">· ' + esc(dec.standard) + '</span>' : '') + '</h2>';
|
||||
|
||||
result.innerHTML =
|
||||
'<div class="wt-card">' + head +
|
||||
'<dl class="mt-3 space-y-1 text-xs">' +
|
||||
row('Dokumenttype', '<span class="font-semibold">' + esc(docType) + '</span> (UBL ' + (esc(ublv) || '2.x') + ')') +
|
||||
row('ID', esc(id)) +
|
||||
row('ProfileID', esc(profile)) +
|
||||
row('CustomizationID', esc(custom)) +
|
||||
'</dl>' +
|
||||
(dec.notes.length ? '<div class="mt-3 flex flex-wrap gap-1.5">' + dec.notes.map(function (n) { return badge(n, ''); }).join('') + '</div>' : '') +
|
||||
(epHtml ? '<p class="mt-3 text-xs text-muted">Parter (EAS):</p><div class="mt-1 space-y-1">' + epHtml + '</div>' : '') +
|
||||
(dec.match ? '<p class="mt-3 text-xs"><a class="text-accent hover:underline" href="/profiler?q=' + encodeURIComponent(dec.match.id) + '">Se profilen i /profiler ↗</a></p>'
|
||||
: '<p class="mt-3 text-xs text-muted">Ingen eksakt match i profil-databasen, afkodet ud fra mønstre.</p>') +
|
||||
'</div>';
|
||||
result.hidden = false; err.hidden = true;
|
||||
}
|
||||
|
||||
function renderId(s) {
|
||||
var dec = decode(s, s);
|
||||
result.innerHTML = '<div class="wt-card">' +
|
||||
(dec.match ? '<div class="flex flex-wrap items-center gap-2">' + badge(dec.match.standard, 'ok') +
|
||||
'</div><h2 class="mt-2 text-xl font-semibold tracking-tight">' + esc(dec.match.navn) + '</h2>'
|
||||
: '<h2 class="text-xl font-semibold tracking-tight">Identifikator</h2>') +
|
||||
'<dl class="mt-3 space-y-1 text-xs">' + row('Streng', esc(s)) + '</dl>' +
|
||||
(dec.notes.length ? '<div class="mt-3 flex flex-wrap gap-1.5">' + dec.notes.map(function (n) { return badge(n, ''); }).join('') + '</div>'
|
||||
: '<p class="mt-3 text-xs text-muted">Genkendte ingen kendte mønstre.</p>') +
|
||||
(dec.match ? '<p class="mt-3 text-xs"><a class="text-accent hover:underline" href="/profiler?q=' + encodeURIComponent(dec.match.id) + '">Se profilen i /profiler ↗</a></p>' : '') +
|
||||
'</div>';
|
||||
result.hidden = false; err.hidden = true;
|
||||
}
|
||||
|
||||
function analyze(text) {
|
||||
text = (text || '').trim();
|
||||
if (!text) return;
|
||||
if (text.indexOf('<') === 0 || text.indexOf('<?xml') === 0) {
|
||||
var doc = new DOMParser().parseFromString(text, 'application/xml');
|
||||
if (doc.getElementsByTagName('parsererror').length) {
|
||||
err.textContent = 'Kunne ikke parse XML.. er filen velformet?'; err.hidden = false; result.hidden = true; return;
|
||||
}
|
||||
renderXml(doc);
|
||||
} else {
|
||||
renderId(text);
|
||||
}
|
||||
}
|
||||
|
||||
// fil-input + drag/drop
|
||||
function readFile(f) { var r = new FileReader(); r.onload = function () { analyze(String(r.result)); }; r.readAsText(f); }
|
||||
fileInput.addEventListener('change', function () { if (fileInput.files[0]) readFile(fileInput.files[0]); });
|
||||
['dragenter', 'dragover'].forEach(function (ev) { drop.addEventListener(ev, function (e) {
|
||||
e.preventDefault(); drop.classList.add('is-over'); }); });
|
||||
['dragleave', 'drop'].forEach(function (ev) { drop.addEventListener(ev, function (e) {
|
||||
e.preventDefault(); drop.classList.remove('is-over'); }); });
|
||||
drop.addEventListener('drop', function (e) { var f = e.dataTransfer && e.dataTransfer.files[0]; if (f) readFile(f); });
|
||||
document.getElementById('analyze').addEventListener('click', function () { analyze(paste.value); });
|
||||
paste.addEventListener('keydown', function (e) { if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') analyze(paste.value); });
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user