/* global window, jQuery */ /** * Movie Import toolbar button for luxtools. * * Fetches movie metadata from OMDb (client-side) and inserts/replaces * a wiki markup block in the editor. * * The OMDb API key is intentionally passed to the browser via JSINFO. * It will be visible in browser developer tools and network requests. * This is an accepted tradeoff for this single-user LAN deployment. */ (function () { 'use strict'; var MARKER_BEGIN = ''; var MARKER_END = ''; /** * Get the OMDb API key from JSINFO (set by PHP in action.php). */ function getApiKey() { if (window.JSINFO && window.JSINFO.luxtools_omdb_apikey) { return String(window.JSINFO.luxtools_omdb_apikey); } return ''; } /** * Get localized string from DokuWiki's LANG object. */ function lang(key, fallback) { if (window.LANG && window.LANG.plugins && window.LANG.plugins.luxtools && window.LANG.plugins.luxtools[key]) { return String(window.LANG.plugins.luxtools[key]); } return fallback || key; } /** * Extract the first heading from the editor text. * DokuWiki headings use ====== Heading ====== syntax. * Returns the heading text trimmed, or empty string. */ function extractFirstHeading(text) { var match = text.match(/^={2,6}\s*(.+?)\s*={2,6}\s*$/m); if (match && match[1]) { return match[1].trim(); } return ''; } /** * Parse a title string that may contain a trailing year in parentheses. * e.g. "Project Hail Mary (2026)" -> { title: "Project Hail Mary", year: "2026" } * e.g. "Inception" -> { title: "Inception", year: null } */ function parseTitleYear(raw) { var match = raw.match(/^(.+?)\s*\((\d{4})\)\s*$/); if (match) { return { title: match[1].trim(), year: match[2] }; } return { title: raw.trim(), year: null }; } /** * Fetch movie data from OMDb. * Returns a Promise that resolves with the parsed JSON response. */ function fetchMovie(apiKey, title, year) { var url = 'https://www.omdbapi.com/?apikey=' + encodeURIComponent(apiKey) + '&type=movie&t=' + encodeURIComponent(title); if (year) { url += '&y=' + encodeURIComponent(year); } return jQuery.ajax({ url: url, dataType: 'json', timeout: 10000 }); } /** * Build the wiki markup block for a movie. */ function buildMarkup(movie) { var lines = []; lines.push(MARKER_BEGIN); // Poster image (omit if N/A or empty) var poster = movie.Poster || ''; if (poster && poster !== 'N/A') { lines.push('{{image>' + poster + '}}'); } // Data table lines.push('^ Title | ' + safe(movie.Title) + ' |'); lines.push('^ Year | ' + safe(movie.Year) + ' |'); lines.push('^ Genre | ' + safe(movie.Genre) + ' |'); lines.push('^ Director | ' + safe(movie.Director) + ' |'); lines.push('^ Actors | ' + safe(movie.Actors) + ' |'); lines.push('^ Plot | ' + safe(movie.Plot) + ' |'); lines.push(MARKER_END); return lines.join('\n'); } /** * Return value for table cell, replacing N/A with empty string. */ function safe(val) { if (!val || val === 'N/A') return ''; return String(val); } /** * Get the editor textarea element by id. */ function getEditor(edid) { var id = edid || 'wiki__text'; return document.getElementById(id); } /** * Main import action: prompt for title, fetch from OMDb, insert/replace markup. */ function importMovie(edid) { var apiKey = getApiKey(); if (!apiKey) { alert(lang('movie_error_no_apikey', 'OMDb API key is not configured. Set it in Admin → luxtools.')); return; } var editor = getEditor(edid); if (!editor) return; var text = editor.value || ''; var heading = extractFirstHeading(text); var defaultTitle = heading || ''; var input = prompt(lang('movie_prompt', 'Enter movie title (optionally with year):'), defaultTitle); if (input === null || input.trim() === '') return; var parsed = parseTitleYear(input.trim()); fetchMovie(apiKey, parsed.title, parsed.year) .done(function (data) { if (!data || data.Response === 'False') { var errMsg = (data && data.Error) ? data.Error : lang('movie_error_not_found', 'Movie not found.'); alert(errMsg); return; } var markup = buildMarkup(data); insertOrReplace(editor, markup); }) .fail(function () { alert(lang('movie_error_fetch', 'OMDb lookup failed.')); }); } /** * Insert movie markup into the editor, replacing an existing movie block if present. */ function insertOrReplace(editor, markup) { var text = editor.value || ''; var beginIdx = text.indexOf(MARKER_BEGIN); var endIdx = text.indexOf(MARKER_END); if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) { // Replace existing block var before = text.substring(0, beginIdx); var after = text.substring(endIdx + MARKER_END.length); editor.value = before + markup + after; } else { // Append after the first heading line, or at the end var headingMatch = text.match(/^(={2,6}\s*.+?\s*={2,6}\s*)$/m); if (headingMatch) { var headingEnd = text.indexOf(headingMatch[0]) + headingMatch[0].length; editor.value = text.substring(0, headingEnd) + '\n\n' + markup + text.substring(headingEnd); } else { editor.value = text + '\n\n' + markup; } } // Trigger input event so DokuWiki knows the content changed try { editor.dispatchEvent(new Event('input', { bubbles: true })); } catch (e) { // IE fallback } } // Register toolbar button action handler. // DokuWiki toolbar looks for window.addBtnAction for custom button types. window.addBtnActionLuxtoolsMovieImport = function ($btn, props, edid) { $btn.on('click', function () { importMovie(edid); return false; }); return 'luxtools-movie-import'; }; })();