Modifications pour le document DiagramEditSheet
Modifié par Admin le 19/03/2025 - 19:24
Résumé
-
Objets (1 modifications, 0 ajouts, 0 suppressions)
Détails
- XWiki.JavaScriptExtension[2]
-
- Code
-
... ... @@ -42,32 +42,6 @@ 42 42 // Do nothing. 43 43 } 44 44 45 - // Override the Graph.updateSvgLinks method to ensure that the links are preserved in the final SVG. 46 - // We need to directly modify the original method because drawio does not provide a parameter to override the default 47 - // behavior or a smaller method that only performs the replacement. 48 - Graph.prototype.updateSvgLinks = function (node, target, removeCustom) { 49 - var links = node.getElementsByTagName('a'); 50 - for (var i = 0; i < links.length; i++) { 51 - if (links[i].getAttribute('target') == null) { 52 - var href = links[i].getAttribute('href'); 53 - if (href == null) { 54 - href = links[i].getAttribute('xlink:href'); 55 - } 56 - 57 - if (href != null) { 58 - if (target != null && /^https?:\/\//.test(href)) { 59 - // If the href starts with http or https, set the target attribute. 60 - links[i].setAttribute('target', target); 61 - } else if (this.isCustomLink(href)) { 62 - // Handle custom links 63 - let absoluteLink = $('<a/>').attr('href', diagramLinkHandler.getURLFromCustomLink(href)).prop('href'); 64 - links[i].setAttribute('href', absoluteLink); 65 - } 66 - } 67 - } 68 - } 69 - }; 70 - 71 71 // Overwrite Graph.getSvg in order to replace XWiki custom links with absolute URLs. 72 72 // Also fix the text fallback for viewers with no support for foreignObjects. 73 73 var originalGraphGetSVG = Graph.prototype.getSvg; ... ... @@ -127,6 +127,318 @@ 127 127 return converter; 128 128 }; 129 129 104 + // Copied from the drawio version 24.5.4 to include a fix for importing a file in an empty diagram. This method should 105 + // be removed once we upgrade to a drawio version >= 24.4.0. Being a big method, the structure was altered just to 106 + // make it shorter. 107 + var importFilesNew = function(files, x, y, maxSize, fn, resultFn, filterFn, barrierFn, 108 + resizeDialog, maxBytes, resampleThreshold, ignoreEmbeddedXml, evt) { 109 + maxSize = (maxSize != null) ? maxSize : this.maxImageSize; 110 + maxBytes = (maxBytes != null) ? maxBytes : this.maxImageBytes; 111 + var crop = x != null && y != null; 112 + var resizeImages = true; 113 + x = (x != null) ? x : 0; 114 + y = (y != null) ? y : 0; 115 + // Checks if large images are imported 116 + var largeImages = false; 117 + if (!mxClient.IS_CHROMEAPP && files != null) { 118 + var thresh = resampleThreshold || this.resampleThreshold; 119 + for (var i = 0; i < files.length; i++) { 120 + if (files[i].type.substring(0, 9) !== 'image/svg' && 121 + files[i].type.substring(0, 6) === 'image/' && 122 + files[i].size > thresh) { 123 + largeImages = true; 124 + break; 125 + } 126 + } 127 + } 128 + var doImportFiles = mxUtils.bind(this, function() { 129 + var graph = this.editor.graph; 130 + var gs = graph.gridSize; 131 + fn = (fn != null) ? fn : mxUtils.bind(this, function(data, mimeType, x, y, w, h, filename, done, file) { 132 + try { 133 + if (data != null && data.substring(0, 10) == '<mxlibrary') { 134 + this.spinner.stop(); 135 + this.loadLibrary(new LocalLibrary(this, data, filename)); 136 + this.showSidebar(); 137 + return null; 138 + } 139 + else { 140 + // Drop on empty file ignores drop location 141 + if (this.isCompatibleString(data) && files.length == 1 && evt != null && 142 + evt.type == 'drop' && this.isBlankFile() && !this.canUndo()) { 143 + crop = false; 144 + x = 0; 145 + y = 0; 146 + } 147 + return this.importFile(data, mimeType, x, y, w, h, filename, 148 + done, file, crop, ignoreEmbeddedXml, evt); 149 + } 150 + } 151 + catch (e) { 152 + this.handleError(e); 153 + return null; 154 + } 155 + }); 156 + resultFn = (resultFn != null) ? resultFn : mxUtils.bind(this, function(cells) { 157 + graph.setSelectionCells(cells); 158 + }); 159 + if (this.spinner.spin(document.body, mxResources.get('loading'))) { 160 + var count = files.length; 161 + var remain = count; 162 + var queue = []; 163 + // Barrier waits for all files to be loaded asynchronously 164 + var barrier = mxUtils.bind(this, function(index, fnc) { 165 + queue[index] = fnc; 166 + if (--remain == 0) { 167 + this.spinner.stop(); 168 + if (barrierFn != null) { 169 + barrierFn(queue); 170 + } 171 + else { 172 + var cells = []; 173 + graph.getModel().beginUpdate(); 174 + try { 175 + for (var j = 0; j < queue.length; j++) { 176 + var tmp = queue[j](); 177 + if (tmp != null) { 178 + cells = cells.concat(tmp); 179 + } 180 + } 181 + } 182 + finally { 183 + graph.getModel().endUpdate(); 184 + } 185 + } 186 + resultFn(cells); 187 + } 188 + }); 189 + for (var i = 0; i < count; i++) { 190 + (mxUtils.bind(this, function(index) { 191 + var file = files[index]; 192 + if (file != null) { 193 + var reader = new FileReader(); 194 + reader.onload = mxUtils.bind(this, function(e) { 195 + if (filterFn == null || filterFn(file)) { 196 + try { 197 + if (file.type.substring(0, 6) == 'image/') { 198 + if (file.type.substring(0, 9) == 'image/svg') { 199 + // Checks if SVG contains content attribute 200 + var data = Graph.clipSvgDataUri(e.target.result); 201 + var comma = data.indexOf(','); 202 + var svgText = decodeURIComponent(escape(atob(data.substring(comma + 1)))); 203 + var root = mxUtils.parseXml(svgText); 204 + var svgs = root.getElementsByTagName('svg'); 205 + if (svgs.length > 0) { 206 + var svgRoot = svgs[0]; 207 + var cont = (ignoreEmbeddedXml) ? null : svgRoot.getAttribute('content'); 208 + if (cont != null && cont.charAt(0) != '<' && cont.charAt(0) != '%') { 209 + cont = unescape((window.atob) ? atob(cont) : Base64.decode(cont, true)); 210 + } 211 + if (cont != null && cont.charAt(0) == '%') { 212 + cont = decodeURIComponent(cont); 213 + } 214 + if (cont != null && (cont.substring(0, 8) === '<mxfile ' || 215 + cont.substring(0, 14) === '<mxGraphModel ')) { 216 + barrier(index, mxUtils.bind(this, function() { 217 + return fn(cont, 'text/xml', x + index * gs, y + index * gs, 0, 0, file.name); 218 + })); 219 + } 220 + else { 221 + // SVG needs special handling to add viewbox if missing and 222 + // find initial size from SVG attributes (only for IE11) 223 + barrier(index, mxUtils.bind(this, function() { 224 + try { 225 + // Parses SVG and find width and height 226 + if (root != null) { 227 + var svgs = root.getElementsByTagName('svg'); 228 + if (svgs.length > 0) { 229 + var svgRoot = svgs[0]; 230 + var w = svgRoot.getAttribute('width'); 231 + var h = svgRoot.getAttribute('height'); 232 + if (w != null && w.charAt(w.length - 1) != '%') { 233 + w = parseFloat(w); 234 + } 235 + else { 236 + w = NaN; 237 + } 238 + if (h != null && h.charAt(h.length - 1) != '%') { 239 + h = parseFloat(h); 240 + } 241 + else { 242 + h = NaN; 243 + } 244 + // Check if viewBox attribute already exists 245 + var vb = svgRoot.getAttribute('viewBox'); 246 + if (vb == null || vb.length == 0) { 247 + svgRoot.setAttribute('viewBox', '0 0 ' + w + ' ' + h); 248 + } 249 + // Uses width and height from viewbox for 250 + // missing width and height attributes 251 + else if (isNaN(w) || isNaN(h)) { 252 + var tokens = vb.split(' '); 253 + if (tokens.length > 3) { 254 + w = parseFloat(tokens[2]); 255 + h = parseFloat(tokens[3]); 256 + } 257 + } 258 + data = Editor.createSvgDataUri(mxUtils.getXml(svgRoot)); 259 + var s = Math.min(1, Math.min(maxSize / Math.max(1, w)), maxSize / Math.max(1, h)); 260 + var cells = fn(data, file.type, x + index * gs, y + index * gs, Math.max( 261 + 1, Math.round(w * s)), Math.max(1, Math.round(h * s)), file.name); 262 + // Hack to fix width and height asynchronously 263 + if (cells != null && (isNaN(w) || isNaN(h))) { 264 + var img = new Image(); 265 + img.onload = mxUtils.bind(this, function() { 266 + w = Math.max(1, img.width); 267 + h = Math.max(1, img.height); 268 + cells[0].geometry.width = w; 269 + cells[0].geometry.height = h; 270 + svgRoot.setAttribute('viewBox', '0 0 ' + w + ' ' + h); 271 + data = Editor.createSvgDataUri(mxUtils.getXml(svgRoot)); 272 + var semi = data.indexOf(';'); 273 + if (semi > 0) { 274 + data = data.substring(0, semi) + data.substring(data.indexOf(',', semi + 1)); 275 + } 276 + graph.setCellStyles('image', data, [cells[0]]); 277 + }); 278 + img.src = Editor.createSvgDataUri(mxUtils.getXml(svgRoot)); 279 + } 280 + return cells; 281 + } 282 + } 283 + } 284 + catch (e) { 285 + // ignores any SVG parsing errors 286 + } 287 + return null; 288 + })); 289 + } 290 + } 291 + else { 292 + barrier(index, mxUtils.bind(this, function() { 293 + return null; 294 + })); 295 + } 296 + } 297 + else { 298 + // Checks if PNG+XML is available to bypass code below 299 + var containsModel = false; 300 + if (file.type == 'image/png') { 301 + var xml = (ignoreEmbeddedXml) ? null : this.extractGraphModelFromPng(e.target.result); 302 + if (xml != null && xml.length > 0) { 303 + var img = new Image(); 304 + img.src = e.target.result; 305 + barrier(index, mxUtils.bind(this, function() { 306 + return fn(xml, 'text/xml', x + index * gs, y + index * gs, 307 + img.width, img.height, file.name); 308 + })); 309 + containsModel = true; 310 + } 311 + } 312 + // Additional asynchronous step for finding image size 313 + if (!containsModel) { 314 + // Cannot load local files in Chrome App 315 + if (mxClient.IS_CHROMEAPP) { 316 + this.spinner.stop(); 317 + this.showError(mxResources.get('error'), mxResources.get('dragAndDropNotSupported'), 318 + mxResources.get('cancel'), mxUtils.bind(this, function() 319 + { 320 + // Hides the dialog 321 + }), null, mxResources.get('ok'), mxUtils.bind(this, function() 322 + { 323 + // Redirects to import function 324 + this.actions.get('import').funct(); 325 + }) 326 + ); 327 + } 328 + else { 329 + this.loadImage(e.target.result, mxUtils.bind(this, function(img) { 330 + this.resizeImage(img, e.target.result, mxUtils.bind(this, function(data2, w2, h2) { 331 + barrier(index, mxUtils.bind(this, function() { 332 + // Refuses to insert images above a certain size as they kill the app 333 + if (data2 != null && data2.length < maxBytes) { 334 + var s = (!resizeImages || !this.isResampleImageSize( 335 + file.size, resampleThreshold)) ? 1 : 336 + Math.min(1, Math.min(maxSize / w2, maxSize / h2)); 337 + return fn(data2, file.type, x + index * gs, y + index * gs, 338 + Math.round(w2 * s), Math.round(h2 * s), file.name); 339 + } 340 + else { 341 + this.handleError({message: mxResources.get('imageTooBig')}); 342 + return null; 343 + } 344 + })); 345 + }), resizeImages, maxSize, resampleThreshold, file.size); 346 + }), mxUtils.bind(this, function() { 347 + this.handleError({message: mxResources.get('invalidOrMissingFile')}); 348 + })); 349 + } 350 + } 351 + } 352 + } 353 + else { 354 + var data = e.target.result; 355 + fn(data, file.type, x + index * gs, y + index * gs, 240, 160, file.name, function(cells) { 356 + barrier(index, function() { 357 + return cells; 358 + }); 359 + }, file); 360 + } 361 + } 362 + catch (e) { 363 + // Ignores file parsing error 364 + barrier(index, mxUtils.bind(this, function() { 365 + return null; 366 + })); 367 + if (window.console != null) { 368 + console.error(e, file); 369 + } 370 + } 371 + } 372 + else { 373 + // Ignores file and decrements counter 374 + barrier(index, mxUtils.bind(this, function() 375 + { 376 + return null; 377 + })); 378 + } 379 + }); 380 + // Handles special cases 381 + if (/(\.v(dx|sdx?))($|\?)/i.test(file.name) || /(\.vs(x|sx?))($|\?)/i.test(file.name)) { 382 + fn(null, file.type, x + index * gs, y + index * gs, 240, 160, file.name, function(cells) { 383 + barrier(index, function() { 384 + return cells; 385 + }); 386 + }, file); 387 + } 388 + else if (file.type.substring(0, 5) == 'image' || file.type == 'application/pdf') { 389 + reader.readAsDataURL(file); 390 + } 391 + else { 392 + reader.readAsText(file); 393 + } 394 + } 395 + }))(i); 396 + } 397 + } 398 + }); 399 + if (largeImages) { 400 + // Workaround for lost files array in async code 401 + var tmp = []; 402 + for (var i = 0; i < files.length; i++) { 403 + tmp.push(files[i]); 404 + } 405 + files = tmp; 406 + this.confirmImageResize(function(doResize) { 407 + resizeImages = doResize; 408 + doImportFiles(); 409 + }, resizeDialog); 410 + } 411 + else { 412 + doImportFiles(); 413 + } 414 + }; 415 + 130 130 // Override for uploading the image as attachment instead of encode it to Base64. 131 131 var originalImportFiles = EditorUi.prototype.importFiles; 132 132 EditorUi.prototype.importFiles = function(files, x, y, maxSize, fn, resultFn, filterFn, barrierFn, resizeDialog, ... ... @@ -156,7 +156,7 @@ 156 156 } 157 157 }; 158 158 } 159 - originalImportFiles.apply(this, importFilesArgs);445 + importFilesNew.apply(this, importFilesArgs); 160 160 }; 161 161 162 162 // Add support for inserting images by specifying the XWiki attachment reference. ... ... @@ -290,15 +290,6 @@ 290 290 }; 291 291 }); 292 292 293 -define('diagramMenuTranslations', { 294 - prefix: 'diagram.editor.menu.', 295 - keys: [ 296 - // File menu. 297 - 'print.label', 298 - 'print.title' 299 - ] 300 -}); 301 - 302 302 /** 303 303 * Integrates draw.io diagram editor in XWiki. 304 304 */ ... ... @@ -308,12 +308,11 @@ 308 308 'diagram-utils', 309 309 'diagram-url-io', 310 310 'diagram-config', 311 - 'xwiki-l10n!diagramMenuTranslations', 312 312 'diagram-graph-xml-filter', 313 313 'diagram-link-editor', 314 314 'diagram-image-editor', 315 315 'diagram-external-services' 316 -], function($, diagramStore, diagramUtils, diagramUrlIO, diagramConfig , l10n) {592 +], function($, diagramStore, diagramUtils, diagramUrlIO, diagramConfig) { 317 317 318 318 // These variables are used to decide if an image should be uploaded at original resolution or 319 319 // should be declined for being too big. ... ... @@ -345,7 +345,6 @@ 345 345 346 346 var fixEditorUI = function(editorUI) { 347 347 cleanMenu(editorUI); 348 - renameMenu(editorUI); 349 349 fixKeyboardShortcutsAction(editorUI); 350 350 fixEditorButtons($(editorUI.container)); 351 351 removeThemeButton(); ... ... @@ -385,31 +385,11 @@ 385 385 var originalAddSubmenu = Menus.prototype.addSubmenu; 386 386 Menus.prototype.addSubmenu = function(name, menu, parent, label) { 387 387 var subMenu = this.get(name); 388 - if (subMenu && subMenu.is Enabled()!== false) {389 - returnoriginalAddSubmenu.apply(this, arguments);663 + if (subMenu && subMenu.visible !== false) { 664 + originalAddSubmenu.apply(this, arguments); 390 390 } 391 391 }; 392 392 393 - 394 - /* 395 - * Map with all the menu items that we want to have a title. 396 - */ 397 - const titleMap = new Map([ 398 - ['print', l10n['print.title']] 399 - ]); 400 - 401 - /* 402 - * Update the title of the menu items. 403 - */ 404 - var originalAddMenuItem = Menus.prototype.addMenuItem; 405 - Menus.prototype.addMenuItem = function(menu, key, parent, trigger, sprite, label) { 406 - let item = originalAddMenuItem.apply(this, arguments); 407 - if (item != null && titleMap.has(key)) { 408 - item.title = titleMap.get(key); 409 - } 410 - return item; 411 - }; 412 - 413 413 // Remove the language picker because the diagram editor is configured to use the XWiki language. 414 414 var originalCreateMenubar = Menus.prototype.createMenubar; 415 415 Menus.prototype.createMenubar = function(container) { ... ... @@ -429,24 +429,6 @@ 429 429 }; 430 430 431 431 // 432 - // Rename menu options to fit our needs. 433 - // 434 - var renameMenu = function(editorUI) { 435 - const menuItems = [ 436 - // File menu 437 - ['print', l10n['print.label']] 438 - ]; 439 - 440 - // Iterate over the array of tuples 441 - menuItems.forEach(function([menuKey, newLabel]) { 442 - var action = editorUI.actions.actions[menuKey]; 443 - if (action) { 444 - action.label = newLabel; 445 - } 446 - }); 447 - }; 448 - 449 - // 450 450 // Clean the editor menu by removing the features that are not needed. 451 451 // 452 452 var cleanMenu = function(editorUI) { ... ... @@ -459,7 +459,7 @@ 459 459 // Help menu 460 460 'downloadDesktop', 'useOffline', 461 461 // ExportAs 462 - 'exportHtml' , 'exportPdf'699 + 'exportHtml' 463 463 ].forEach(function(actionName) { 464 464 var action = editorUI.actions.actions[actionName]; 465 465 if (action) {