Änderungen von Dokument DiagramViewSheet

Zuletzt geändert von Daniel Herrmann am 2026/02/04 20:25

Von Version Icon 2.1
bearbeitet von Daniel Herrmann
am 2026/02/04 20:25
Änderungskommentar: Install extension [com.xwiki.diagram:application-diagram/1.22.11]
Auf Version 1.1 Icon
bearbeitet von Mike Schneider
am 2025/12/30 10:37
Änderungskommentar: Install extension [org.xwiki.contrib:application-diagram/1.3]

Zusammenfassung

Details

Icon Seiteneigenschaften
Dokument-Autor
... ... @@ -1,1 +1,1 @@
1 -XWiki.dherrman
1 +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}}
Icon 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  });
Icon 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]));
Icon 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
Icon 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