diff --git a/assets/editor.js b/assets/editor.js index 17de39c..93e4a32 100644 --- a/assets/editor.js +++ b/assets/editor.js @@ -58,6 +58,7 @@ var T = EditorTables; var L = EditorLists; var D = EditorDates; + var M = EditorMovie; var actions = { save: function () { form.submit(); }, @@ -100,6 +101,7 @@ tbldeleterow: function () { applyTableOp(T.deleteRow); }, dateiso: function () { insertAtCursor(D.isoDate()); }, datelong: function () { insertAtCursor(D.longDate()); }, + movie: function () { M.run(textarea); }, }; // --- Keyboard shortcut registration --- diff --git a/assets/editor/movie.js b/assets/editor/movie.js new file mode 100644 index 0000000..491a319 --- /dev/null +++ b/assets/editor/movie.js @@ -0,0 +1,121 @@ +window.EditorMovie = (function () { + 'use strict'; + + // OMDb API key. Shipped to the browser; acceptable for a single-user LAN tool. + var OMDB_API_KEY = ''; + + var BEGIN = ''; + var END = ''; + + function firstHeading(text) { + var m = text.match(/^#{1,6}\s+(.+?)\s*$/m); + return m ? m[1].trim() : ''; + } + + function parseTitleYear(raw) { + var m = raw.match(/^(.+?)\s*\((\d{4})\)\s*$/); + return m ? { title: m[1].trim(), year: m[2] } : { title: raw.trim(), year: null }; + } + + function safe(v) { return (!v || v === 'N/A') ? '' : String(v); } + + function esc(s) { + return String(s) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + } + + function buildBlock(m) { + var out = [BEGIN, '', END); + return out.join('\n'); + } + + function insertOrReplace(ta, markup) { + var t = ta.value || ''; + var b = t.indexOf(BEGIN); + var e = t.indexOf(END); + if (b !== -1 && e !== -1 && e > b) { + ta.value = t.slice(0, b) + markup + t.slice(e + END.length); + } else { + var h = t.match(/^#{1,6}\s+.+?\s*$/m); + if (h) { + var idx = t.indexOf(h[0]) + h[0].length; + ta.value = t.slice(0, idx) + '\n\n' + markup + t.slice(idx); + } else { + ta.value = markup + (t ? '\n\n' + t : ''); + } + } + ta.dispatchEvent(new Event('input')); + } + + function fetchMovie(title, year) { + var url = 'https://www.omdbapi.com/?apikey=' + encodeURIComponent(OMDB_API_KEY) + + '&type=movie&t=' + encodeURIComponent(title); + if (year) url += '&y=' + encodeURIComponent(year); + return fetch(url).then(function (r) { return r.json(); }); + } + + function showMessage(title, msg) { + openModal({ title: title, body: msg, confirm: { label: 'OK' } }); + } + + function run(textarea) { + if (!OMDB_API_KEY) { + showMessage('Movie import', 'OMDb API key is not set. Edit assets/editor/movie.js.'); + return; + } + + var input = document.createElement('input'); + input.type = 'text'; + input.className = 'modal-input'; + input.placeholder = 'Title, optionally with (YYYY)'; + input.value = firstHeading(textarea.value || ''); + + openModal({ + title: 'Import movie', + body: input, + confirm: { + label: 'IMPORT', + onConfirm: function () { + var raw = input.value.trim(); + if (!raw) return; + var parsed = parseTitleYear(raw); + closeModal(); + fetchMovie(parsed.title, parsed.year) + .then(function (data) { + if (!data || data.Response === 'False') { + showMessage('Not found', + (data && data.Error) || 'Movie not found.'); + return; + } + insertOrReplace(textarea, buildBlock(data)); + }) + .catch(function () { + showMessage('Import failed', 'OMDb lookup failed.'); + }); + }, + }, + }); + } + + return { run: run }; +})(); diff --git a/assets/page.html b/assets/page.html index 67ecba8..d368cb7 100644 --- a/assets/page.html +++ b/assets/page.html @@ -62,12 +62,15 @@ + + + {{else}} {{if .Content}} diff --git a/assets/style.css b/assets/style.css index c03ea43..462c8cf 100644 --- a/assets/style.css +++ b/assets/style.css @@ -584,6 +584,31 @@ hr { word-break: break-all; } +/* === Movie info box === */ +.movie-info { + margin: 0.75rem 0; +} +.movie-info::after { + content: ""; + display: block; + clear: both; +} +.movie-info .movie-poster { + float: right; + max-width: 200px; + margin: 0 0 0.75rem 1rem; +} +.movie-info table { + width: auto; +} +@media (max-width: 600px) { + .movie-info .movie-poster { + float: none; + display: block; + margin: 0 auto 0.75rem; + } +} + /* === Diary Calendar === */ .diary-cal { position: fixed;