Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for wiki links in SVG diagrams #61

Open
lprobsth opened this issue Nov 27, 2023 · 5 comments
Open

Add support for wiki links in SVG diagrams #61

lprobsth opened this issue Nov 27, 2023 · 5 comments

Comments

@lprobsth
Copy link

lprobsth commented Nov 27, 2023

Introduction

The drawio plugin for dokuwiki greatly enhances the experience for users by increasing the speed in which documentations can be created without leaving the wiki. I instructed our users to crate SVG diagrams by default. I'm also using #53, which shows an edit button and enables the proper use of links inside the diagrams.

I think the last showstopper for creating the perfect diagrams inside dokuwiki is the feature to implement wiki links [[namespace:page|Link Name]] inside the diagrams. Right now links to wiki pages have to be set with the complete URL wiki.my-domain.com/namespace/page#section. But using static URLs quickly leads to broken links if pages are moved.

Technical prerequisites

If SVGs are enabled for drawio in dokuwiki, drawio saves the diagram with embedded drawio diagram data (https://www.drawio.com/doc/faq/save-file-formats). The data of links inside the diagram elements is represented with the following string href=&quot;[[namespace:page|Text]]&quot;. This can be read and altered from php. The SVG elements are represented as normal HTML links <a href="[[namespace:page|Text]]">Original link text</a>

Concept

As it is hard to constantly modify the original drawio file for rendering the links, it might be a good idea to move the rendering of these links to JavaScript. But links could be broken if pages are moved. Also plugins like "OrphansWanted" (https://www.dokuwiki.org/plugin:orphanswanted) should be able to index the links.

  • register the meta data for the page relation on saving (https://www.dokuwiki.org/devel:metadata)
    this way the OrphansWanted plugin (and other plugins) know about our diagram including a link to another page
  • implement JavaScript function for rendering the links inside the browser (should alter the HTML elements for links inside diagrams)
  • register hook for page moves (https://www.dokuwiki.org/plugin:move#support_for_other_plugins)
    • on page move both elements for the drawio XML and the SVG links should be updated
    • update the meta data for the page including the SVG

Possible problems

  • the format of the diagram could be broken after links are rendered (link does not have the same length as the original text)
    -> maybe use the link text from the original object in drawio and do not use the link text from the wiki link
  • the page relations in the meta data could be broken after the diagram itself is moved
    -> might need more complex move handling
  • it might be a good idea to implement the rendering of the wiki links in svgembed

Edit 27.11.2023

Another requirement that was not mentioned clearly in the original text is that we probably should use the svgembed plugin for this feature (an implementation can be seen in https://github.com/gkrid/dokuwiki-plugin-drawio/tree/feature-svgembed-integration - I also use this feature with some slight modifications in my setup). This would make it easier to implement the JavaScript rendering of links. But there also occurs a problem: we only render the svgembed syntax. I think this would break some event handlers that are needed for move events and all meta data registration that happens in svgembed that need to be implemented for the compatibility with the plugins move and orphanswanted.

@lprobsth
Copy link
Author

lprobsth commented Nov 27, 2023

Prototype for the JavaScript rendering of the links in svgembed (disclaimer: created with the help of ChatGPT):

jQuery(function(){
    function updateSVGLinksInSVG(svgElement) {
        // Find all <a> elements within each SVG
        jQuery(svgElement).find('a').each(function() {
            var $link = jQuery(this);
            var href = $link.attr('href');

            // Check if the href matches the pattern
            if (href && href.startsWith('[[') && href.endsWith(']]')) {
                // Extract namespace, page, and section
                var parts = href.slice(2, -2).split(':');
                var namespace = parts[0];
                var pageSection = parts[1].split('#');
                var page = pageSection[0];
                var section = pageSection[1];

                // Construct the new URL (modify this according to your URL structure)
                var newHref = DOKU_BASE + namespace + '/' + page + (section ? '#' + section : '');

                // Update the href attribute
                $link.attr('href', newHref);
            }
        });
    }


    // Function to handle an object element
    function handleObject($obj) {
        var svgDoc = $obj[0].contentDocument; // Get the document of the object tag
        if (svgDoc) {
            var svg = svgDoc.querySelector('svg');
            if (svg) {
                updateSVGLinksInSVG(svg);
            }
        }
    }

    // Find all object tags that are supposed to contain SVGs
    jQuery('object[type="image/svg+xml"]').each(function() {
        var $this = jQuery(this);

            $this.on('load', function() {
                handleObject($this);
            });
    });
});

Possible problems

  • does not check if link exists
  • URL may not work if wiki is not configured for nice URL rewriting
  • protection against cross site scripting (are SVGs secure at all?)

Possible enhancement

Edit: 29.11.2023

One thing to consider with the links inside a SVGs is that all links should be rendered relative to the namespace of the SVG itself. Otherwise the links would lead to different pages if the the SVG is included in multiple pages. Also, if the links are not rendered relative to the namespace of the SVG, page moves could lead to broken links. How should the link be changed on a page move if the SVG is used on two different pages? The only thing we can certainly know on a page move is the namespace of the SVG itself.

Edit: 30.11.2023

If the SVG is viewed without a wiki page (in a new tab when opened from a link / from the media manager) the script is not loaded and the links are not rendered. Another possibility is to modify the SVG when the 'MEDIA_SENDFILE' event triggers. This is also beneficial for rendering the link state (existence of the linked page/media file). But I'll first have to look into caching for modified media files because otherwise the parsing of the SVG would happen on each request.

Another edit for the edit: The svgimg2 plugin does a conversion for SVG files and then stores the output in a custom cache file: https://codesearch.dokuwiki.org/xref/plugin/svgimg2/action.php#49
This could be done similarly for rendered links in SVGs. If we then replace the file path in the event of 'MEDIA_SENDFILE', our rendering could also be chained with a plugin like svgimg2, so it also receives our rendered version before sending.

@lprobsth
Copy link
Author

lprobsth commented Nov 28, 2023

About moving pages with the "move" plugin

An example for how pages are moved can be found in the rename function of the move plugin:
https://github.com/michitux/dokuwiki-plugin-move/blob/8ba3be2eda0ebb92d8e61ec873172357acab2952/action/rename.php#L107

Here affected PAGES are searched through the meta key "relation_references" (these are pages that reference our currently moved page):
https://github.com/michitux/dokuwiki-plugin-move/blob/8ba3be2eda0ebb92d8e61ec873172357acab2952/helper/op.php#L138

It then saves information for the move in the meta data entry "plugin_move" for each of the affected pages:
https://github.com/michitux/dokuwiki-plugin-move/blob/8ba3be2eda0ebb92d8e61ec873172357acab2952/helper/op.php#L214

After the meta data has been saved and the page is renamed it then redirects to the new location of the page.

On the next "IO_WIKIPAGE_READ" event the plugin tries to modify the page content:
https://github.com/michitux/dokuwiki-plugin-move/blob/8ba3be2eda0ebb92d8e61ec873172357acab2952/action/rewrite.php#L73

Then it initializes a new parser with the handlers that have been registered by the move compatible plugins:
https://github.com/michitux/dokuwiki-plugin-move/blob/8ba3be2eda0ebb92d8e61ec873172357acab2952/helper/rewrite.php#L247

This means that for each syntax plugin the lexer entry is matched against the content of the page and if it matches, the registered plugin handler for the modification of the match according to the move is called.

What this means for SVGs

Normally the "relation_references" meta data is only created for pages. As far as I understand, meta data can also be saved for media files. So if a meta data entry "relation_references" for a media file exists, it should be found by the indexer (https://www.dokuwiki.org/devel:metadata#metadata_index) (EDIT: the indexer only finds pages by default - we have to manually add the meta data). As the "move" plugin only looks up the IDs for "relation_references" entries in the indexer, it should also detect media files as affected pages and save the "plugin_move" meta data for these.
Currently with the plugin handler registration in the "move" plugin it will not be possible to modify the media files, since the call to the handler is done through the dokuwiki parser with the lexer entries for the syntax of the individual plugin. As the parser/lexer does not match against media files, there is no way of implementing a notification to the plugins handler that way.
Hence we need another notification mechanism in the move plugin for media files, that let's plugins modify the media file if a move affects it.

Pitfalls (=how many plugins are affected)

  • "move" plugin: should also monitor media files and notify plugins with an event similar to "PLUGIN_MOVE_HANDLERS_REGISTER" for giving us the chance to do modifications when "plugin_move" meta data is available for the file (media files could be monitored with the MEDIA_SENDFILE https://www.dokuwiki.org/devel:event:media_sendfile event - for the tree based move the notification has to be implemented also)
  • "svgembed" plugin: should implement a handler for modifying the wiki links inside the SVG if the "move" plugin detects an affecting move
  • "svgembed" plugin: should set the "relation_references" and "relation_media" meta data for included SVGs ("relation_media" is needed if we add links to images in the diagrams)
  • "drawio" plugin: should implement a handler for modifying the wiki link inside the draw.io source of the diagram
  • "drawio" plugin: should set the "relation_references" and "relation_media" meta data for saved draw.io files with the SVG format

Edit: 29.11.2023

It seems like the indexer of dokuwiki (which the move plugin uses to find all affected pages with the "relation_references" meta entry) does not index the meta data of media files.
Therefore it is necessary to add the media files meta data manually to the index when the media file is saved:

$target = 'my_diagram.svg';

$page = 'my_page';

idx_get_indexer()->addMetaKeys($target, 'relation_references', $page);

$result = idx_get_indexer()->lookupKey('relation_references', $page);
// outputs a list with all IDs that point to our 'my_page' page - including our diagram!

lprobsth added a commit to lprobsth/dokuwiki-plugin-svgEmbed that referenced this issue Nov 29, 2023
@lprobsth
Copy link
Author

Technical difficulties with the orphanswanted plugin

The orphanswanted plugin correctly receives the pages (including our SVG media files that have been added to the index with the code shown in my last comment):
https://github.com/lupo49/dokuwiki-plugin-orphanswanted/blob/54262becefb1608379094928a7776d8db4e215d3/helper.php#L31

But then it checks if the page exists before receiving the "relation_references" meta data for the SVG. Since the SVG ist not a page, the check fails and the references are never added to the index:
https://github.com/lupo49/dokuwiki-plugin-orphanswanted/blob/54262becefb1608379094928a7776d8db4e215d3/helper.php#L39

If I remove this check from the orphanswanted plugin, the links from the SVGs are correctly shown in the overviews created with the plugin. But when clicking on the backlinks of a page, the backlink page of dokuwik (builtin functionality) does not show the SVG that linked the page. This is due to another "page_exists":
https://github.com/dokuwiki/dokuwiki/blob/133e2f6d07a7b695a4b6bde21f477409f3c32e48/inc/fulltext.php#L191

Possible workaround

In all cases an additional check for "media_exists" could be added where "page_exists" is run for IDs returned from the indexer for "relation_references" meta data. This would allow for media files to also reference pages.
The backlink UI page of dokuwiki would also have to be changed to correctly render the links to media files if a ID that corresponds to a media file is returned from the indexer. Checking if a ID corresponds to a media file could lead to mismatched IDs if the extension is omitted. But the way I implemented the meta data for the indexer, media files with references should always be saved with the extension in place ("namespace:imagename.svg"). If the indexer is not messed up by other plugins it should always return references from media files with the extension.

@lprobsth
Copy link
Author

lprobsth commented Nov 30, 2023

Current progress: rendering of wiki links

I now implemented the rendering of wiki links to pages and media files inside SVGs in svgembed with PHP. I use a caching object that stores the modified SVG and check if the original SVG has a newer timestamp for expiring the cache. So far this works. The code is not ready yet because I have to do more testing.

One thing I noticed is that the current mechanism of loading SVGs that have been edited with drawio are directly loaded from the editor to the current view of the page. This way the rendering of wiki links does not happen. Also the page format is broken if the old page used svgembed to display the SVG.

Edit 01.12.2023

In the JavaScript code of the drawio plugin I now added a test to detect whether the SVG is rendered with the svgembed plugin and then load the SVG via the media fetch executor of dokuwiki on save. This ensures that the SVG goes through the renderer that I implemented in svgembed.

I'm now working on setting the styles of the links for existing/non-existing wiki pages (style classes "wikilink1" and "wikilink2"). But since the svgembed plugin loads the SVG inside an object-element (which is considered good practice), the style classes are not available in the SVG element. I currently see two possibilities for fixing this:

  1. Copying the style definitions of the CSS classes "wikilink1" and "wikilink2" from the root document to the object element in JavaScript (this ensures that if the global style changes because of template designs the style of wiki links inside the svg will stay the same)
  2. defining custom link styles that are injected into the SVG (but this way the style may differ from the template design)

lprobsth added a commit to lprobsth/dokuwiki-plugin-svgEmbed that referenced this issue Dec 9, 2023
…luded in a SVGs and the rendering of wiki links through cache files.

The references of wiki links are stored both in the meta file of the SVG and the indexer.
This is a preparation step for implement the rewrite of wiki links inside the SVG when pages are moved with the move plugin.

Also a render function is implemented that renders wiki links inside the SVG and stores the rendered SVG in the cache.

This is a preliminary version - the meta data is updated on each fetch of the status of the SVG (very inefficent).

This commit is part of lejmr/dokuwiki-plugin-drawio#61
@lprobsth
Copy link
Author

lprobsth commented Dec 9, 2023

The current versions of the plugins can be found in:

What does work

  • wiki links inside SVGs are rendered with svgembed
  • rendered versions of SVGs are saved in the cache
  • svgembed saves meta data for the references (on each status request for the media file - needs to be fixed somehow. maybe with validation: was SVG changed since last time?)
  • move plugin shows that links need to be adapted in the SVG

What does NOT work

  • rewriting wiki links on page move
    • changes are needed in the move plugin
  • showing references from SVG in overviews of orphanswanted
    • orphanswanted checks if page form refrence meta exists - our SVG is not a page
  • showing backlinks from SVGs (needs changes in the dokuwiki core code)
    • currently the backlinks page checks if a page that references the wanted page exists - since our SVG is not a page, it does not show the SVG as a backlink

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant