Compare commits
3 Commits
e750736a1c
...
14d4a2895a
| Author | SHA1 | Date | |
|---|---|---|---|
| 14d4a2895a | |||
| 59a430938b | |||
| 211418c6c4 |
58
README.md
58
README.md
@@ -189,6 +189,10 @@ Key settings:
|
|||||||
Maximum directory depth for `.pagelink` discovery under each configured root.
|
Maximum directory depth for `.pagelink` discovery under each configured root.
|
||||||
`0` means only the root directory itself is checked.
|
`0` means only the root directory itself is checked.
|
||||||
|
|
||||||
|
- **omdb_apikey**
|
||||||
|
OMDb API key used for the movie import toolbar button. The key is sent to the
|
||||||
|
browser for client-side API requests and will be visible in developer tools.
|
||||||
|
|
||||||
### Template style settings
|
### Template style settings
|
||||||
|
|
||||||
The `{{open>...}}` links and directory “open” links use a dedicated color
|
The `{{open>...}}` links and directory “open” links use a dedicated color
|
||||||
@@ -254,7 +258,43 @@ Supported input examples include:
|
|||||||
- `2026-01-30 13:45`
|
- `2026-01-30 13:45`
|
||||||
- `2026-01-30T13:45:00`
|
- `2026-01-30T13:45:00`
|
||||||
|
|
||||||
### 0.2) Page Link: link a page to a folder
|
### 0.2) Editor toolbar: Movie Import
|
||||||
|
|
||||||
|
The plugin adds a toolbar button for importing movie metadata from the [OMDb API](https://www.omdbapi.com/).
|
||||||
|
|
||||||
|
**Setup:**
|
||||||
|
1. Obtain an OMDb API key from https://www.omdbapi.com/apikey.aspx
|
||||||
|
2. Enter the key in **Admin → luxtools** under "Movie Import (OMDb)".
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
1. Open a page for editing.
|
||||||
|
2. Click the movie icon in the toolbar.
|
||||||
|
3. A prompt appears pre-filled with the first heading from the page (e.g. `Project Hail Mary (2026)`).
|
||||||
|
4. Edit the title if needed and confirm.
|
||||||
|
5. The plugin queries OMDb and inserts a movie metadata block into the editor.
|
||||||
|
|
||||||
|
**Inserted markup example:**
|
||||||
|
```
|
||||||
|
<!-- BEGIN MOVIE -->
|
||||||
|
{{image>https://...poster.jpg}}
|
||||||
|
^ Title | Project Hail Mary |
|
||||||
|
^ Year | 2026 |
|
||||||
|
^ Genre | Adventure, Drama, Sci-Fi |
|
||||||
|
^ Director | Phil Lord, Christopher Miller |
|
||||||
|
^ Actors | Ryan Gosling |
|
||||||
|
^ Plot | A lone astronaut must save Earth... |
|
||||||
|
<!-- END MOVIE -->
|
||||||
|
```
|
||||||
|
|
||||||
|
**Re-import behavior:** Running the import again replaces the existing movie block
|
||||||
|
(delimited by `<!-- BEGIN MOVIE -->` / `<!-- END MOVIE -->` markers) instead of
|
||||||
|
appending a duplicate.
|
||||||
|
|
||||||
|
**Security note:** The OMDb API key is passed to the browser and used for
|
||||||
|
client-side requests. It is visible in browser developer tools and network
|
||||||
|
traffic. This is an intentional tradeoff for this single-user LAN deployment.
|
||||||
|
|
||||||
|
### 0.3) Page Link: link a page to a folder
|
||||||
|
|
||||||
Page linking uses a page-scoped UUID stored in page metadata. This UUID is used
|
Page linking uses a page-scoped UUID stored in page metadata. This UUID is used
|
||||||
to link the page to a folder that contains a `.pagelink` file with the same UUID.
|
to link the page to a folder that contains a `.pagelink` file with the same UUID.
|
||||||
@@ -282,7 +322,7 @@ for example:
|
|||||||
{{directory>blobs/&recursive=1}}
|
{{directory>blobs/&recursive=1}}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 0.3) Calendar widget
|
### 0.4) Calendar widget
|
||||||
|
|
||||||
Render a basic monthly calendar that links each day to canonical chronological pages:
|
Render a basic monthly calendar that links each day to canonical chronological pages:
|
||||||
|
|
||||||
@@ -311,7 +351,7 @@ Notes:
|
|||||||
- Indicator placement in small mode is configured per slot via the `Display` setting.
|
- Indicator placement in small mode is configured per slot via the `Display` setting.
|
||||||
- Slot colors are reused for both indicators and inline event accents.
|
- Slot colors are reused for both indicators and inline event accents.
|
||||||
|
|
||||||
### 0.4) Virtual chronological day pages
|
### 0.5) Virtual chronological day pages
|
||||||
|
|
||||||
When a canonical day page (for example `chronological:2026:02:13`) does not yet
|
When a canonical day page (for example `chronological:2026:02:13`) does not yet
|
||||||
exist, luxtools renders a virtual page in normal show mode instead of the
|
exist, luxtools renders a virtual page in normal show mode instead of the
|
||||||
@@ -326,7 +366,7 @@ The virtual page includes:
|
|||||||
|
|
||||||
The page is only created once you edit and save actual content.
|
The page is only created once you edit and save actual content.
|
||||||
|
|
||||||
### 0.5) Cache invalidation
|
### 0.6) Cache invalidation
|
||||||
|
|
||||||
luxtools provides an admin-only **Invalidate Cache** action in the page tools menu.
|
luxtools provides an admin-only **Invalidate Cache** action in the page tools menu.
|
||||||
|
|
||||||
@@ -338,7 +378,7 @@ luxtools provides an admin-only **Invalidate Cache** action in the page tools me
|
|||||||
permission errors).
|
permission errors).
|
||||||
- Also useful when actively adding external photos to the current day page.
|
- Also useful when actively adding external photos to the current day page.
|
||||||
|
|
||||||
### 0.6) Multi-calendar slot system
|
### 0.7) Multi-calendar slot system
|
||||||
|
|
||||||
The plugin supports 4 calendar slots, each with independent configuration for
|
The plugin supports 4 calendar slots, each with independent configuration for
|
||||||
a local `.ics` file, CalDAV URL, authentication, and display color.
|
a local `.ics` file, CalDAV URL, authentication, and display color.
|
||||||
@@ -352,7 +392,7 @@ a local `.ics` file, CalDAV URL, authentication, and display color.
|
|||||||
Calendar data is always read from local `.ics` files for rendering. If a remote
|
Calendar data is always read from local `.ics` files for rendering. If a remote
|
||||||
CalDAV source is configured, use the sync feature to populate the local file.
|
CalDAV source is configured, use the sync feature to populate the local file.
|
||||||
|
|
||||||
### 0.7) Maintenance task completion
|
### 0.8) Maintenance task completion
|
||||||
|
|
||||||
Maintenance tasks shown on day pages include a "Complete" button. Clicking it:
|
Maintenance tasks shown on day pages include a "Complete" button. Clicking it:
|
||||||
|
|
||||||
@@ -368,7 +408,7 @@ Write-back rules:
|
|||||||
- Recurring events: Completion writes an occurrence override/exception to preserve
|
- Recurring events: Completion writes an occurrence override/exception to preserve
|
||||||
per-occurrence state rather than modifying the master event.
|
per-occurrence state rather than modifying the master event.
|
||||||
|
|
||||||
### 0.8) Event popup
|
### 0.9) Event popup
|
||||||
|
|
||||||
Clicking any event on a day page opens a popup overlay showing:
|
Clicking any event on a day page opens a popup overlay showing:
|
||||||
- Title
|
- Title
|
||||||
@@ -379,7 +419,7 @@ Clicking any event on a day page opens a popup overlay showing:
|
|||||||
|
|
||||||
Close the popup by clicking outside it or pressing Escape.
|
Close the popup by clicking outside it or pressing Escape.
|
||||||
|
|
||||||
### 0.9) Maintenance task list syntax
|
### 0.10) Maintenance task list syntax
|
||||||
|
|
||||||
Embed a list of open maintenance tasks anywhere on a wiki page:
|
Embed a list of open maintenance tasks anywhere on a wiki page:
|
||||||
|
|
||||||
@@ -401,7 +441,7 @@ window are hidden. The default is `30`.
|
|||||||
|
|
||||||
Each task shows its date, optional time, summary, and a "Complete" button.
|
Each task shows its date, optional time, summary, and a "Complete" button.
|
||||||
|
|
||||||
### 0.10) CalDAV sync
|
### 0.11) CalDAV sync
|
||||||
|
|
||||||
If a slot has a CalDAV URL configured, the admin panel provides a sync button.
|
If a slot has a CalDAV URL configured, the admin panel provides a sync button.
|
||||||
Triggering sync downloads all calendar objects from the remote CalDAV collection
|
Triggering sync downloads all calendar objects from the remote CalDAV collection
|
||||||
|
|||||||
32
action.php
32
action.php
@@ -33,6 +33,12 @@ class action_plugin_luxtools extends ActionPlugin
|
|||||||
$this,
|
$this,
|
||||||
"addScripts",
|
"addScripts",
|
||||||
);
|
);
|
||||||
|
$controller->register_hook(
|
||||||
|
"DOKUWIKI_STARTED",
|
||||||
|
"AFTER",
|
||||||
|
$this,
|
||||||
|
"provideJsInfo",
|
||||||
|
);
|
||||||
$controller->register_hook(
|
$controller->register_hook(
|
||||||
"RENDERER_CONTENT_POSTPROCESS",
|
"RENDERER_CONTENT_POSTPROCESS",
|
||||||
"BEFORE",
|
"BEFORE",
|
||||||
@@ -122,6 +128,7 @@ class action_plugin_luxtools extends ActionPlugin
|
|||||||
"linkfavicon.js",
|
"linkfavicon.js",
|
||||||
"calendar-widget.js",
|
"calendar-widget.js",
|
||||||
"event-popup.js",
|
"event-popup.js",
|
||||||
|
"movie-import.js",
|
||||||
"main.js",
|
"main.js",
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -133,6 +140,23 @@ class action_plugin_luxtools extends ActionPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass plugin data to client-side JavaScript via JSINFO.
|
||||||
|
*
|
||||||
|
* Must run before TPL_METAHEADER_OUTPUT because JSINFO is serialized
|
||||||
|
* during tpl_metaheaders() before that event fires.
|
||||||
|
*
|
||||||
|
* @param Event $event
|
||||||
|
* @param mixed $param
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function provideJsInfo(Event $event, $param)
|
||||||
|
{
|
||||||
|
// Intentional: the key is exposed to the browser for direct OMDb lookups.
|
||||||
|
global $JSINFO;
|
||||||
|
$JSINFO['luxtools_omdb_apikey'] = (string)$this->getConf('omdb_apikey');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serve server-rendered calendar widget HTML for month navigation.
|
* Serve server-rendered calendar widget HTML for month navigation.
|
||||||
*
|
*
|
||||||
@@ -909,6 +933,14 @@ class action_plugin_luxtools extends ActionPlugin
|
|||||||
"icon" => "../../plugins/luxtools/images/date-fix-all.svg",
|
"icon" => "../../plugins/luxtools/images/date-fix-all.svg",
|
||||||
"block" => false,
|
"block" => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Movie Import: fetch movie metadata from OMDb
|
||||||
|
$event->data[] = [
|
||||||
|
"type" => "LuxtoolsMovieImport",
|
||||||
|
"title" => $this->getLang("toolbar_movie_title"),
|
||||||
|
"icon" => "../../plugins/luxtools/images/movie.svg",
|
||||||
|
"block" => false,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
|||||||
'calendar_slot4_color',
|
'calendar_slot4_color',
|
||||||
'calendar_slot4_display',
|
'calendar_slot4_display',
|
||||||
'pagelink_search_depth',
|
'pagelink_search_depth',
|
||||||
|
'omdb_apikey',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getMenuText($language)
|
public function getMenuText($language)
|
||||||
@@ -130,6 +131,8 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
|||||||
if ($depth < 0) $depth = 0;
|
if ($depth < 0) $depth = 0;
|
||||||
$newConf['pagelink_search_depth'] = $depth;
|
$newConf['pagelink_search_depth'] = $depth;
|
||||||
|
|
||||||
|
$newConf['omdb_apikey'] = trim($INPUT->str('omdb_apikey'));
|
||||||
|
|
||||||
if ($this->savePluginLocalConf($newConf)) {
|
if ($this->savePluginLocalConf($newConf)) {
|
||||||
msg($this->getLang('saved'), 1);
|
msg($this->getLang('saved'), 1);
|
||||||
} else {
|
} else {
|
||||||
@@ -360,6 +363,13 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
|||||||
echo '<input type="number" class="edit" min="0" name="pagelink_search_depth" value="' . hsc((string)$this->getConf('pagelink_search_depth')) . '" />';
|
echo '<input type="number" class="edit" min="0" name="pagelink_search_depth" value="' . hsc((string)$this->getConf('pagelink_search_depth')) . '" />';
|
||||||
echo '</label><br />';
|
echo '</label><br />';
|
||||||
|
|
||||||
|
// OMDb API key
|
||||||
|
echo '<h2>' . hsc($this->getLang('omdb_heading')) . '</h2>';
|
||||||
|
echo '<label class="block"><span>' . hsc($this->getLang('omdb_apikey')) . '</span> ';
|
||||||
|
echo '<input type="text" class="edit" name="omdb_apikey" value="' . hsc((string)$this->getConf('omdb_apikey')) . '" />';
|
||||||
|
echo '</label><br />';
|
||||||
|
echo '<p><em>' . hsc($this->getLang('omdb_apikey_note')) . '</em></p>';
|
||||||
|
|
||||||
echo '<button type="submit" class="button">' . hsc($this->getLang('btn_save')) . '</button>';
|
echo '<button type="submit" class="button">' . hsc($this->getLang('btn_save')) . '</button>';
|
||||||
|
|
||||||
echo '</fieldset>';
|
echo '</fieldset>';
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ $conf['calendar_slot4_display'] = 'none';
|
|||||||
// Maximum depth when searching for .pagelink files under allowed roots.
|
// Maximum depth when searching for .pagelink files under allowed roots.
|
||||||
$conf['pagelink_search_depth'] = 3;
|
$conf['pagelink_search_depth'] = 3;
|
||||||
|
|
||||||
|
// OMDb API key for movie metadata import (used client-side).
|
||||||
|
$conf['omdb_apikey'] = '';
|
||||||
|
|
||||||
// Image syntax defaults
|
// Image syntax defaults
|
||||||
$conf['default_image_width'] = 250;
|
$conf['default_image_width'] = 250;
|
||||||
$conf['default_image_align'] = 'right'; // left|right|center
|
$conf['default_image_align'] = 'right'; // left|right|center
|
||||||
|
|||||||
9
images/movie.svg
Normal file
9
images/movie.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<rect x="2" y="2" width="20" height="20" rx="2" ry="2"/>
|
||||||
|
<line x1="2" y1="8" x2="22" y2="8"/>
|
||||||
|
<line x1="6" y1="2" x2="6" y2="8"/>
|
||||||
|
<line x1="10" y1="2" x2="10" y2="8"/>
|
||||||
|
<line x1="14" y1="2" x2="14" y2="8"/>
|
||||||
|
<line x1="18" y1="2" x2="18" y2="8"/>
|
||||||
|
<polygon points="10,12 10,19 16,15.5" fill="currentColor" stroke="none"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 521 B |
206
js/movie-import.js
Normal file
206
js/movie-import.js
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
/* 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 = '<!-- BEGIN MOVIE -->';
|
||||||
|
var MARKER_END = '<!-- END MOVIE -->';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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('^ Runtime | ' + safe(movie.Runtime) + ' |');
|
||||||
|
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<Type> for custom button types.
|
||||||
|
window.addBtnActionLuxtoolsMovieImport = function ($btn, props, edid) {
|
||||||
|
$btn.on('click', function () {
|
||||||
|
importMovie(edid);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return 'luxtools-movie-import';
|
||||||
|
};
|
||||||
|
})();
|
||||||
@@ -122,3 +122,12 @@ $lang["cache_purge_cancel"] = "Abbrechen";
|
|||||||
$lang["cache_purge_confirm"] = "Cache leeren";
|
$lang["cache_purge_confirm"] = "Cache leeren";
|
||||||
$lang["cache_purge_pagelinks_success"] = "Seitenlink-Cache geleert.";
|
$lang["cache_purge_pagelinks_success"] = "Seitenlink-Cache geleert.";
|
||||||
$lang["cache_purge_thumbs_success"] = "Vorschaubild-Cache geleert.";
|
$lang["cache_purge_thumbs_success"] = "Vorschaubild-Cache geleert.";
|
||||||
|
|
||||||
|
$lang["toolbar_movie_title"] = "Film-Import";
|
||||||
|
$lang["movie_prompt"] = "Filmtitel eingeben (optional mit Jahr):";
|
||||||
|
$lang["movie_error_no_apikey"] = "OMDb-API-Schlüssel nicht konfiguriert. Unter Admin → luxtools einstellen.";
|
||||||
|
$lang["movie_error_not_found"] = "Film nicht gefunden.";
|
||||||
|
$lang["movie_error_fetch"] = "OMDb-Abfrage fehlgeschlagen.";
|
||||||
|
$lang["omdb_heading"] = "Film-Import (OMDb)";
|
||||||
|
$lang["omdb_apikey"] = "OMDb-API-Schlüssel";
|
||||||
|
$lang["omdb_apikey_note"] = "Der API-Schlüssel wird an den Browser übergeben für clientseitige OMDb-Abfragen. Er ist in den Browser-Entwicklertools und Netzwerkanfragen sichtbar.";
|
||||||
|
|||||||
@@ -28,3 +28,5 @@ $lang["gallery_thumb_scale"] = "Skalierungsfaktor fuer Galerie-Thumbnails. 2 erz
|
|||||||
$lang["open_service_url"] = "URL des lokalen Client-Dienstes fuer {{open>...}} (z.B. http://127.0.0.1:8765).";
|
$lang["open_service_url"] = "URL des lokalen Client-Dienstes fuer {{open>...}} (z.B. http://127.0.0.1:8765).";
|
||||||
|
|
||||||
$lang["pagelink_search_depth"] = "Maximale Verzeichnisebene fuer .pagelink-Suche (0 = nur Root).";
|
$lang["pagelink_search_depth"] = "Maximale Verzeichnisebene fuer .pagelink-Suche (0 = nur Root).";
|
||||||
|
|
||||||
|
$lang["omdb_apikey"] = "OMDb-API-Schlüssel für den Film-Import. Wird clientseitig im Browser verwendet.";
|
||||||
|
|||||||
@@ -123,3 +123,12 @@ $lang["cache_purge_cancel"] = "Cancel";
|
|||||||
$lang["cache_purge_confirm"] = "Purge Cache";
|
$lang["cache_purge_confirm"] = "Purge Cache";
|
||||||
$lang["cache_purge_pagelinks_success"] = "Pagelinks cache purged.";
|
$lang["cache_purge_pagelinks_success"] = "Pagelinks cache purged.";
|
||||||
$lang["cache_purge_thumbs_success"] = "Thumbnail cache purged.";
|
$lang["cache_purge_thumbs_success"] = "Thumbnail cache purged.";
|
||||||
|
|
||||||
|
$lang["toolbar_movie_title"] = "Movie Import";
|
||||||
|
$lang["movie_prompt"] = "Enter movie title (optionally with year):";
|
||||||
|
$lang["movie_error_no_apikey"] = "OMDb API key is not configured. Set it in Admin → luxtools.";
|
||||||
|
$lang["movie_error_not_found"] = "Movie not found.";
|
||||||
|
$lang["movie_error_fetch"] = "OMDb lookup failed.";
|
||||||
|
$lang["omdb_heading"] = "Movie Import (OMDb)";
|
||||||
|
$lang["omdb_apikey"] = "OMDb API key";
|
||||||
|
$lang["omdb_apikey_note"] = "The API key is passed to the browser for client-side OMDb lookups. It will be visible in browser developer tools and network requests.";
|
||||||
|
|||||||
@@ -28,3 +28,5 @@ $lang['gallery_thumb_scale'] = 'Gallery thumbnail scale factor. Use 2 for sharpe
|
|||||||
$lang['open_service_url'] = 'Local client service URL for the {{open>...}} link (e.g. http://127.0.0.1:8765).';
|
$lang['open_service_url'] = 'Local client service URL for the {{open>...}} link (e.g. http://127.0.0.1:8765).';
|
||||||
|
|
||||||
$lang['pagelink_search_depth'] = 'Maximum directory depth for .pagelink search (0 = only root).';
|
$lang['pagelink_search_depth'] = 'Maximum directory depth for .pagelink search (0 = only root).';
|
||||||
|
|
||||||
|
$lang['omdb_apikey'] = 'OMDb API key for movie metadata import. Used client-side in the browser.';
|
||||||
|
|||||||
60
syntax/moviemarker.php
Normal file
60
syntax/moviemarker.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use dokuwiki\Extension\SyntaxPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* luxtools Plugin: Movie marker syntax.
|
||||||
|
*
|
||||||
|
* Matches the <!-- BEGIN MOVIE --> and <!-- END MOVIE --> markers inserted
|
||||||
|
* by the movie-import toolbar button and renders them as invisible output.
|
||||||
|
* The markers remain in the page source for reliable find-and-replace on
|
||||||
|
* repeated imports.
|
||||||
|
*/
|
||||||
|
class syntax_plugin_luxtools_moviemarker extends SyntaxPlugin
|
||||||
|
{
|
||||||
|
/** @inheritdoc */
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return 'substition';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
public function getPType()
|
||||||
|
{
|
||||||
|
return 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
public function getSort()
|
||||||
|
{
|
||||||
|
return 319;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
public function connectTo($mode)
|
||||||
|
{
|
||||||
|
$this->Lexer->addSpecialPattern(
|
||||||
|
'<!-- BEGIN MOVIE -->',
|
||||||
|
$mode,
|
||||||
|
'plugin_luxtools_moviemarker'
|
||||||
|
);
|
||||||
|
$this->Lexer->addSpecialPattern(
|
||||||
|
'<!-- END MOVIE -->',
|
||||||
|
$mode,
|
||||||
|
'plugin_luxtools_moviemarker'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
public function handle($match, $state, $pos, Doku_Handler $handler)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
public function render($format, Doku_Renderer $renderer, $data)
|
||||||
|
{
|
||||||
|
// Render nothing — markers are source-level only.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user