Änderungen von Dokument DiagramViewSheet
Zuletzt geändert von Daniel Herrmann am 2026/02/04 20:25
Von Version
2.1
bearbeitet von Daniel Herrmann
am 2026/02/04 20:25
am 2026/02/04 20:25
Änderungskommentar:
Install extension [com.xwiki.diagram:application-diagram/1.22.11]
Auf Version 1.1
bearbeitet von Mike Schneider
am 2025/12/30 10:37
am 2025/12/30 10:37
Änderungskommentar:
Install extension [org.xwiki.contrib:application-diagram/1.3]
Zusammenfassung
Details
- Seiteneigenschaften
-
- Dokument-Autor
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki. dherrman1 +XWiki.mschneide - Inhalt
-
... ... @@ -1,41 +3,23 @@ 1 -{{include reference="Diagram.CommonCode"/}} 2 - 3 3 {{velocity}} 4 -#set ($diagramObj = $doc.getObject('Diagram.DiagramClass')) 5 -#if ($diagramObj || "$!request.source" != '') 6 - #set ($discard = $xwiki.ssx.use('Diagram.DiagramSheet')) 7 - #set ($discard = $xwiki.jsx.use('Diagram.DiagramViewSheet')) 8 - #set ($toolbar = 'zoom layers pages lightbox') 9 - #if ("$!request.source" == '' && $services.security.authorization.hasAccess('edit')) 10 - #set ($toolbar = "edit $toolbar") 11 - #end 12 - {{html clean="false"}} 13 - ## Check if the query contains the parameter for getting the diagram from URL. 14 - #set ($displayDiv = "") 15 - #set ($fileName = 'diagram.svg') 16 - #if ($xcontext.action == 'export') 17 - #set ($displayDiv = 'hidden') 18 - #showDiagramSVGInHTML($doc, $fileName) 19 - #end 20 - <div class="diagram $displayDiv" 21 - data-diagram-config="$escapetool.xml($jsontool.serialize($diagramConfig))" 22 - data-toolbar="$escapetool.xml($toolbar)" 23 - #if ("$!request.source" == '') 24 - data-model="$escapetool.xml($tdoc.content)" 25 - data-reference="$escapetool.xml($services.model.serialize($tdoc.documentReference, 'default'))" 26 - data-title="$escapetool.xml($tdoc.plainTitle)" 2 +#if ($doc.getObject('Diagram.DiagramClass')) 3 + #if ($xcontext.action == 'get' && $request.data == 'svg') 4 + #set ($svg = $doc.getValue('svg')) 5 + #if ("$!svg" == '') 6 + #set ($svg = '<svg/>') 27 27 #end 28 - > 29 - ## Show a preview of the diagram until the diagram viewer is loaded. This is also useful for export and WYSIWYG edit 30 - ## mode where the JavaScript code is not executed and thus the diagram viewer is never loaded. 31 - #set ($pngFileName = 'diagram.png') 32 - #if ($xcontext.action == 'export' && $diagramObj.getValue('exportUsingSVG') == 0 33 - && $doc.getAttachment($pngFileName)) 34 - #set ($fileName = $pngFileName) 35 - #end 36 - #set ($diagramURL = $doc.getAttachmentURL($fileName, 'download', "v=$!doc.version")) 37 - <img src="$diagramURL" alt="$escapetool.xml($doc.plainTitle)" /> 38 - </div> 39 - {{/html}} 8 + #set ($discard = $response.setContentType('image/svg+xml')) 9 + #set ($discard = $response.setContentLength($svg.length())) 10 + #set ($discard = $response.writer.write($svg)) 11 + #elseif ($xcontext.action == 'export') 12 + {{html clean="false"}} 13 + <img src="$doc.getURL('get', "data=svg&v=$!doc.version")" alt="$escapetool.xml($doc.plainTitle)" /> 14 + {{/html}} 15 + #else 16 + #set ($discard = $xwiki.ssx.use('Diagram.DiagramViewSheet')) 17 + #set ($discard = $xwiki.jsx.use('Diagram.DiagramViewSheet')) 18 + {{html clean="false"}} 19 + <div class="diagram loading" data-model="$escapetool.xml($tdoc.content)"></div> 20 + {{/html}} 21 + #end 40 40 #end 41 41 {{/velocity}}
- XWiki.JavaScriptExtension[1]
-
- Code
-
... ... @@ -1,21 +1,4 @@ 1 -define('xwiki-diagram-messages', { 2 - prefix: 'diagram.macro.', 3 - keys: [ 4 - 'loadFailed.externalDiagramUrl', 5 - 'loadFailed.externalDiagramUrl.guestUser', 6 - 'loadFailed' 7 - ] 8 -}); 9 - 10 -define('diagram-viewer', [ 11 - 'jquery', 12 - 'xwiki-l10n!xwiki-diagram-messages', 13 - 'diagram-utils', 14 - 'diagram-link-handler', 15 - 'xwiki-meta', 16 - 'diagram-graph-xml-filter', 17 - 'draw.io.viewer' 18 -], function($, l10n, diagramUtils, diagramLinkHandler, xm) { 1 +define('diagramViewer', ['jquery', 'draw.io.viewer'], function($) { 19 19 var getOrigin = function() { 20 20 var origin = window.location.origin; 21 21 if (!origin) { ... ... @@ -32,237 +32,27 @@ 32 32 // This is required for the clipart images. 33 33 GraphViewer.prototype.imageBaseUrl = getOrigin(); 34 34 35 - // Fix the diagram printing from the lightbox. mxPrintPreview#addGraphFragment optimizes the diagram rendering when 36 - // previewing the print by rendering only the shapes that intersect the clip associated with the print page. The 37 - // computations are wrong in view mode (either when computing the bounding rect of the shapes or the clip of the print 38 - // page) and it's not easy to spot the problem unfortunately. The consequence is that the print is empty. Disabling 39 - // the clipping fixes the issue apparently, but we loose the optimization which may cause problems for large diagrams. 40 - // Note that starting with version 3.9.9 of mxGraph the mxPrintPreview#addGraphFragment function doesn't skip the 41 - // shapes that don't interset the clip anymore because the return line has been commented out. 42 - // See https://github.com/jgraph/mxgraph/commit/d5c1345ec946b9d55a9c2a8c1c5df0f154561edf 43 - mxPrintPreview.prototype.clipping = false; 44 - 45 - // Overwrite in order to fix: Links with heterogeneous inner styles are not entirely clickable #107 46 - var graphLabelLinkClicked = Graph.prototype.labelLinkClicked; 47 - Graph.prototype.labelLinkClicked = function() { 48 - var newArguments = arguments; 49 - var link = arguments[1]; 50 - var href = link.getAttribute('href'); 51 - var originalLinkPolicy = this.linkPolicy; 52 - if (diagramLinkHandler.isXWikiCustomLink(href)) { 53 - newArguments = Array.prototype.slice.apply(arguments); 54 - newArguments[1] = $('<a/>').attr('href', diagramLinkHandler.getURLFromCustomLink(href))[0]; 55 - // Behave as if the link is clicked directly. 56 - this.linkPolicy = 'blank'; 57 - } 58 - try { 59 - graphLabelLinkClicked.apply(this, newArguments); 60 - } catch (e) { 61 - // Restore the link policy. 62 - this.linkPolicy = originalLinkPolicy; 63 - } 64 - }; 65 - // Overwrite in order to fix the same issue but when clicking the links from the light box. 66 - var graphAddClickHandler = Graph.prototype.addClickHandler; 67 - Graph.prototype.addClickHandler = function() { 68 - var originalBeforeClick = arguments[1]; 69 - var newArguments = Array.prototype.slice.apply(arguments); 70 - if (typeof originalBeforeClick === 'function') { 71 - var newBeforeClick = function(event, href) { 72 - if (href == null) { 73 - href = $(mxEvent.getSource(event)).closest('a').attr('href'); 74 - } 75 - originalBeforeClick.call(this, event, href); 76 - }; 77 - newArguments[1] = newBeforeClick; 78 - } 79 - graphAddClickHandler.apply(this, newArguments); 80 - }; 81 - 82 - var getDiagramViewerConfig = function(diagramContainer) { 83 - var config = { 84 - title: diagramContainer.data('title'), 85 - lightbox: false, 86 - toolbar: 'zoom layers pages lightbox', 87 - 'toolbar-buttons': { 88 - edit: { 89 - title: mxResources.get('edit'), 90 - image: Editor.editImage 91 - } 92 - } 93 - }; 94 - if (diagramContainer.data('reference')) { 95 - config.toolbar = 'edit ' + config.toolbar; 96 - var diagramReference = XWiki.Model.resolve(diagramContainer.data('reference'), XWiki.EntityType.DOCUMENT); 97 - config.reference = diagramReference; 98 - var diagramEditURL = new XWiki.Document(diagramReference).getURL('edit'); 99 - config['toolbar-buttons'].edit.handler = function() { 100 - window.location.href = diagramEditURL; 101 - }; 102 - } 103 - var toolbar = diagramContainer.data('toolbar'); 104 - if (toolbar === 'false') { 105 - delete config.toolbar; 106 - } else if (typeof toolbar === 'string') { 107 - config.toolbar = toolbar; 108 - } 109 - return config; 110 - }; 111 - 112 - const observer = new MutationObserver((mutations) => { 113 - mutations.forEach((mutation) => { 114 - mutation.addedNodes.forEach((node) => { 115 - if ($(node).hasClass('xwiki-diagram-drawio-toolbar')) { 116 - node.style.width = Math.min($('#xwikicontent').width(), parseInt(node.style.width)) + 'px'; 117 - } 118 - }); 119 - if (mutation.type === 'attributes') { 120 - if ($(mutation.target).hasClass('xwiki-diagram-drawio-toolbar')) { 121 - mutation.target.style.width = 122 - Math.min($('#xwikicontent').width(), parseInt(mutation.target.style.width)) + 'px'; 123 - } 124 - } 125 - }); 126 - }); 127 - 128 - // Enforce the maximum width of the diagram toolbar to prevent overflows. 129 - observer.observe(document.body, { 130 - childList: true, 131 - subtree: true, 132 - attributes: true, 133 - attributeFilter: ['style'] 134 - }); 135 - 136 - // Fix position of a dialog at the top of the window. 137 - Dialog.prototype.fixDialogPosition = function() { 138 - this.container.style.top = '0px'; 139 - this.container.style.position = 'fixed'; 140 - }; 141 - 142 - // If a diagram is inserted in a page with a lot of content before it, then PrintDialog won't be visible, since the 143 - // top of the dialog is computed to consider a page that only holds the diagram. 144 - var originalShowDialog = EditorUi.prototype.showDialog; 145 - EditorUi.prototype.showDialog = function(elt, w, h, modal, closable, onClose, noScroll, transparent, onResize, 146 - ignoreBgClick) { 147 - originalShowDialog.apply(this, arguments); 148 - var dialog = this.dialog; 149 - if ($(dialog.container).find("input[name='printZoom']")) { 150 - dialog.fixDialogPosition(); 151 - var originalResizeListener = dialog.resizeListener; 152 - dialog.resizeListener = mxUtils.bind(dialog, function() { 153 - originalResizeListener.apply(this, arguments); 154 - this.fixDialogPosition(); 155 - }); 156 - // Since the listener is already added at construction step, we need to remove it and reattach the new function. 157 - mxEvent.removeListener(window, 'resize', originalResizeListener); 158 - mxEvent.addListener(window, 'resize', dialog.resizeListener); 159 - } 160 - }; 161 - 162 - var getProxyUrl = function(url) { 163 - const queryParams = $.param({ 164 - 'url': url, 165 - 'xpage': 'plain', 166 - 'outputSyntax': 'plain', 167 - 'importDiagram': 'true', 168 - }); 169 - let ProxyUrl = new URL(window.PROXY_URL + '?' + queryParams, window.location); 170 - return ProxyUrl; 171 - }; 172 - 173 - var getDiagramXML = function(element) { 174 - let fromStorage = false; 175 - let diagramXML; 176 - let externalDiagramUrl = element.getAttribute('data-external-diagram-url'); 177 - if (externalDiagramUrl) { 178 - if (!xm.userReference) { 179 - // Protect against spamming the proxy. 180 - throw "Diagram preview from URL is not available for unregistered users"; 181 - } 182 - // If the diagram should be fetched from an external url, use a cache to reduce the amount of requests. For the 183 - // inplace WYSIWYG editor it's especially helpful, where there are 5-10 requests for the same source. 184 - if (!window.externalDiagramUrlCache) { 185 - window.externalDiagramUrlCache = new Map(); 186 - } 187 - diagramXML = window.externalDiagramUrlCache.get(externalDiagramUrl); 188 - if (!diagramXML) { 189 - // Use a proxy to get around CORS. 190 - diagramXML = mxUtils.load(getProxyUrl(externalDiagramUrl)).getXml().documentElement; 191 - window.externalDiagramUrlCache.set(externalDiagramUrl, diagramXML); 192 - } 193 - // Add the XML so drawio can access it. 194 - element.setAttribute('data-model', diagramXML.outerHTML); 195 - } else { 196 - diagramXML = diagramUtils.getDiagramXMLFromURL(window.location.href); 197 - if (!diagramXML) { 198 - diagramXML = $(element).data('model') || '<mxGraphModel/>'; 199 - // fromStorage is used to signal when to transform links from XWiki references to URLs. 200 - fromStorage = true; 201 - } 202 - diagramXML = mxUtils.parseXml(diagramXML).documentElement; 203 - } 204 - return [fromStorage, diagramXML]; 205 - }; 206 - 207 - var renderDiagram = function(element, diagramXML, fromStorage, configOverride) { 208 - element.innerHTML = ''; 209 - var diagramRootNode = diagramXML; 210 - if (!diagramRootNode || (diagramRootNode.localName != 'mxfile' && diagramRootNode.localName != 'mxGraphModel')) { 211 - throw "Invalid diagram XML."; 212 - } 213 - diagramRootNode.fromStorage = fromStorage; 214 - var config = $.extend(getDiagramViewerConfig($(element)), configOverride); 215 - var graphViewer = new GraphViewer(element, diagramRootNode, config); 216 - // Make the diagram title from the tool bar a link to the diagram page. 217 - if (config.title && config.reference) { 218 - var diagramViewURL = new XWiki.Document(config.reference).getURL(); 219 - var diagramLink = $('<a/>').attr('href', diagramViewURL).text(config.title); 220 - $(graphViewer.toolbar).children().last().empty().append(diagramLink); 221 - } 222 - // Identify the toolbar by class. 223 - $(graphViewer.toolbar).addClass('xwiki-diagram-drawio-toolbar'); 224 - } 225 - 226 - function getErrorKey(externalDiagramUrl, hasUser) { 227 - if (!externalDiagramUrl) return 'loadFailed'; 228 - return hasUser 229 - ? 'loadFailed.externalDiagramUrl' 230 - : 'loadFailed.externalDiagramUrl.guestUser'; 231 - } 232 - 233 - var renderError = function(element, text) { 234 - element.innerHTML = ''; 235 - $(element).html('<div class="box warningmessage"></div>'); 236 - $(element).children().text(text); 237 - }; 238 - 239 - const initializedDiagramMarkerClass = 'diagram-initialized'; 240 - $.fn.viewDiagram = function(configOverride) { 18 + $.fn.viewDiagram = function(options) { 19 + options = $.extend({ 20 + lightbox: false 21 + }, options); 241 241 return this.each(function() { 242 - try { 243 - // Guard against re-rendering an existing diagram or one which is in the process of displaying. 244 - if (!this.classList.contains(initializedDiagramMarkerClass)) { 245 - this.classList.add(initializedDiagramMarkerClass); 246 - let [fromStorage, diagramXML] = getDiagramXML(this); 247 - renderDiagram(this, diagramXML, fromStorage, configOverride); 248 - } 249 - } catch (e) { 250 - console.error(e); 251 - const externalDiagramUrl = this.getAttribute('data-external-diagram-url'); 252 - const errorMessage = getErrorKey(externalDiagramUrl, xm.userReference); 253 - renderError(this, l10n.get(errorMessage)); 254 - } 255 - }); 23 + var xmlDoc = mxUtils.parseXml($(this).data('model')); 24 + new GraphViewer(this, xmlDoc.documentElement, options); 25 + }).removeClass('loading'); 256 256 }; 257 257 258 - $(document).on('xwiki:dom:updated', function() { 259 - // When using the externalDiagramUrl parameter, and in the in-place WYSIWYG editor, reload the diagram on the client side. 260 - $('.diagram').viewDiagram(); 261 - }); 262 - 263 - return diagramUtils.loadTranslationAndTheme().done(function(theme) { 264 - // Configure the default viewer theme. 28 + var diagramViewerDeferred = $.Deferred(); 29 + // Load the default theme. The theme controls how the shapes are rendered. 30 + mxUtils.get(STYLE_PATH + '/default.xml', function(response) { 31 + // Configures the default viewer theme. 265 265 Graph.prototype.defaultThemes = Graph.prototype.defaultThemes || {}; 266 - Graph.prototype.defaultThemes[Graph.prototype.defaultThemeName] = theme; 33 + Graph.prototype.defaultThemes[Graph.prototype.defaultThemeName] = response.getDocumentElement(); 34 + diagramViewerDeferred.resolve(); 35 + }, function() { 36 + // Failed to load the theme. 37 + diagramViewerDeferred.reject(); 267 267 }); 39 + 40 + return diagramViewerDeferred.promise(); 268 268 });
- XWiki.JavaScriptExtension[2]
-
- Code
-
... ... @@ -1,37 +1,5 @@ 1 -/*! 2 -## Make sure that the version loaded with RequireJS is not a cached one. 3 -#set ($version = $services.extension.installed.getInstalledExtension('com.xwiki.diagram:application-diagram', 4 - "wiki:$xcontext.database").version.value) 5 -#set ($params = $escapetool.url({ 6 - 'minify': $!services.debug.minify, 7 - 'appVersion': $version 8 -})) 9 -#[[*/ 10 -// Start JavaScript-only code. 11 -(function(params) { 12 - "use strict"; 13 - 14 -require.config({ 15 - paths: { 16 - 'diagram-setup': new XWiki.Document('DiagramSheet', 'Diagram').getURL('jsx', params) 17 - }, 18 - map: { 19 - 'diagram-utils': { 20 - 'mxgraph-common': 'mxgraph-viewer' 21 - }, 22 - 'diagram-link-handler': { 23 - 'draw.io.common': 'draw.io.viewer' 24 - } 25 - } 26 -}); 27 - 28 -require(['diagram-setup'], function() { 29 - require(['jquery', 'diagram-viewer'], function($, diagramViewerPromise) { 30 - diagramViewerPromise.done(function() { 31 - $('.diagram').viewDiagram(); 32 - }); 1 +require(['jquery', 'diagramViewer'], function($, diagramViewerPromise) { 2 + diagramViewerPromise.done(function() { 3 + $('.diagram').viewDiagram(); 33 33 }); 34 34 }); 35 - 36 -// End JavaScript-only code. 37 -}).apply(']]#', $jsontool.serialize([$params]));
- XWiki.JavaScriptExtension[0]
-
- Pufferstrategie
-
... ... @@ -1,0 +1,1 @@ 1 +long - Code
-
... ... @@ -1,0 +1,32 @@ 1 +// mxGraph Client Configuration 2 +var mxBasePath = "$services.webjars.url('org.xwiki.contrib:mxgraph-client', '')"; 3 +var mxLoadResources = false; 4 + 5 +var mxGraphViewerBasePath = "$services.webjars.url('org.xwiki.contrib:mxgraph-editor', '')"; 6 + 7 +// Diagram Viewer Configuration 8 +var diagramViewerBasePath = "$services.webjars.url('org.xwiki.contrib:draw.io', '')"; 9 +var STENCIL_PATH = diagramViewerBasePath + 'stencils'; 10 +var IMAGE_PATH = diagramViewerBasePath + 'images'; 11 +var STYLE_PATH = CSS_PATH = diagramViewerBasePath + 'styles'; 12 +var SHAPES_PATH = diagramViewerBasePath + 'shapes'; 13 +var GRAPH_IMAGE_PATH = diagramViewerBasePath + 'img'; 14 + 15 +var urlParams = {}; 16 + 17 +require.config({ 18 + paths: { 19 + 'mxgraph-client': mxBasePath + 'mxClient.min', 20 + 'sanitizer': mxGraphViewerBasePath + 'sanitizer/sanitizer.min', 21 + 'mxgraph-viewer': mxGraphViewerBasePath + 'mxGraphViewer.min', 22 + 'draw.io.viewer': diagramViewerBasePath + 'js/draw.io.viewer.min' 23 + }, 24 + shim: { 25 + 'mxgraph-viewer': { 26 + deps: ['mxgraph-client', 'sanitizer'] 27 + }, 28 + 'draw.io.viewer': { 29 + deps: ['mxgraph-viewer'] 30 + } 31 + } 32 +}); - Name
-
... ... @@ -1,0 +1,1 @@ 1 +Configuration - Inhalt parsen
-
... ... @@ -1,0 +1,1 @@ 1 +Ja - Benutze diese Erweiterung
-
... ... @@ -1,0 +1,1 @@ 1 +onDemand
- XWiki.StyleSheetExtension[0]
-
- Pufferstrategie
-
... ... @@ -1,0 +1,1 @@ 1 +long - Code
-
... ... @@ -1,0 +1,23 @@ 1 +.diagram { 2 + min-height: 25px; 3 +} 4 + 5 +/** 6 + * Diagram Macro 7 + */ 8 +.geDiagramContainer, 9 +.diagram-container > .thumbnail { 10 + max-width: 100%; 11 +} 12 + 13 +.diagram-container > .thumbnail { 14 + display: inline-block; 15 +} 16 + 17 +.diagram-container > .thumbnail .box { 18 + margin-bottom: 0; 19 +} 20 + 21 +.diagram-container > .thumbnail svg { 22 + max-width: 100%; 23 +} - Content Type
-
... ... @@ -1,0 +1,1 @@ 1 +CSS - Inhalt parsen
-
... ... @@ -1,0 +1,1 @@ 1 +Nein - Benutze diese Erweiterung
-
... ... @@ -1,0 +1,1 @@ 1 +onDemand