diff --git a/docs/06.5-Interwiki-Links.md b/docs/06.5-Interwiki-Links.md new file mode 100644 index 0000000..9271d16 --- /dev/null +++ b/docs/06.5-Interwiki-Links.md @@ -0,0 +1,26 @@ +# Inter-wiki Links +Pepperminty Wiki, as of v0.18, supports _inter-wiki links_. Such a link sends the user to another wiki elsewhere on the internet. This is configured via the `interwiki_index_location` setting, which should point to a CSV file (either as a file path or an absolute URL) that specifies the wikis that can be linked to. Here are some example inter-wiki links: + +```markdown + - [[another_wiki:Apples]] + - [[trees:Apple Trees]] + - In the [[history:The Great Rainforest|rainforest]], lots of trees can be found. + - .... Text text text [[any prefix here:page name|Display text]] text text text .... +``` + +Note that the automatic page name correction doesn't work with inter-wiki links, so you'll need to get the casing exactly right (try using the vertical-bar `|` display text feature if you want to the display text to use a different casing to the actual page name. + +The CSV file format is best explained with an example: + +```csv +Name,Prefix,Root URL +Another Wiki,another_wiki,https://wiki.example.com/?page=%s +Tree Field Guide,trees,https://trees.bobsrockets.io/wiki/%s +History Wiki,history,https://history.sanssatellites.co.uk/#%s +Wiki Display Name,internal link prefix,url with %s in place of page name +Apt Link,apt,apt://%s +``` + +The top line is a header and is discarded by _Pepperminty Wiki_ (so you can put anything you like here). + +The url can be any URI supported by the user's browser. The string `%s` will be replaced with the (url encoded) page name. To this end, you can use this feature for _any_ external service you like - it doesn't have to be a Pepperminty Wiki installation (or even a wiki at all)! diff --git a/modules/feature-interwiki-links.php b/modules/feature-interwiki-links.php index 0db8e71..b93da8e 100644 --- a/modules/feature-interwiki-links.php +++ b/modules/feature-interwiki-links.php @@ -96,7 +96,7 @@ function interwiki_get_pagename_url($interwiki_pagename) { [$prefix, $pagename] = interwiki_pagename_parse($interwiki_pagename); return str_replace( - "{{page_name}}", rawurlencode($pagename), + "%s", rawurlencode($pagename), $interwiki_def->root_url ); } diff --git a/modules/parser-parsedown.php b/modules/parser-parsedown.php index 647377b..2ecf178 100644 --- a/modules/parser-parsedown.php +++ b/modules/parser-parsedown.php @@ -446,67 +446,95 @@ class PeppermintParsedown extends ParsedownExtra { global $pageindex, $env; - if(preg_match('/^\[\[([^\]]*)\]\]([^\s!?",;.()\[\]{}*=+\/]*)/u', $fragment["text"], $matches)) - { - $linkPage = trim($matches[1]); - $display = $linkPage . trim($matches[2]); + if(preg_match('/^\[\[([^\]]*)\]\]([^\s!?",;.()\[\]{}*=+\/]*)/u', $fragment["text"], $matches)) { + // 1: Parse parameters out + // ------------------------------- + $link_page = trim($matches[1]); + $display = $link_page . trim($matches[2]); if(strpos($matches[1], "|") !== false || strpos($matches[1], "¦") !== false) { // We have a bar character $parts = preg_split("/\\||¦/", $matches[1], 2); - $linkPage = trim($parts[0]); // The page to link to + $link_page = trim($parts[0]); // The page to link to $display = trim($parts[1]); // The text to display } - $hashCode = ""; - if(strpos($linkPage, "#") !== false) + + // 2: Parse the hash out + // ------------------------------- + $hash_code = ""; + if(strpos($link_page, "#") !== false) { // We want to link to a subsection of a page - $hashCode = substr($linkPage, strpos($linkPage, "#") + 1); - $linkPage = substr($linkPage, 0, strpos($linkPage, "#")); + $hash_code = substr($link_page, strpos($link_page, "#") + 1); + $link_page = substr($link_page, 0, strpos($link_page, "#")); - // If $linkPage is empty then we want to link to the current page - if(strlen($linkPage) === 0) - $linkPage = $env->page; - } - - // If the page doesn't exist, check varying different - // capitalisations to see if it exists under some variant. - if(empty($pageindex->$linkPage)) - { - if(!empty($pageindex->{ucfirst($linkPage)})) - $linkPage = ucfirst($linkPage); - else if(!empty($pageindex->{ucwords($linkPage)})) - $linkPage = ucwords($linkPage); + // If $link_page is empty then we want to link to the current page + if(strlen($link_page) === 0) + $link_page = $env->page; } - // Construct the full url - $linkUrl = str_replace( - "%s", rawurlencode($linkPage), - $this->internalLinkBase - ); - if(strlen($hashCode) > 0) - $linkUrl .= "#$hashCode"; + // 3: Page name auto-correction + // ------------------------------- + $is_interwiki_link = module_exists("feature-interwiki-links") && is_interwiki_link($link_page); + if(!is_interwiki_link && empty($pageindex->$link_page)) { + // If the page doesn't exist, check varying different + // capitalisations to see if it exists under some variant. + if(!empty($pageindex->{ucfirst($link_page)})) + $link_page = ucfirst($link_page); + else if(!empty($pageindex->{ucwords($link_page)})) + $link_page = ucwords($link_page); + } + + // 4: Construct the full url + // ------------------------------- + $link_url = null; + // If it's an interwiki link, then handle it as such + if($is_interwiki_link) + $link_url = interwiki_get_pagename_url($link_page); + + // If it isn't (or it failed), then try it as a normal link instead + if(empty($link_url)) { + $link_url = str_replace( + "%s", rawurlencode($link_page), + $this->internalLinkBase + ); + // We failed to handle it as an interwiki link, so we should + // tell everyone that + $is_interwiki_link = false; + } + + if(strlen($hash_code) > 0) + $link_url .= "#$hash_code"; + + // 6: Result encoding + // ------------------------------- $result = [ "extent" => strlen($matches[0]), "element" => [ "name" => "a", "text" => $display, "attributes" => [ - "href" => $linkUrl + "href" => $link_url ] ] ]; - if(empty($pageindex->{makepathsafe($linkPage)})) - $result["element"]["attributes"]["class"] = "redlink"; + // Attach some useful classes based on how we handled it + $class_list = []; + // Interwiki links can never be redlinks + if(!$is_interwiki_link && empty($pageindex->{makepathsafe($link_page)})) + $class_list[] = "redlink"; + if($is_interwiki_link) + $class_list[] = "interwiki_link"; + + $result["element"]["attributes"]["class"] = implode(" ", $class_list); return $result; } - return; } /* diff --git a/peppermint.guiconfig.json b/peppermint.guiconfig.json index b92c0f9..18581a5 100644 --- a/peppermint.guiconfig.json +++ b/peppermint.guiconfig.json @@ -15,10 +15,10 @@ "admindisplaychar": { "type": "text", "description": "The string that is prepended before an admin's name on the nav bar. Defaults to a diamond shape (◆).", "default": "◆" }, "protectedpagechar": { "type": "text", "description": "The string that is prepended a page's name in the page title if it is protected. Defaults to a lock symbol. (🔒)", "default": "🔒" }, "editing": { "type": "checkbox", "description": "Whether editing is enabled.", "default": true}, - "anonedits": { "type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false}, - "maxpagesize": { "type": "number", "description": "The maximum page size in characters.", "default": 135000}, + "anonedits": { "type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false }, + "maxpagesize": { "type": "number", "description": "The maximum page size in characters.", "default": 135000 }, "parser": { "type": "text", "description": "The parser to use when rendering pages. Defaults to an extended version of parsedown (http://parsedown.org/)", "default": "parsedown" }, - "interwiki_index_location": { "type": "url", "description": "The location to find the interwiki wiki definition file, which contains a list of wikis along with their names, prefixes, and root urls. May be a URL, or simply a file path - as it's passed to file_get_contents()." }, + "interwiki_index_location": { "type": "url", "description": "The location to find the interwiki wiki definition file, which contains a list of wikis along with their names, prefixes, and root urls. May be a URL, or simply a file path - as it's passed to file_get_contents().", "default": null }, "clean_raw_html": { "type": "checkbox", "description": "Whether page sources should be cleaned of HTML before rendering. It is STRONGLY recommended that you keep this option turned on.", "default": true}, "enable_math_rendering": { "type": "checkbox", "description": "Whether to enable client side rendering of mathematical expressions with MathJax (https://www.mathjax.org/). Math expressions should be enclosed inside of dollar signs ($). Turn off if you don't use it.", "default": true}, "users": { "type": "usertable", "description": "An array of usernames and passwords - passwords should be hashed with password_hash() (the hash action can help here)", "default": {