1/** 2 * Copyright (c) 2006-2020, JGraph Ltd 3 * Copyright (c) 2006-2020, draw.io AG 4 */ 5 6var StorageDialog = function(editorUi, fn, rowLimit) 7{ 8 rowLimit = (rowLimit != null) ? rowLimit : 2; 9 10 var div = document.createElement('div'); 11 div.style.textAlign = 'center'; 12 div.style.whiteSpace = 'nowrap'; 13 div.style.paddingTop = '0px'; 14 div.style.paddingBottom = '20px'; 15 16 var buttons = document.createElement('div'); 17 buttons.style.border = '1px solid #d3d3d3'; 18 buttons.style.borderWidth = '1px 0px 1px 0px'; 19 buttons.style.padding = '10px 0px 20px 0px'; 20 21 var count = 0, totalBtns = 0; 22 var container = document.createElement('div'); 23 container.style.paddingTop = '2px'; 24 buttons.appendChild(container); 25 26 var p3 = document.createElement('p'); 27 28 function addLogo(img, title, mode, clientName, labels, clientFn) 29 { 30 totalBtns++; 31 32 if (++count > rowLimit) 33 { 34 mxUtils.br(container); 35 count = 1; 36 } 37 38 var button = document.createElement('a'); 39 button.style.overflow = 'hidden'; 40 button.style.display = 'inline-block'; 41 button.className = 'geBaseButton'; 42 button.style.boxSizing = 'border-box'; 43 button.style.fontSize = '11px'; 44 button.style.position = 'relative'; 45 button.style.margin = '4px'; 46 button.style.marginTop = '8px'; 47 button.style.marginBottom = '0px'; 48 button.style.padding = '8px 10px 8px 10px'; 49 button.style.width = '88px'; 50 button.style.height = '100px'; 51 button.style.whiteSpace = 'nowrap'; 52 button.setAttribute('title', title); 53 54 var label = document.createElement('div'); 55 label.style.textOverflow = 'ellipsis'; 56 label.style.overflow = 'hidden'; 57 label.style.position = 'absolute'; 58 label.style.bottom = '8px'; 59 label.style.left = '0px'; 60 label.style.right = '0px'; 61 mxUtils.write(label, title); 62 button.appendChild(label); 63 64 if (img != null) 65 { 66 var logo = document.createElement('img'); 67 logo.setAttribute('src', img); 68 logo.setAttribute('border', '0'); 69 logo.setAttribute('align', 'absmiddle'); 70 logo.style.width = '60px'; 71 logo.style.height = '60px'; 72 logo.style.paddingBottom = '6px'; 73 74 button.appendChild(logo); 75 } 76 else 77 { 78 label.style.paddingTop = '5px'; 79 label.style.whiteSpace = 'normal'; 80 81 // Handles special case 82 if (mxClient.IS_IOS) 83 { 84 button.style.padding = '0px 10px 20px 10px'; 85 button.style.top = '6px'; 86 } 87 else if (mxClient.IS_FF) 88 { 89 label.style.paddingTop = '0px'; 90 label.style.marginTop = '-2px'; 91 } 92 } 93 94 if (labels != null) 95 { 96 for (var i = 0; i < labels.length; i++) 97 { 98 mxUtils.br(label); 99 mxUtils.write(label, labels[i]); 100 } 101 } 102 103 function initButton() 104 { 105 mxEvent.addListener(button, 'click', (clientFn != null) ? clientFn : function() 106 { 107 // Special case: Redirect all drive users to draw.io pro 108 if (mode == App.MODE_GOOGLE && !editorUi.isDriveDomain()) 109 { 110 window.location.hostname = DriveClient.prototype.newAppHostname; 111 } 112 else if (mode == App.MODE_GOOGLE && editorUi.spinner.spin(document.body, mxResources.get('authorizing'))) 113 { 114 // Tries immediate authentication 115 editorUi.drive.checkToken(mxUtils.bind(this, function() 116 { 117 editorUi.spinner.stop(); 118 editorUi.setMode(mode, true); 119 fn(); 120 })); 121 } 122 else if (mode == App.MODE_ONEDRIVE && editorUi.spinner.spin(document.body, mxResources.get('authorizing'))) 123 { 124 // Tries immediate authentication 125 editorUi.oneDrive.checkToken(mxUtils.bind(this, function() 126 { 127 editorUi.spinner.stop(); 128 editorUi.setMode(mode, true); 129 fn(); 130 })); 131 } 132 else 133 { 134 editorUi.setMode(mode, true); 135 fn(); 136 } 137 }); 138 }; 139 140 // Supports lazy loading 141 if (clientName != null && editorUi[clientName] == null) 142 { 143 logo.style.visibility = 'hidden'; 144 mxUtils.setOpacity(label, 10); 145 var size = 12; 146 147 var spinner = new Spinner({ 148 lines: 12, // The number of lines to draw 149 length: size, // The length of each line 150 width: 5, // The line thickness 151 radius: 10, // The radius of the inner circle 152 rotate: 0, // The rotation offset 153 color: Editor.isDarkMode() ? '#c0c0c0' : '#000', // #rgb or #rrggbb 154 speed: 1.5, // Rounds per second 155 trail: 60, // Afterglow percentage 156 shadow: false, // Whether to render a shadow 157 hwaccel: false, // Whether to use hardware acceleration 158 top: '40%', 159 zIndex: 2e9 // The z-index (defaults to 2000000000) 160 }); 161 spinner.spin(button); 162 163 // Timeout after 30 secs 164 var timeout = window.setTimeout(function() 165 { 166 if (editorUi[clientName] == null) 167 { 168 spinner.stop(); 169 button.style.display = 'none'; 170 } 171 }, 30000); 172 173 editorUi.addListener('clientLoaded', mxUtils.bind(this, function(sender, evt) 174 { 175 if (editorUi[clientName] != null && evt.getProperty('client') == editorUi[clientName]) 176 { 177 window.clearTimeout(timeout); 178 mxUtils.setOpacity(label, 100); 179 logo.style.visibility = ''; 180 spinner.stop(); 181 initButton(); 182 183 if (clientName == 'drive' && p3.parentNode != null) 184 { 185 p3.parentNode.removeChild(p3); 186 } 187 } 188 })); 189 } 190 else 191 { 192 initButton(); 193 } 194 195 container.appendChild(button); 196 }; 197 198 var hd = document.createElement('p'); 199 hd.style.cssText = 'font-size:22px;padding:4px 0 16px 0;margin:0;color:gray;'; 200 mxUtils.write(hd, mxResources.get('saveDiagramsTo') + ':'); 201 div.appendChild(hd); 202 203 var addButtons = function() 204 { 205 count = 0; 206 207 if (typeof window.DriveClient === 'function') 208 { 209 addLogo(IMAGE_PATH + '/google-drive-logo.svg', mxResources.get('googleDrive'), App.MODE_GOOGLE, 'drive'); 210 } 211 212 if (typeof window.OneDriveClient === 'function') 213 { 214 addLogo(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), App.MODE_ONEDRIVE, 'oneDrive'); 215 } 216 217 if (urlParams['noDevice'] != '1') 218 { 219 addLogo(IMAGE_PATH + '/osa_drive-harddisk.png', mxResources.get('device'), App.MODE_DEVICE); 220 } 221 222 if (isLocalStorage && (urlParams['browser'] == '1' || urlParams['offline'] == '1')) 223 { 224 addLogo(IMAGE_PATH + '/osa_database.png', mxResources.get('browser'), App.MODE_BROWSER); 225 } 226 227 if (typeof window.DropboxClient === 'function') 228 { 229 addLogo(IMAGE_PATH + '/dropbox-logo.svg', mxResources.get('dropbox'), App.MODE_DROPBOX, 'dropbox'); 230 } 231 232 if (editorUi.gitHub != null) 233 { 234 addLogo(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), App.MODE_GITHUB, 'gitHub'); 235 } 236 237 if (editorUi.gitLab != null) 238 { 239 addLogo(IMAGE_PATH + '/gitlab-logo.svg', mxResources.get('gitlab'), App.MODE_GITLAB, 'gitLab'); 240 } 241 242 if (totalBtns < 6 && editorUi.notion != null) 243 { 244 addLogo(IMAGE_PATH + '/notion-logo.svg', mxResources.get('notion'), App.MODE_NOTION, 'notion'); 245 } 246 }; 247 248 div.appendChild(buttons); 249 addButtons(); 250 251 var later = document.createElement('span'); 252 later.style.cssText = 'position:absolute;cursor:pointer;bottom:27px;color:gray;userSelect:none;text-align:center;left:50%;'; 253 mxUtils.setPrefixedStyle(later.style, 'transform', 'translate(-50%,0)'); 254 mxUtils.write(later, mxResources.get('decideLater')); 255 256 mxEvent.addListener(later, 'click', function() 257 { 258 editorUi.hideDialog(); 259 var prev = Editor.useLocalStorage; 260 editorUi.createFile(editorUi.defaultFilename, 261 null, null, null, null, null, null, true); 262 Editor.useLocalStorage = prev; 263 }); 264 265 div.appendChild(later); 266 267 // Checks if Google Drive is missing after a 5 sec delay 268 if (mxClient.IS_SVG && isLocalStorage && urlParams['gapi'] != '0' && 269 (document.documentMode == null || document.documentMode >= 10)) 270 { 271 window.setTimeout(function() 272 { 273 if (editorUi.drive == null) 274 { 275 // To check for Disconnect plugin in chrome use mxClient.IS_GC and check for URL: 276 // chrome-extension://jeoacafpbcihiomhlakheieifhpjdfeo/scripts/vendor/jquery/jquery-2.0.3.min.map 277 p3.style.padding = '7px'; 278 p3.style.fontSize = '9pt'; 279 p3.style.marginTop = '-14px'; 280 p3.innerHTML = '<a style="background-color:#dcdcdc;padding:6px;color:black;text-decoration:none;" ' + 281 'href="https://desk.draw.io/a/solutions/articles/16000074659" target="_blank">' + 282 '<img border="0" src="' + mxGraph.prototype.warningImage.src + '" align="absmiddle" ' + 283 'style="margin-top:-4px"> ' + mxResources.get('googleDriveMissingClickHere') + '</a>'; 284 div.appendChild(p3); 285 } 286 }, 5000); 287 } 288 289 this.container = div; 290}; 291 292/** 293 * Constructs a dialog for creating new files from templates. 294 */ 295var SplashDialog = function(editorUi) 296{ 297 var div = document.createElement('div'); 298 div.style.textAlign = 'center'; 299 300 if (mxClient.IS_CHROMEAPP || EditorUi.isElectronApp) 301 { 302 var elt = editorUi.addLanguageMenu(div, true); 303 304 if (elt != null) 305 { 306 elt.style.bottom = '19px'; 307 } 308 } 309 310 var serviceCount = editorUi.getServiceCount(); 311 var logo = document.createElement('img'); 312 logo.setAttribute('border', '0'); 313 logo.setAttribute('align', 'absmiddle'); 314 logo.style.width = '32px'; 315 logo.style.height = '32px'; 316 logo.style.marginRight = '8px'; 317 logo.style.marginTop = '-4px'; 318 319 var buttons = document.createElement('div'); 320 buttons.style.margin = '8px 0px 0px 0px'; 321 buttons.style.padding = '18px 0px 24px 0px'; 322 323 var service = ''; 324 325 if (editorUi.mode == App.MODE_GOOGLE) 326 { 327 logo.src = IMAGE_PATH + '/google-drive-logo.svg'; 328 service = mxResources.get('googleDrive'); 329 } 330 else if (editorUi.mode == App.MODE_DROPBOX) 331 { 332 logo.src = IMAGE_PATH + '/dropbox-logo.svg'; 333 service = mxResources.get('dropbox'); 334 } 335 else if (editorUi.mode == App.MODE_ONEDRIVE) 336 { 337 logo.src = IMAGE_PATH + '/onedrive-logo.svg'; 338 service = mxResources.get('oneDrive'); 339 } 340 else if (editorUi.mode == App.MODE_GITHUB) 341 { 342 logo.src = IMAGE_PATH + '/github-logo.svg'; 343 service = mxResources.get('github'); 344 } 345 else if (editorUi.mode == App.MODE_GITLAB) 346 { 347 logo.src = IMAGE_PATH + '/gitlab-logo.svg'; 348 service = mxResources.get('gitlab'); 349 } 350 else if (editorUi.mode == App.MODE_NOTION) 351 { 352 logo.src = IMAGE_PATH + '/notion-logo.svg'; 353 service = mxResources.get('notion'); 354 } 355 else if (editorUi.mode == App.MODE_BROWSER) 356 { 357 logo.src = IMAGE_PATH + '/osa_database.png'; 358 service = mxResources.get('browser'); 359 } 360 else if (editorUi.mode == App.MODE_TRELLO) 361 { 362 logo.src = IMAGE_PATH + '/trello-logo.svg'; 363 service = mxResources.get('trello'); 364 } 365 else 366 { 367 logo.src = IMAGE_PATH + '/osa_drive-harddisk.png'; 368 buttons.style.paddingBottom = '10px'; 369 buttons.style.paddingTop = '30px'; 370 service = mxResources.get('device'); 371 } 372 373 var btn = document.createElement('button'); 374 btn.className = 'geBigButton'; 375 btn.style.marginBottom = '8px'; 376 btn.style.fontSize = '18px'; 377 btn.style.padding = '10px'; 378 btn.style.width = '340px'; 379 380 if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp) 381 { 382 buttons.style.border = '1px solid #d3d3d3'; 383 buttons.style.borderWidth = '1px 0px 1px 0px'; 384 385 var table = document.createElement('table'); 386 var tbody = document.createElement('tbody'); 387 var row = document.createElement('tr'); 388 var left = document.createElement('td'); 389 var right = document.createElement('td'); 390 table.setAttribute('align', 'center'); 391 left.appendChild(logo); 392 393 var title = document.createElement('div'); 394 title.style.fontSize = '22px'; 395 title.style.paddingBottom = '6px'; 396 title.style.color = 'gray'; 397 mxUtils.write(title, service); 398 399 right.style.textAlign = 'left'; 400 right.appendChild(title); 401 402 row.appendChild(left); 403 row.appendChild(right); 404 tbody.appendChild(row); 405 table.appendChild(tbody); 406 div.appendChild(table); 407 408 var change = document.createElement('span'); 409 change.style.cssText = 'position:absolute;cursor:pointer;bottom:27px;color:gray;userSelect:none;text-align:center;left:50%;'; 410 mxUtils.setPrefixedStyle(change.style, 'transform', 'translate(-50%,0)'); 411 mxUtils.write(change, mxResources.get('changeStorage')); 412 413 mxEvent.addListener(change, 'click', function() 414 { 415 editorUi.hideDialog(false); 416 editorUi.setMode(null); 417 editorUi.clearMode(); 418 editorUi.showSplash(true); 419 }); 420 421 div.appendChild(change); 422 } 423 else 424 { 425 buttons.style.padding = '42px 0px 10px 0px'; 426 btn.style.marginBottom = '12px'; 427 } 428 429 mxUtils.write(btn, mxResources.get('createNewDiagram')); 430 431 mxEvent.addListener(btn, 'click', function() 432 { 433 editorUi.hideDialog(); 434 editorUi.actions.get('new').funct(); 435 }); 436 437 buttons.appendChild(btn); 438 mxUtils.br(buttons); 439 440 var btn = document.createElement('button'); 441 btn.className = 'geBigButton'; 442 btn.style.marginBottom = '22px'; 443 btn.style.fontSize = '18px'; 444 btn.style.padding = '10px'; 445 btn.style.width = '340px'; 446 447 mxUtils.write(btn, mxResources.get('openExistingDiagram')); 448 449 mxEvent.addListener(btn, 'click', function() 450 { 451 editorUi.actions.get('open').funct(); 452 }); 453 454 buttons.appendChild(btn); 455 456 var storage = 'undefined'; 457 458 if (editorUi.mode == App.MODE_GOOGLE) 459 { 460 storage = mxResources.get('googleDrive'); 461 } 462 else if (editorUi.mode == App.MODE_DROPBOX) 463 { 464 storage = mxResources.get('dropbox'); 465 } 466 else if (editorUi.mode == App.MODE_ONEDRIVE) 467 { 468 storage = mxResources.get('oneDrive'); 469 } 470 else if (editorUi.mode == App.MODE_GITHUB) 471 { 472 storage = mxResources.get('github'); 473 } 474 else if (editorUi.mode == App.MODE_GITLAB) 475 { 476 storage = mxResources.get('gitlab'); 477 } 478 else if (editorUi.mode == App.MODE_NOTION) 479 { 480 storage = mxResources.get('notion'); 481 } 482 else if (editorUi.mode == App.MODE_TRELLO) 483 { 484 storage = mxResources.get('trello'); 485 } 486 else if (editorUi.mode == App.MODE_DEVICE) 487 { 488 storage = mxResources.get('device'); 489 } 490 else if (editorUi.mode == App.MODE_BROWSER) 491 { 492 storage = mxResources.get('browser'); 493 } 494 495 if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp) 496 { 497 function addLogout(logout) 498 { 499 btn.style.marginBottom = '24px'; 500 501 var link = document.createElement('a'); 502 link.style.display = 'inline-block'; 503 link.style.color = 'gray'; 504 link.style.cursor = 'pointer'; 505 link.style.marginTop = '6px'; 506 mxUtils.write(link, mxResources.get('signOut')); 507 508 // Makes room after last big buttons 509 btn.style.marginBottom = '16px'; 510 buttons.style.paddingBottom = '18px'; 511 512 mxEvent.addListener(link, 'click', function() 513 { 514 editorUi.confirm(mxResources.get('areYouSure'), function() 515 { 516 logout(); 517 }); 518 }); 519 520 buttons.appendChild(link); 521 }; 522 523 if (editorUi.mode == App.MODE_GOOGLE && editorUi.drive != null) 524 { 525 var driveUsers =editorUi.drive.getUsersList(); 526 527 if (driveUsers.length > 0) 528 { 529 var title = document.createElement('span'); 530 title.style.marginTop = '6px'; 531 mxUtils.write(title, mxResources.get('changeUser') + ':'); 532 533 // Makes room after last big buttons 534 btn.style.marginBottom = '16px'; 535 buttons.style.paddingBottom = '18px'; 536 buttons.appendChild(title); 537 538 var usersSelect = document.createElement('select'); 539 usersSelect.style.marginLeft = '4px'; 540 usersSelect.style.width = '140px'; 541 542 for (var i = 0; i < driveUsers.length; i++) 543 { 544 var option = document.createElement('option'); 545 mxUtils.write(option, driveUsers[i].displayName); 546 option.value = i; 547 usersSelect.appendChild(option); 548 //More info (email) about the user in a disabled option 549 option = document.createElement('option'); 550 option.innerHTML = ' '; 551 mxUtils.write(option, '<' + driveUsers[i].email + '>'); 552 option.setAttribute('disabled', 'disabled'); 553 usersSelect.appendChild(option); 554 } 555 556 //Add account option 557 var option = document.createElement('option'); 558 mxUtils.write(option, mxResources.get('addAccount')); 559 option.value = driveUsers.length; 560 usersSelect.appendChild(option); 561 562 mxEvent.addListener(usersSelect, 'change', function() 563 { 564 var userIndex = usersSelect.value; 565 var existingAccount = driveUsers.length != userIndex; 566 567 if (existingAccount) 568 { 569 editorUi.drive.setUser(driveUsers[userIndex]); 570 } 571 572 editorUi.drive.authorize(existingAccount, function() 573 { 574 editorUi.setMode(App.MODE_GOOGLE); 575 editorUi.hideDialog(); 576 editorUi.showSplash(); 577 }, function(resp) 578 { 579 editorUi.handleError(resp, null, function() 580 { 581 editorUi.hideDialog(); 582 editorUi.showSplash(); 583 }); 584 }, true); 585 }); 586 587 buttons.appendChild(usersSelect); 588 } 589 else 590 { 591 addLogout(function() 592 { 593 editorUi.drive.logout(); 594 }); 595 } 596 } 597 else if (editorUi.mode == App.MODE_ONEDRIVE && editorUi.oneDrive != null && !editorUi.oneDrive.noLogout) 598 { 599 addLogout(function() 600 { 601 editorUi.oneDrive.logout(); 602 }); 603 } 604 else if (editorUi.mode == App.MODE_GITHUB && editorUi.gitHub != null) 605 { 606 addLogout(function() 607 { 608 editorUi.gitHub.logout(); 609 editorUi.openLink('https://www.github.com/logout'); 610 }); 611 } 612 else if (editorUi.mode == App.MODE_GITLAB && editorUi.gitLab != null) 613 { 614 addLogout(function() 615 { 616 editorUi.gitLab.logout(); 617 editorUi.openLink(DRAWIO_GITLAB_URL + '/users/sign_out'); 618 }); 619 } 620 else if (editorUi.mode == App.MODE_NOTION && editorUi.notion != null) 621 { 622 addLogout(function() 623 { 624 editorUi.notion.logout(); 625 }); 626 } 627 else if (editorUi.mode == App.MODE_TRELLO && editorUi.trello != null) 628 { 629 if (editorUi.trello.isAuthorized()) 630 { 631 addLogout(function() 632 { 633 editorUi.trello.logout(); 634 }); 635 } 636 } 637 else if (editorUi.mode == App.MODE_DROPBOX && editorUi.dropbox != null) 638 { 639 // NOTE: Dropbox has a logout option in the picker 640 addLogout(function() 641 { 642 editorUi.dropbox.logout(); 643 editorUi.openLink('https://www.dropbox.com/logout'); 644 }); 645 } 646 } 647 648 div.appendChild(buttons); 649 this.container = div; 650}; 651 652/** 653 * Constructs a new embed dialog 654 */ 655var EmbedDialog = function(editorUi, result, timeout, ignoreSize, previewFn, title, tweet, previewTitle, filename) 656{ 657 tweet = (tweet != null) ? tweet : 'Check out the diagram I made using @drawio'; 658 var div = document.createElement('div'); 659 var maxSize = 500000; 660 var maxFbSize = 51200; 661 var maxTwitterSize = 7168; 662 663 // Checks if result is a link 664 var validUrl = /^https?:\/\//.test(result) || /^mailto:\/\//.test(result); 665 666 if (title != null) 667 { 668 mxUtils.write(div, title); 669 } 670 else 671 { 672 mxUtils.write(div, mxResources.get((result.length < maxSize) ? 673 ((validUrl) ? 'link' : 'mainEmbedNotice') : 'preview') + ':'); 674 } 675 mxUtils.br(div); 676 677 var size = document.createElement('div'); 678 size.style.position = 'absolute'; 679 size.style.top = '30px'; 680 size.style.right = '30px'; 681 size.style.color = 'gray'; 682 mxUtils.write(size, editorUi.formatFileSize(result.length)); 683 684 div.appendChild(size); 685 686 // Using DIV for faster rendering 687 var text = document.createElement('textarea'); 688 text.setAttribute('autocomplete', 'off'); 689 text.setAttribute('autocorrect', 'off'); 690 text.setAttribute('autocapitalize', 'off'); 691 text.setAttribute('spellcheck', 'false'); 692 text.style.fontFamily = 'monospace'; 693 text.style.wordBreak = 'break-all'; 694 text.style.marginTop = '10px'; 695 text.style.resize = 'none'; 696 text.style.height = '150px'; 697 text.style.width = '440px'; 698 text.style.border = '1px solid gray'; 699 text.value = mxResources.get('updatingDocument'); 700 div.appendChild(text); 701 mxUtils.br(div); 702 703 this.init = function() 704 { 705 window.setTimeout(function() 706 { 707 if (result.length < maxSize) 708 { 709 text.value = result; 710 text.focus(); 711 712 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 713 { 714 text.select(); 715 } 716 else 717 { 718 document.execCommand('selectAll', false, null); 719 } 720 } 721 else 722 { 723 text.setAttribute('readonly', 'true'); 724 text.value = mxResources.get('tooLargeUseDownload'); 725 } 726 }, 0); 727 }; 728 729 var buttons = document.createElement('div'); 730 buttons.style.position = 'absolute'; 731 buttons.style.bottom = '36px'; 732 buttons.style.right = '32px'; 733 734 var previewBtn = null; 735 736 // Loads forever in IE9 737 if (EmbedDialog.showPreviewOption && (!mxClient.IS_CHROMEAPP || validUrl) && !navigator.standalone && (validUrl || 738 (mxClient.IS_SVG && (document.documentMode == null || document.documentMode > 9)))) 739 { 740 previewBtn = mxUtils.button((previewTitle != null) ? previewTitle : 741 mxResources.get((result.length < maxSize) ? 'preview' : 'openInNewWindow'), function() 742 { 743 var value = (result.length < maxSize) ? text.value : result; 744 745 if (previewFn != null) 746 { 747 previewFn(value); 748 } 749 else 750 { 751 if (validUrl) 752 { 753 try 754 { 755 var win = editorUi.openLink(value); 756 757 if (win != null && (timeout == null || timeout > 0)) 758 { 759 window.setTimeout(mxUtils.bind(this, function() 760 { 761 try 762 { 763 if (win != null && win.location.href != null && 764 win.location.href.substring(0, 8) != value.substring(0, 8)) 765 { 766 win.close(); 767 editorUi.handleError({message: mxResources.get('drawingTooLarge')}); 768 } 769 } 770 catch (e) 771 { 772 // ignore 773 } 774 }), timeout || 500); 775 } 776 } 777 catch (e) 778 { 779 editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')}); 780 } 781 } 782 else 783 { 784 var wnd = window.open(); 785 var doc = (wnd != null) ? wnd.document : null; 786 787 if (doc != null) 788 { 789 doc.writeln('<html><head><title>' + encodeURIComponent(mxResources.get('preview')) + 790 '</title><meta charset="utf-8"></head>' + 791 '<body>' + result + '</body></html>'); 792 doc.close(); 793 } 794 else 795 { 796 editorUi.handleError({message: mxResources.get('errorUpdatingPreview')}); 797 } 798 } 799 } 800 }); 801 802 previewBtn.className = 'geBtn'; 803 buttons.appendChild(previewBtn); 804 } 805 806 if (!validUrl || result.length > 7500) 807 { 808 var downloadBtn = mxUtils.button(mxResources.get('download'), function() 809 { 810 editorUi.hideDialog(); 811 editorUi.saveData((filename != null) ? filename : 'embed.txt', 'txt', result, 'text/plain'); 812 }); 813 814 downloadBtn.className = 'geBtn'; 815 buttons.appendChild(downloadBtn); 816 } 817 818 // Twitter-intent does not allow more characters, must be pasted manually 819 if (validUrl && (!editorUi.isOffline() || mxClient.IS_CHROMEAPP)) 820 { 821 if (result.length < maxFbSize) 822 { 823 var fbBtn = mxUtils.button('', function() 824 { 825 try 826 { 827 var url = 'https://www.facebook.com/sharer.php?p[url]=' + 828 encodeURIComponent(text.value); 829 editorUi.openLink(url); 830 } 831 catch (e) 832 { 833 editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')}); 834 } 835 }); 836 837 var img = document.createElement('img'); 838 img.setAttribute('src', Editor.facebookImage); 839 img.setAttribute('width', '18'); 840 img.setAttribute('height', '18'); 841 img.setAttribute('border', '0'); 842 843 fbBtn.appendChild(img); 844 fbBtn.setAttribute('title', mxResources.get('facebook') + ' (' + 845 editorUi.formatFileSize(maxFbSize) + ' max)'); 846 fbBtn.style.verticalAlign = 'bottom'; 847 fbBtn.style.paddingTop = '4px'; 848 fbBtn.style.minWidth = '46px' 849 fbBtn.className = 'geBtn'; 850 buttons.appendChild(fbBtn); 851 } 852 853 if (result.length < maxTwitterSize) 854 { 855 var tweetBtn = mxUtils.button('', function() 856 { 857 try 858 { 859 var url = 'https://twitter.com/intent/tweet?text=' + 860 encodeURIComponent(tweet) + '&url=' + 861 encodeURIComponent(text.value); 862 editorUi.openLink(url); 863 } 864 catch (e) 865 { 866 editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')}); 867 } 868 }); 869 870 var img = document.createElement('img'); 871 img.setAttribute('src', Editor.tweetImage); 872 img.setAttribute('width', '18'); 873 img.setAttribute('height', '18'); 874 img.setAttribute('border', '0'); 875 img.style.marginBottom = '5px' 876 877 tweetBtn.appendChild(img); 878 tweetBtn.setAttribute('title', mxResources.get('twitter') + ' (' + 879 editorUi.formatFileSize(maxTwitterSize) + ' max)'); 880 tweetBtn.style.verticalAlign = 'bottom'; 881 tweetBtn.style.paddingTop = '4px'; 882 tweetBtn.style.minWidth = '46px' 883 tweetBtn.className = 'geBtn'; 884 buttons.appendChild(tweetBtn); 885 } 886 } 887 888 var closeBtn = mxUtils.button(mxResources.get('close'), function() 889 { 890 editorUi.hideDialog(); 891 }); 892 893 buttons.appendChild(closeBtn); 894 895 var copyBtn = mxUtils.button(mxResources.get('copy'), function() 896 { 897 text.focus(); 898 899 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 900 { 901 text.select(); 902 } 903 else 904 { 905 document.execCommand('selectAll', false, null); 906 } 907 908 document.execCommand('copy'); 909 editorUi.alert(mxResources.get('copiedToClipboard')); 910 }); 911 912 if (result.length < maxSize) 913 { 914 // Does not work in Safari and shows annoying dialog for IE11- 915 if (!mxClient.IS_SF && document.documentMode == null) 916 { 917 buttons.appendChild(copyBtn); 918 copyBtn.className = 'geBtn gePrimaryBtn'; 919 closeBtn.className = 'geBtn'; 920 } 921 else 922 { 923 closeBtn.className = 'geBtn gePrimaryBtn'; 924 } 925 } 926 else 927 { 928 buttons.appendChild(previewBtn); 929 closeBtn.className = 'geBtn'; 930 previewBtn.className = 'geBtn gePrimaryBtn'; 931 } 932 933 div.appendChild(buttons); 934 this.container = div; 935}; 936 937/** 938 * Add embed dialog option. 939 */ 940EmbedDialog.showPreviewOption = true; 941 942/** 943 * Constructs a dialog for embedding the diagram in Google Sites. 944 */ 945var GoogleSitesDialog = function(editorUi, publicUrl) 946{ 947 var div = document.createElement('div'); 948 949 var graph = editorUi.editor.graph; 950 var bounds = graph.getGraphBounds(); 951 var scale = graph.view.scale; 952 var x0 = Math.floor(bounds.x / scale - graph.view.translate.x); 953 var y0 = Math.floor(bounds.y / scale - graph.view.translate.y); 954 955 mxUtils.write(div, mxResources.get('googleGadget') + ':'); 956 mxUtils.br(div); 957 958 var gadgetInput = document.createElement('input'); 959 gadgetInput.setAttribute('type', 'text'); 960 gadgetInput.style.marginBottom = '8px'; 961 gadgetInput.style.marginTop = '2px'; 962 gadgetInput.style.width = '410px'; 963 div.appendChild(gadgetInput); 964 mxUtils.br(div); 965 966 this.init = function() 967 { 968 gadgetInput.focus(); 969 970 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 971 { 972 gadgetInput.select(); 973 } 974 else 975 { 976 document.execCommand('selectAll', false, null); 977 } 978 }; 979 980 mxUtils.write(div, mxResources.get('top') + ':'); 981 var topInput = document.createElement('input'); 982 topInput.setAttribute('type', 'text'); 983 topInput.setAttribute('size', '4'); 984 topInput.style.marginRight = '16px'; 985 topInput.style.marginLeft = '4px'; 986 topInput.value = x0; 987 div.appendChild(topInput); 988 989 mxUtils.write(div, mxResources.get('height') + ':'); 990 var heightInput = document.createElement('input'); 991 heightInput.setAttribute('type', 'text'); 992 heightInput.setAttribute('size', '4'); 993 heightInput.style.marginLeft = '4px'; 994 heightInput.value = Math.ceil(bounds.height / scale); 995 div.appendChild(heightInput); 996 mxUtils.br(div); 997 998 var hr = document.createElement('hr'); 999 hr.setAttribute('size', '1'); 1000 hr.style.marginBottom = '16px'; 1001 hr.style.marginTop = '16px'; 1002 div.appendChild(hr); 1003 1004 mxUtils.write(div, mxResources.get('publicDiagramUrl') + ':'); 1005 mxUtils.br(div); 1006 1007 var urlInput = document.createElement('input'); 1008 urlInput.setAttribute('type', 'text'); 1009 urlInput.setAttribute('size', '28'); 1010 urlInput.style.marginBottom = '8px'; 1011 urlInput.style.marginTop = '2px'; 1012 urlInput.style.width = '410px'; 1013 urlInput.value = publicUrl || ''; 1014 div.appendChild(urlInput); 1015 mxUtils.br(div); 1016 1017 mxUtils.write(div, mxResources.get('borderWidth') + ':'); 1018 var borderInput = document.createElement('input'); 1019 borderInput.setAttribute('type', 'text'); 1020 borderInput.setAttribute('size', '3'); 1021 borderInput.style.marginBottom = '8px'; 1022 borderInput.style.marginLeft = '4px'; 1023 borderInput.value = '0'; 1024 div.appendChild(borderInput); 1025 mxUtils.br(div); 1026 1027 var panCheckBox = document.createElement('input'); 1028 panCheckBox.setAttribute('type', 'checkbox'); 1029 panCheckBox.setAttribute('checked', 'checked'); 1030 panCheckBox.defaultChecked = true; 1031 panCheckBox.style.marginLeft = '16px'; 1032 div.appendChild(panCheckBox); 1033 mxUtils.write(div, mxResources.get('pan') + ' '); 1034 1035 var zoomCheckBox = document.createElement('input'); 1036 zoomCheckBox.setAttribute('type', 'checkbox'); 1037 zoomCheckBox.setAttribute('checked', 'checked'); 1038 zoomCheckBox.defaultChecked = true; 1039 zoomCheckBox.style.marginLeft = '8px'; 1040 div.appendChild(zoomCheckBox); 1041 mxUtils.write(div, mxResources.get('zoom') + ' '); 1042 1043 var editCheckBox = document.createElement('input'); 1044 editCheckBox.setAttribute('type', 'checkbox'); 1045 editCheckBox.style.marginLeft = '8px'; 1046 editCheckBox.setAttribute('title', window.location.href); 1047 div.appendChild(editCheckBox); 1048 mxUtils.write(div, mxResources.get('edit') + ' '); 1049 1050 var editBlankCheckBox = document.createElement('input'); 1051 editBlankCheckBox.setAttribute('type', 'checkbox'); 1052 editBlankCheckBox.style.marginLeft = '8px'; 1053 div.appendChild(editBlankCheckBox); 1054 mxUtils.write(div, mxResources.get('asNew') + ' '); 1055 mxUtils.br(div); 1056 1057 var resizeCheckBox = document.createElement('input'); 1058 resizeCheckBox.setAttribute('type', 'checkbox'); 1059 resizeCheckBox.setAttribute('checked', 'checked'); 1060 resizeCheckBox.defaultChecked = true; 1061 resizeCheckBox.style.marginLeft = '16px'; 1062 div.appendChild(resizeCheckBox); 1063 mxUtils.write(div, mxResources.get('resize') + ' '); 1064 1065 var fitCheckBox = document.createElement('input'); 1066 fitCheckBox.setAttribute('type', 'checkbox'); 1067 fitCheckBox.style.marginLeft = '8px'; 1068 div.appendChild(fitCheckBox); 1069 mxUtils.write(div, mxResources.get('fit') + ' '); 1070 1071 var embedCheckBox = document.createElement('input'); 1072 embedCheckBox.setAttribute('type', 'checkbox'); 1073 embedCheckBox.style.marginLeft = '8px'; 1074 div.appendChild(embedCheckBox); 1075 mxUtils.write(div, mxResources.get('embed') + ' '); 1076 1077 var node = null; 1078 var s = editorUi.getBasenames().join(';'); 1079 var file = editorUi.getCurrentFile(); 1080 1081 function update() 1082 { 1083 var title = (file != null && file.getTitle() != null) ? file.getTitle() : this.defaultFilename; 1084 1085 if (embedCheckBox.checked && urlInput.value != '') 1086 { 1087 var encUrl = encodeURIComponent(mxUtils.htmlEntities(urlInput.value)); 1088 var gurl = 'https://www.draw.io/gadget.xml?type=4&diagram=' + encUrl; 1089 1090 if (title != null) 1091 { 1092 gurl += '&title=' + encodeURIComponent(title); 1093 } 1094 1095 if (s.length > 0) 1096 { 1097 gurl += '&s=' + s; 1098 } 1099 1100 if (borderInput.value != '' && borderInput.value != '0') 1101 { 1102 gurl += '&border=' + borderInput.value; 1103 } 1104 1105 if (heightInput.value != '') 1106 { 1107 gurl += '&height=' + heightInput.value; 1108 } 1109 1110 gurl += '&pan=' + ((panCheckBox.checked) ? '1': '0'); 1111 gurl += '&zoom=' + ((zoomCheckBox.checked) ? '1': '0'); 1112 gurl += '&fit=' + ((fitCheckBox.checked) ? '1': '0'); 1113 gurl += '&resize=' + ((resizeCheckBox.checked) ? '1': '0'); 1114 gurl += '&x0=' + Number(topInput.value); 1115 gurl += '&y0=' + y0; 1116 1117 if (graph.mathEnabled) 1118 { 1119 gurl += '&math=1'; 1120 } 1121 1122 if (editBlankCheckBox.checked) 1123 { 1124 gurl += '&edit=_blank'; 1125 } 1126 else if (editCheckBox.checked) 1127 { 1128 gurl += '&edit=' + encodeURIComponent(mxUtils.htmlEntities(window.location.href)); 1129 } 1130 1131 gadgetInput.value = gurl; 1132 } 1133 else if (file.constructor == DriveFile || file.constructor == DropboxFile) 1134 { 1135 var gurl = 'https://www.draw.io/gadget.xml?embed=0&diagram='; 1136 1137 if (urlInput.value != '') 1138 { 1139 gurl += encodeURIComponent(mxUtils.htmlEntities(urlInput.value)) + '&type=3'; 1140 } 1141 else 1142 { 1143 gurl += file.getHash().substring(1); 1144 1145 if (file.constructor == DropboxFile) 1146 { 1147 gurl += '&type=2'; 1148 } 1149 else 1150 { 1151 gurl += '&type=1'; 1152 } 1153 } 1154 1155 if (title != null) 1156 { 1157 gurl += '&title=' + encodeURIComponent(title); 1158 } 1159 1160 if (heightInput.value != '') 1161 { 1162 var h = parseInt(heightInput.value) + parseInt(topInput.value); 1163 gurl += '&height=' + h; 1164 } 1165 1166 gadgetInput.value = gurl; 1167 } 1168 else 1169 { 1170 gadgetInput.value = ''; 1171 } 1172 }; 1173 1174 mxEvent.addListener(panCheckBox, 'change', update); 1175 mxEvent.addListener(zoomCheckBox, 'change', update); 1176 mxEvent.addListener(resizeCheckBox, 'change', update); 1177 mxEvent.addListener(fitCheckBox, 'change', update); 1178 mxEvent.addListener(editCheckBox, 'change', update); 1179 mxEvent.addListener(editBlankCheckBox, 'change', update); 1180 mxEvent.addListener(embedCheckBox, 'change', update); 1181 mxEvent.addListener(heightInput, 'change', update); 1182 mxEvent.addListener(topInput, 'change', update); 1183 mxEvent.addListener(borderInput, 'change', update); 1184 mxEvent.addListener(urlInput, 'change', update); 1185 update(); 1186 1187 mxEvent.addListener(gadgetInput, 'click', function() 1188 { 1189 gadgetInput.focus(); 1190 1191 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 1192 { 1193 gadgetInput.select(); 1194 } 1195 else 1196 { 1197 document.execCommand('selectAll', false, null); 1198 } 1199 }); 1200 1201 var buttons = document.createElement('div'); 1202 buttons.style.paddingTop = '12px'; 1203 buttons.style.textAlign = 'right'; 1204 1205 var closeBtn = mxUtils.button(mxResources.get('close'), function() 1206 { 1207 editorUi.hideDialog(); 1208 }); 1209 closeBtn.className = 'geBtn gePrimaryBtn'; 1210 buttons.appendChild(closeBtn); 1211 1212 div.appendChild(buttons); 1213 1214 this.container = div; 1215}; 1216 1217/** 1218 * Constructs a new parse dialog. 1219 */ 1220var CreateGraphDialog = function(editorUi, title, type) 1221{ 1222 var div = document.createElement('div'); 1223 div.style.textAlign = 'right'; 1224 1225 this.init = function() 1226 { 1227 var container = document.createElement('div'); 1228 container.style.position = 'relative'; 1229 container.style.border = '1px solid gray'; 1230 container.style.width = '100%'; 1231 container.style.height = '360px'; 1232 container.style.overflow = 'hidden'; 1233 container.style.marginBottom = '16px'; 1234 mxEvent.disableContextMenu(container); 1235 div.appendChild(container); 1236 1237 var graph = new Graph(container); 1238 1239 graph.setCellsCloneable(true); 1240 graph.setPanning(true); 1241 graph.setAllowDanglingEdges(false); 1242 graph.connectionHandler.select = false; 1243 graph.view.setTranslate(20, 20); 1244 graph.border = 20; 1245 graph.panningHandler.useLeftButtonForPanning = true; 1246 1247 var vertexStyle = 'rounded=1;'; 1248 var edgeStyle = 'curved=1;'; 1249 var startStyle = 'ellipse'; 1250 1251 // FIXME: Does not work in iPad 1252 var mxCellRendererInstallCellOverlayListeners = mxCellRenderer.prototype.installCellOverlayListeners; 1253 graph.cellRenderer.installCellOverlayListeners = function(state, overlay, shape) 1254 { 1255 mxCellRenderer.prototype.installCellOverlayListeners.apply(this, arguments); 1256 1257 mxEvent.addListener(shape.node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', function (evt) 1258 { 1259 overlay.fireEvent(new mxEventObject('pointerdown', 'event', evt, 'state', state)); 1260 }); 1261 1262 if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) 1263 { 1264 mxEvent.addListener(shape.node, 'touchstart', function (evt) 1265 { 1266 overlay.fireEvent(new mxEventObject('pointerdown', 'event', evt, 'state', state)); 1267 }); 1268 } 1269 }; 1270 1271 graph.getAllConnectionConstraints = function() 1272 { 1273 return null; 1274 }; 1275 1276 // Keeps highlight behind overlays 1277 graph.connectionHandler.marker.highlight.keepOnTop = false; 1278 1279 graph.connectionHandler.createEdgeState = function(me) 1280 { 1281 var edge = graph.createEdge(null, null, null, null, null, edgeStyle); 1282 1283 return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge)); 1284 }; 1285 1286 // Gets the default parent for inserting new cells. This 1287 // is normally the first child of the root (ie. layer 0). 1288 var parent = graph.getDefaultParent(); 1289 1290 var addOverlay = mxUtils.bind(this, function(cell) 1291 { 1292 // Creates a new overlay with an image and a tooltip 1293 var overlay = new mxCellOverlay(this.connectImage, 'Add outgoing'); 1294 overlay.cursor = 'hand'; 1295 1296 // Installs a handler for clicks on the overlay 1297 overlay.addListener(mxEvent.CLICK, function(sender, evt2) 1298 { 1299 // TODO: Add menu for picking next shape 1300 graph.connectionHandler.reset(); 1301 graph.clearSelection(); 1302 var geo = graph.getCellGeometry(cell); 1303 1304 var v2; 1305 1306 executeLayout(function() 1307 { 1308 v2 = graph.insertVertex(parent, null, 'Entry', geo.x, geo.y, 80, 30, vertexStyle); 1309 addOverlay(v2); 1310 graph.view.refresh(v2); 1311 var e1 = graph.insertEdge(parent, null, '', cell, v2, edgeStyle); 1312 }, function() 1313 { 1314 graph.scrollCellToVisible(v2); 1315 }); 1316 }); 1317 1318 // FIXME: Does not work in iPad (inserts loop) 1319 overlay.addListener('pointerdown', function(sender, eo) 1320 { 1321 var evt2 = eo.getProperty('event'); 1322 var state = eo.getProperty('state'); 1323 1324 graph.popupMenuHandler.hideMenu(); 1325 graph.stopEditing(false); 1326 1327 var pt = mxUtils.convertPoint(graph.container, 1328 mxEvent.getClientX(evt2), mxEvent.getClientY(evt2)); 1329 graph.connectionHandler.start(state, pt.x, pt.y); 1330 graph.isMouseDown = true; 1331 graph.isMouseTrigger = mxEvent.isMouseEvent(evt2); 1332 mxEvent.consume(evt2); 1333 }); 1334 1335 // Sets the overlay for the cell in the graph 1336 graph.addCellOverlay(cell, overlay); 1337 }); 1338 1339 // Adds cells to the model in a single step 1340 graph.getModel().beginUpdate(); 1341 var v1; 1342 try 1343 { 1344 v1 = graph.insertVertex(parent, null, 'Start', 0, 0, 80, 30, startStyle); 1345 addOverlay(v1); 1346 } 1347 finally 1348 { 1349 // Updates the display 1350 graph.getModel().endUpdate(); 1351 } 1352 1353 var layout; 1354 1355 if (type == 'horizontalTree') 1356 { 1357 layout = new mxCompactTreeLayout(graph); 1358 layout.edgeRouting = false; 1359 layout.levelDistance = 30; 1360 edgeStyle = 'edgeStyle=elbowEdgeStyle;elbow=horizontal;'; 1361 } 1362 else if (type == 'verticalTree') 1363 { 1364 layout = new mxCompactTreeLayout(graph, false); 1365 layout.edgeRouting = false; 1366 layout.levelDistance = 30; 1367 edgeStyle = 'edgeStyle=elbowEdgeStyle;elbow=vertical;'; 1368 } 1369 else if (type == 'radialTree') 1370 { 1371 layout = new mxRadialTreeLayout(graph, false); 1372 layout.edgeRouting = false; 1373 layout.levelDistance = 80; 1374 } 1375 else if (type == 'verticalFlow') 1376 { 1377 layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_NORTH); 1378 } 1379 else if (type == 'horizontalFlow') 1380 { 1381 layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST); 1382 } 1383 else if (type == 'organic') 1384 { 1385 layout = new mxFastOrganicLayout(graph, false); 1386 layout.forceConstant = 80; 1387 } 1388 else if (type == 'circle') 1389 { 1390 layout = new mxCircleLayout(graph); 1391 } 1392 1393 if (layout != null) 1394 { 1395 var executeLayout = function(change, post) 1396 { 1397 graph.getModel().beginUpdate(); 1398 try 1399 { 1400 if (change != null) 1401 { 1402 change(); 1403 } 1404 1405 layout.execute(graph.getDefaultParent(), v1); 1406 } 1407 catch (e) 1408 { 1409 throw e; 1410 } 1411 finally 1412 { 1413 // New API for animating graph layout results asynchronously 1414 var morph = new mxMorphing(graph); 1415 morph.addListener(mxEvent.DONE, mxUtils.bind(this, function() 1416 { 1417 graph.getModel().endUpdate(); 1418 1419 if (post != null) 1420 { 1421 post(); 1422 } 1423 })); 1424 1425 morph.startAnimation(); 1426 } 1427 }; 1428 1429 var edgeHandleConnect = mxEdgeHandler.prototype.connect; 1430 mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me) 1431 { 1432 edgeHandleConnect.apply(this, arguments); 1433 executeLayout(); 1434 }; 1435 1436 graph.resizeCell = function() 1437 { 1438 mxGraph.prototype.resizeCell.apply(this, arguments); 1439 1440 executeLayout(); 1441 }; 1442 1443 graph.connectionHandler.addListener(mxEvent.CONNECT, function() 1444 { 1445 executeLayout(); 1446 }); 1447 } 1448 1449 var cancelBtn = mxUtils.button(mxResources.get('close'), function() 1450 { 1451 editorUi.confirm(mxResources.get('areYouSure'), function() 1452 { 1453 if (container.parentNode != null) 1454 { 1455 graph.destroy(); 1456 container.parentNode.removeChild(container); 1457 } 1458 1459 editorUi.hideDialog(); 1460 }); 1461 }) 1462 1463 cancelBtn.className = 'geBtn'; 1464 1465 if (editorUi.editor.cancelFirst) 1466 { 1467 div.appendChild(cancelBtn); 1468 } 1469 1470 var okBtn = mxUtils.button(mxResources.get('insert'), function(evt) 1471 { 1472 graph.clearCellOverlays(); 1473 1474 var cells = graph.getModel().getChildren(graph.getDefaultParent()); 1475 var pt = (mxEvent.isAltDown(evt)) ? 1476 editorUi.editor.graph.getFreeInsertPoint() : 1477 editorUi.editor.graph.getCenterInsertPoint( 1478 graph.getBoundingBoxFromGeometry(cells, true)); 1479 cells = editorUi.editor.graph.importCells(cells, pt.x, pt.y); 1480 var view = editorUi.editor.graph.view; 1481 var temp = view.getBounds(cells); 1482 temp.x -= view.translate.x; 1483 temp.y -= view.translate.y; 1484 editorUi.editor.graph.scrollRectToVisible(temp); 1485 editorUi.editor.graph.setSelectionCells(cells); 1486 1487 if (container.parentNode != null) 1488 { 1489 graph.destroy(); 1490 container.parentNode.removeChild(container); 1491 } 1492 1493 editorUi.hideDialog(); 1494 }); 1495 1496 div.appendChild(okBtn); 1497 okBtn.className = 'geBtn gePrimaryBtn'; 1498 1499 if (!editorUi.editor.cancelFirst) 1500 { 1501 div.appendChild(cancelBtn); 1502 } 1503 }; 1504 1505 this.container = div; 1506}; 1507 1508/** 1509 * 1510 */ 1511CreateGraphDialog.prototype.connectImage = new mxImage((mxClient.IS_SVG) ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjQ3OTk0QjMyRDcyMTFFNThGQThGNDVBMjNBMjFDMzkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjQ3OTk0QjQyRDcyMTFFNThGQThGNDVBMjNBMjFDMzkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyRjA0N0I2MjJENzExMUU1OEZBOEY0NUEyM0EyMUMzOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNDc5OTRCMjJENzIxMUU1OEZBOEY0NUEyM0EyMUMzOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjIf+MgAAATlSURBVHjanFZraFxFFD735u4ru3ls0yZG26ShgmJoKK1J2vhIYzBgRdtIURHyw1hQUH9IxIgI2h8iCEUF/1RRlNQYCsYfCTHVhiTtNolpZCEStqSC22xIsrs1bDfu7t37Gs/cO3Ozxs1DBw73zpk555vzmHNGgJ0NYatFgmNLYUHYUoHASMz5ijmgVLmxgfKCUiBxC4ACJAeSG8nb1dVVOTc3dyoSibwWDofPBIPBJzo7O8vpGtvjpDICGztxkciECpF2LS0tvZtOpwNkk5FKpcYXFxffwL1+JuPgllPj8nk1F6RoaGjoKCqZ5ApljZDZO4SMRA0SuG2QUJIQRV8HxMOM9vf3H0ZZH9Nhg20MMl2QkFwjIyNHWlpahtADnuUMwLcRHX5aNSBjCJYEsSSLUeLEbhGe3ytCmQtA1/XY+Pj46dbW1iDuyCJp9BC5ycBj4hoeHq5ra2sbw0Xn1ZgBZ+dVkA1Lc+6p0Ck2p0QS4Ox9EhwpEylYcmBg4LH29vYQLilIOt0u5FhDfevNZDI/u93uw6PLOrwTUtjxrbPYbhD42WgMrF8JmR894ICmCgnQjVe8Xu8pXEkzMJKbuo5oNPomBbm1ZsD7s2kwFA1JZ6QBUXWT1nmGNc/qoMgavDcrQzxjQGFh4aOYIJ0sFAXcEtui4uLiVjr5KpSBVFYDDZVrWUaKRRWSAYeK0fmKykgDXbVoNaPChRuyqdDv97czL5nXxQbq6empQmsaklkDBiNpSwFVrmr2P6UyicD5piI4f8wHh0oEm8/p4h8pyGiEWvVQd3e3nxtjAzU1NR2jP7NRBWQ8GbdEzzJAmc0V3RR4cI8Dvmwuhc8fKUFA0d6/ltHg5p+Kuaejo6OeY0jcNJ/PV00ZS0nFUoZRvvFS1bZFsKHCCQ2Pl8H0chY+C96B6ZUsrCQ1qKtwQVFRURW/QhIXMAzDPAZ6BgOr8tTa8dDxCmiYGApaJbJMxSzV+brE8pdgWkcpY5dbMF1AR9XH8/xu2ilef48bvn92n82ZwHh+8ssqTEXS9p7dHisiiURikd8PbpExNTU1UVNTA3V3Y7lC16n0gpB/NwpNcZjfa7dScC4Qh0kOQCwnlEgi3F/hMVl9fX0zvKrzSk2lfXjRhj0eT/2rvWG4+Pta3oJY7XfC3hInXAv/ldeFLx8shQ+eqQL0UAAz7ylkpej5eNZRVBWL6BU6ef14OYiY1oqyTtmsavr/5koaRucT1pzx+ZpL1+GV5nLutksUgIcmtwTRiuuVZXnU5XId7A2swJkfFsymRWC91hHg1Viw6x23+7vn9sPJ+j20BE1hCXqSWaNSQ8ScbknRZWxub1PGCw/fBV+c3AeijlUbY5bBjEqr9GuYZP4jP41WudGSC6erTRCqdGZm5i1WvXWeDHnbBCZGc2Nj4wBl/hZOwrmBBfgmlID1HmGJutHaF+tKoevp/XCgstDkjo2NtWKLuc6AVN4mNjY+s1XQxoenOoFuDPHGtnRbJj9ej5GvL0dI7+giuRyMk1giazc+DP6vgUDgOJVlOv7R+PJ12QIeL6SyeDz+Kfp8ZrNWjgDTsVjsQ7qXyTjztXJhm9ePxFLfMTg4eG9tbe1RTP9KFFYQfHliYmIS69kCC7jKYmKwxxD5P88tkVkqbPPcIps9t4T/+HjcuJ/s5BFJgf4WYABCtxGuxIZ90gAAAABJRU5ErkJggg==' : 1512 IMAGE_PATH + '/handle-connect.png', 26, 26); 1513 1514/** 1515 * Constructs a new parse dialog. 1516 */ 1517var BackgroundImageDialog = function(editorUi, applyFn, img) 1518{ 1519 var div = document.createElement('div'); 1520 div.style.whiteSpace = 'nowrap'; 1521 1522 var h3 = document.createElement('h2'); 1523 mxUtils.write(h3, mxResources.get('backgroundImage')); 1524 h3.style.marginTop = '0px'; 1525 div.appendChild(h3); 1526 1527 var isPageLink = img != null && img.originalSrc != null; 1528 var pageFound = false; 1529 1530 var urlRadio = document.createElement('input'); 1531 urlRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 1532 urlRadio.setAttribute('value', 'url'); 1533 urlRadio.setAttribute('type', 'radio'); 1534 urlRadio.setAttribute('name', 'geBackgroundImageDialogOption'); 1535 1536 var pageRadio = document.createElement('input'); 1537 pageRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 1538 pageRadio.setAttribute('value', 'url'); 1539 pageRadio.setAttribute('type', 'radio'); 1540 pageRadio.setAttribute('name', 'geBackgroundImageDialogOption'); 1541 1542 var urlInput = document.createElement('input'); 1543 urlInput.setAttribute('type', 'text'); 1544 urlInput.style.marginBottom = '8px'; 1545 urlInput.style.width = '320px'; 1546 urlInput.value = (isPageLink || img == null) ? '' : img.src; 1547 1548 var pageSelect = document.createElement('select'); 1549 pageSelect.style.width = '320px'; 1550 1551 if (editorUi.pages != null) 1552 { 1553 for (var i = 0; i < editorUi.pages.length; i++) 1554 { 1555 var pageOption = document.createElement('option'); 1556 mxUtils.write(pageOption, editorUi.pages[i].getName() || 1557 mxResources.get('pageWithNumber', [i + 1])); 1558 pageOption.setAttribute('value', 'data:page/id,' + 1559 editorUi.pages[i].getId()); 1560 1561 if (editorUi.pages[i] == editorUi.currentPage) 1562 { 1563 pageOption.setAttribute('disabled', 'disabled'); 1564 } 1565 1566 if (img != null && img.originalSrc == pageOption.getAttribute('value')) 1567 { 1568 pageOption.setAttribute('selected', 'selected'); 1569 pageFound = true; 1570 } 1571 1572 pageSelect.appendChild(pageOption); 1573 } 1574 } 1575 1576 if (!isPageLink && (editorUi.pages == null || editorUi.pages.length == 1)) 1577 { 1578 urlRadio.style.display = 'none'; 1579 pageRadio.style.display = 'none'; 1580 pageSelect.style.display = 'none'; 1581 } 1582 1583 var resetting = false; 1584 var ignoreEvt = false; 1585 1586 var urlChanged = function(evt, done) 1587 { 1588 // Skips blur event if called from apply button 1589 if (!resetting && (evt == null || !ignoreEvt)) 1590 { 1591 if (pageRadio.checked) 1592 { 1593 if (done != null) 1594 { 1595 done(pageSelect.value); 1596 } 1597 } 1598 else if (urlInput.value != '' && !editorUi.isOffline()) 1599 { 1600 urlInput.value = mxUtils.trim(urlInput.value); 1601 1602 editorUi.loadImage(urlInput.value, function(img) 1603 { 1604 widthInput.value = img.width; 1605 heightInput.value = img.height; 1606 1607 if (done != null) 1608 { 1609 done(urlInput.value); 1610 } 1611 }, function() 1612 { 1613 editorUi.showError(mxResources.get('error'), mxResources.get('fileNotFound'), mxResources.get('ok')); 1614 widthInput.value = ''; 1615 heightInput.value = ''; 1616 1617 if (done != null) 1618 { 1619 done(null); 1620 } 1621 }); 1622 } 1623 else 1624 { 1625 widthInput.value = ''; 1626 heightInput.value = ''; 1627 1628 if (done != null) 1629 { 1630 done(''); 1631 } 1632 } 1633 } 1634 }; 1635 1636 this.init = function() 1637 { 1638 if (isPageLink) 1639 { 1640 pageSelect.focus(); 1641 } 1642 else 1643 { 1644 urlInput.focus(); 1645 } 1646 1647 mxEvent.addListener(pageSelect, 'focus', function() 1648 { 1649 urlRadio.removeAttribute('checked'); 1650 pageRadio.setAttribute('checked', 'checked'); 1651 pageRadio.checked = true; 1652 }); 1653 1654 mxEvent.addListener(urlInput, 'focus', function() 1655 { 1656 pageRadio.removeAttribute('checked'); 1657 urlRadio.setAttribute('checked', 'checked'); 1658 urlRadio.checked = true; 1659 }); 1660 1661 // Installs drag and drop handler for local images and links 1662 if (Graph.fileSupport) 1663 { 1664 urlInput.setAttribute('placeholder', mxResources.get('dragImagesHere')); 1665 1666 // Setup the dnd listeners 1667 var dlg = div.parentNode; 1668 var graph = editorUi.editor.graph; 1669 var dropElt = null; 1670 1671 mxEvent.addListener(dlg, 'dragleave', function(evt) 1672 { 1673 if (dropElt != null) 1674 { 1675 dropElt.parentNode.removeChild(dropElt); 1676 dropElt = null; 1677 } 1678 1679 evt.stopPropagation(); 1680 evt.preventDefault(); 1681 }); 1682 1683 mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt) 1684 { 1685 // IE 10 does not implement pointer-events so it can't have a drop highlight 1686 if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10)) 1687 { 1688 dropElt = editorUi.highlightElement(dlg); 1689 } 1690 1691 evt.stopPropagation(); 1692 evt.preventDefault(); 1693 })); 1694 1695 mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt) 1696 { 1697 if (dropElt != null) 1698 { 1699 dropElt.parentNode.removeChild(dropElt); 1700 dropElt = null; 1701 } 1702 1703 if (evt.dataTransfer.files.length > 0) 1704 { 1705 editorUi.importFiles(evt.dataTransfer.files, 0, 0, editorUi.maxBackgroundSize, function(data, mimeType, x, y, w, h) 1706 { 1707 urlInput.value = data; 1708 urlChanged(); 1709 }, function() 1710 { 1711 // No post processing 1712 }, function(file) 1713 { 1714 // Handles only images 1715 return file.type.substring(0, 6) == 'image/'; 1716 }, function(queue) 1717 { 1718 // Invokes elements of queue in order 1719 for (var i = 0; i < queue.length; i++) 1720 { 1721 queue[i](); 1722 } 1723 }, true, editorUi.maxBackgroundBytes, editorUi.maxBackgroundBytes, true); 1724 } 1725 else if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0) 1726 { 1727 var uri = evt.dataTransfer.getData('text/uri-list'); 1728 1729 if ((/\.(gif|jpg|jpeg|tiff|png|svg)$/i).test(uri)) 1730 { 1731 urlInput.value = decodeURIComponent(uri); 1732 urlChanged(); 1733 } 1734 } 1735 1736 evt.stopPropagation(); 1737 evt.preventDefault(); 1738 }), false); 1739 } 1740 }; 1741 1742 div.appendChild(urlRadio); 1743 div.appendChild(urlInput); 1744 mxUtils.br(div); 1745 1746 var span = document.createElement('span'); 1747 span.style.marginLeft = '30px'; 1748 mxUtils.write(span, mxResources.get('width') + ':'); 1749 div.appendChild(span); 1750 1751 var widthInput = document.createElement('input'); 1752 widthInput.setAttribute('type', 'text'); 1753 widthInput.style.width = '60px'; 1754 widthInput.style.marginLeft = '8px'; 1755 widthInput.style.marginRight = '16px'; 1756 widthInput.value = (img != null && !isPageLink) ? img.width : ''; 1757 1758 div.appendChild(widthInput); 1759 1760 mxUtils.write(div, mxResources.get('height') + ':'); 1761 1762 var heightInput = document.createElement('input'); 1763 heightInput.setAttribute('type', 'text'); 1764 heightInput.style.width = '60px'; 1765 heightInput.style.marginLeft = '8px'; 1766 heightInput.style.marginRight = '16px'; 1767 heightInput.value = (img != null && !isPageLink) ? img.height : ''; 1768 1769 div.appendChild(heightInput); 1770 mxUtils.br(div); 1771 mxUtils.br(div); 1772 1773 mxEvent.addListener(urlInput, 'change', urlChanged); 1774 1775 ImageDialog.filePicked = function(data) 1776 { 1777 if (data.action == google.picker.Action.PICKED) 1778 { 1779 if (data.docs[0].thumbnails != null) 1780 { 1781 var thumb = data.docs[0].thumbnails[data.docs[0].thumbnails.length - 1]; 1782 1783 if (thumb != null) 1784 { 1785 urlInput.value = thumb.url; 1786 urlChanged(); 1787 } 1788 } 1789 } 1790 1791 urlInput.focus(); 1792 }; 1793 1794 div.appendChild(pageRadio); 1795 div.appendChild(pageSelect); 1796 mxUtils.br(div); 1797 1798 if (isPageLink) 1799 { 1800 pageRadio.setAttribute('checked', 'checked'); 1801 pageRadio.checked = true; 1802 } 1803 else 1804 { 1805 urlRadio.setAttribute('checked', 'checked'); 1806 urlRadio.checked = true; 1807 } 1808 1809 if (!pageFound && pageRadio.checked) 1810 { 1811 var notFoundOption = document.createElement('option'); 1812 mxUtils.write(notFoundOption, mxResources.get('pageNotFound')); 1813 notFoundOption.setAttribute('disabled', 'disabled'); 1814 notFoundOption.setAttribute('selected', 'selected'); 1815 notFoundOption.setAttribute('value', 'pageNotFound'); 1816 pageSelect.appendChild(notFoundOption); 1817 1818 mxEvent.addListener(pageSelect, 'change', function() 1819 { 1820 if (notFoundOption.parentNode != null && !notFoundOption.selected) 1821 { 1822 notFoundOption.parentNode.removeChild(notFoundOption); 1823 } 1824 }); 1825 } 1826 1827 var btns = document.createElement('div'); 1828 btns.style.marginTop = '30px'; 1829 btns.style.textAlign = 'right'; 1830 1831 var resetBtn = mxUtils.button(mxResources.get('reset'), function() 1832 { 1833 urlInput.value = ''; 1834 widthInput.value = ''; 1835 heightInput.value = ''; 1836 urlRadio.checked = true; 1837 resetting = false; 1838 }); 1839 mxEvent.addGestureListeners(resetBtn, function() 1840 { 1841 // Blocks processing a image URL while clicking reset 1842 resetting = true; 1843 }); 1844 resetBtn.className = 'geBtn'; 1845 resetBtn.width = '100'; 1846 btns.appendChild(resetBtn); 1847 1848 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 1849 { 1850 resetting = true; 1851 editorUi.hideDialog(); 1852 }); 1853 1854 cancelBtn.className = 'geBtn'; 1855 1856 if (editorUi.editor.cancelFirst) 1857 { 1858 btns.appendChild(cancelBtn); 1859 } 1860 1861 applyBtn = mxUtils.button(mxResources.get('apply'), function() 1862 { 1863 editorUi.hideDialog(); 1864 1865 urlChanged(null, function(url) 1866 { 1867 applyFn((url != '' && url != null) ? new mxImage(url, 1868 widthInput.value, heightInput.value) : null, 1869 url == null); 1870 }); 1871 }); 1872 1873 mxEvent.addGestureListeners(applyBtn, function() 1874 { 1875 ignoreEvt = true; 1876 }); 1877 1878 applyBtn.className = 'geBtn gePrimaryBtn'; 1879 btns.appendChild(applyBtn); 1880 1881 if (!editorUi.editor.cancelFirst) 1882 { 1883 btns.appendChild(cancelBtn); 1884 } 1885 1886 div.appendChild(btns); 1887 1888 this.container = div; 1889}; 1890 1891/** 1892 * Constructs a new parse dialog. 1893 */ 1894var ParseDialog = function(editorUi, title, defaultType) 1895{ 1896 var plantUmlExample = '@startuml\nskinparam shadowing false\nAlice -> Bob: Authentication Request\nBob --> Alice: Authentication Response\n\nAlice -> Bob: Another authentication Request\nAlice <-- Bob: Another authentication Response\n@enduml'; 1897 var insertPoint = editorUi.editor.graph.getFreeInsertPoint(); 1898 1899 function parse(text, type, evt) 1900 { 1901 var lines = text.split('\n'); 1902 1903 if (type == 'plantUmlPng' || type == 'plantUmlSvg' || type == 'plantUmlTxt') 1904 { 1905 if (editorUi.spinner.spin(document.body, mxResources.get('inserting'))) 1906 { 1907 var graph = editorUi.editor.graph; 1908 var format = (type == 'plantUmlTxt') ? 'txt' : 1909 ((type == 'plantUmlPng') ? 'png' : 'svg'); 1910 1911 function insertPlantUmlImage(text, format, data, w, h) 1912 { 1913 insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : graph.getCenterInsertPoint(new mxRectangle(0, 0, w, h)); 1914 var cell = null; 1915 1916 graph.getModel().beginUpdate(); 1917 try 1918 { 1919 cell = (format == 'txt') ? 1920 editorUi.insertAsPreText(data, insertPoint.x, insertPoint.y) : 1921 graph.insertVertex(null, null, null, insertPoint.x, insertPoint.y, 1922 w, h, 'shape=image;noLabel=1;verticalAlign=top;aspect=fixed;imageAspect=0;' + 1923 'image=' + editorUi.convertDataUri(data) + ';') 1924 graph.setAttributeForCell(cell, 'plantUmlData', 1925 JSON.stringify({data: text, format: format}, 1926 null, 2)); 1927 } 1928 finally 1929 { 1930 graph.getModel().endUpdate(); 1931 } 1932 1933 if (cell != null) 1934 { 1935 graph.setSelectionCell(cell); 1936 graph.scrollCellToVisible(cell); 1937 } 1938 }; 1939 1940 // Hardcoded response for default settings 1941 if (text == plantUmlExample && format == 'svg') 1942 { 1943 window.setTimeout(function() 1944 { 1945 editorUi.spinner.stop(); 1946 insertPlantUmlImage(text, format, 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U2NyaXB0VHlwZT0iYXBwbGljYXRpb24vZWNtYXNjcmlwdCIgY29udGVudFN0eWxlVHlwZT0idGV4dC9jc3MiIGhlaWdodD0iMjEycHgiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiIHN0eWxlPSJ3aWR0aDoyOTVweDtoZWlnaHQ6MjEycHg7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyOTUgMjEyIiB3aWR0aD0iMjk1cHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48bGluZSBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsgc3Ryb2tlLWRhc2hhcnJheTogNS4wLDUuMDsiIHgxPSIzMSIgeDI9IjMxIiB5MT0iMzQuNDg4MyIgeTI9IjE3MS43MzA1Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjA7IHN0cm9rZS1kYXNoYXJyYXk6IDUuMCw1LjA7IiB4MT0iMjY0LjUiIHgyPSIyNjQuNSIgeTE9IjM0LjQ4ODMiIHkyPSIxNzEuNzMwNSIvPjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGhlaWdodD0iMzAuNDg4MyIgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjU7IiB3aWR0aD0iNDciIHg9IjgiIHk9IjMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIzMyIgeD0iMTUiIHk9IjIzLjUzNTIiPkFsaWNlPC90ZXh0PjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGhlaWdodD0iMzAuNDg4MyIgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjU7IiB3aWR0aD0iNDciIHg9IjgiIHk9IjE3MC43MzA1Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMzMiIHg9IjE1IiB5PSIxOTEuMjY1NiI+QWxpY2U8L3RleHQ+PHJlY3QgZmlsbD0iI0ZFRkVDRSIgaGVpZ2h0PSIzMC40ODgzIiBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuNTsiIHdpZHRoPSI0MCIgeD0iMjQ0LjUiIHk9IjMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIyNiIgeD0iMjUxLjUiIHk9IjIzLjUzNTIiPkJvYjwvdGV4dD48cmVjdCBmaWxsPSIjRkVGRUNFIiBoZWlnaHQ9IjMwLjQ4ODMiIHN0eWxlPSJzdHJva2U6ICNBODAwMzY7IHN0cm9rZS13aWR0aDogMS41OyIgd2lkdGg9IjQwIiB4PSIyNDQuNSIgeT0iMTcwLjczMDUiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIyNiIgeD0iMjUxLjUiIHk9IjE5MS4yNjU2Ij5Cb2I8L3RleHQ+PHBvbHlnb24gZmlsbD0iI0E4MDAzNiIgcG9pbnRzPSIyNTIuNSw2MS43OTg4LDI2Mi41LDY1Ljc5ODgsMjUyLjUsNjkuNzk4OCwyNTYuNSw2NS43OTg4IiBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsiIHgxPSIzMS41IiB4Mj0iMjU4LjUiIHkxPSI2NS43OTg4IiB5Mj0iNjUuNzk4OCIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmdBbmRHbHlwaHMiIHRleHRMZW5ndGg9IjE0NyIgeD0iMzguNSIgeT0iNjEuMDU2NiI+QXV0aGVudGljYXRpb24gUmVxdWVzdDwvdGV4dD48cG9seWdvbiBmaWxsPSIjQTgwMDM2IiBwb2ludHM9IjQyLjUsOTEuMTA5NCwzMi41LDk1LjEwOTQsNDIuNSw5OS4xMDk0LDM4LjUsOTUuMTA5NCIgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjA7IHN0cm9rZS1kYXNoYXJyYXk6IDIuMCwyLjA7IiB4MT0iMzYuNSIgeDI9IjI2My41IiB5MT0iOTUuMTA5NCIgeTI9Ijk1LjEwOTQiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIxNTciIHg9IjQ4LjUiIHk9IjkwLjM2NzIiPkF1dGhlbnRpY2F0aW9uIFJlc3BvbnNlPC90ZXh0Pjxwb2x5Z29uIGZpbGw9IiNBODAwMzYiIHBvaW50cz0iMjUyLjUsMTIwLjQxOTksMjYyLjUsMTI0LjQxOTksMjUyLjUsMTI4LjQxOTksMjU2LjUsMTI0LjQxOTkiIHN0eWxlPSJzdHJva2U6ICNBODAwMzY7IHN0cm9rZS13aWR0aDogMS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6ICNBODAwMzY7IHN0cm9rZS13aWR0aDogMS4wOyIgeDE9IjMxLjUiIHgyPSIyNTguNSIgeTE9IjEyNC40MTk5IiB5Mj0iMTI0LjQxOTkiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIxOTkiIHg9IjM4LjUiIHk9IjExOS42Nzc3Ij5Bbm90aGVyIGF1dGhlbnRpY2F0aW9uIFJlcXVlc3Q8L3RleHQ+PHBvbHlnb24gZmlsbD0iI0E4MDAzNiIgcG9pbnRzPSI0Mi41LDE0OS43MzA1LDMyLjUsMTUzLjczMDUsNDIuNSwxNTcuNzMwNSwzOC41LDE1My43MzA1IiBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsgc3Ryb2tlLWRhc2hhcnJheTogMi4wLDIuMDsiIHgxPSIzNi41IiB4Mj0iMjYzLjUiIHkxPSIxNTMuNzMwNSIgeTI9IjE1My43MzA1Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMjA5IiB4PSI0OC41IiB5PSIxNDguOTg4MyI+QW5vdGhlciBhdXRoZW50aWNhdGlvbiBSZXNwb25zZTwvdGV4dD48IS0tTUQ1PVs3ZjNlNGQwYzkwMWVmZGJjNTdlYjQ0MjQ5YTNiODE5N10KQHN0YXJ0dW1sDQpza2lucGFyYW0gc2hhZG93aW5nIGZhbHNlDQpBbGljZSAtPiBCb2I6IEF1dGhlbnRpY2F0aW9uIFJlcXVlc3QNCkJvYiAtIC0+IEFsaWNlOiBBdXRoZW50aWNhdGlvbiBSZXNwb25zZQ0KDQpBbGljZSAtPiBCb2I6IEFub3RoZXIgYXV0aGVudGljYXRpb24gUmVxdWVzdA0KQWxpY2UgPC0gLSBCb2I6IEFub3RoZXIgYXV0aGVudGljYXRpb24gUmVzcG9uc2UNCkBlbmR1bWwNCgpQbGFudFVNTCB2ZXJzaW9uIDEuMjAyMC4wMihTdW4gTWFyIDAxIDA0OjIyOjA3IENTVCAyMDIwKQooTUlUIHNvdXJjZSBkaXN0cmlidXRpb24pCkphdmEgUnVudGltZTogT3BlbkpESyBSdW50aW1lIEVudmlyb25tZW50CkpWTTogT3BlbkpESyA2NC1CaXQgU2VydmVyIFZNCkphdmEgVmVyc2lvbjogMTIrMzMKT3BlcmF0aW5nIFN5c3RlbTogTWFjIE9TIFgKRGVmYXVsdCBFbmNvZGluZzogVVRGLTgKTGFuZ3VhZ2U6IGVuCkNvdW50cnk6IFVTCi0tPjwvZz48L3N2Zz4=', 1947 295, 212); 1948 }, 200); 1949 1950 } 1951 else 1952 { 1953 editorUi.generatePlantUmlImage(text, format, function(data, w, h) 1954 { 1955 editorUi.spinner.stop(); 1956 insertPlantUmlImage(text, format, data, w, h); 1957 1958 }, function(e) 1959 { 1960 editorUi.handleError(e); 1961 }); 1962 } 1963 } 1964 } 1965 else if (type == 'mermaid') 1966 { 1967 if (editorUi.spinner.spin(document.body, mxResources.get('inserting'))) 1968 { 1969 var graph = editorUi.editor.graph; 1970 1971 editorUi.generateMermaidImage(text, format, function(data, w, h) 1972 { 1973 insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : graph.getCenterInsertPoint(new mxRectangle(0, 0, w, h)); 1974 editorUi.spinner.stop(); 1975 var cell = null; 1976 1977 graph.getModel().beginUpdate(); 1978 try 1979 { 1980 cell = graph.insertVertex(null, null, null, insertPoint.x, insertPoint.y, 1981 w, h, 'shape=image;noLabel=1;verticalAlign=top;imageAspect=1;' + 1982 'image=' + data + ';') 1983 graph.setAttributeForCell(cell, 'mermaidData', 1984 JSON.stringify({data: text, config: 1985 EditorUi.defaultMermaidConfig}, null, 2)); 1986 } 1987 finally 1988 { 1989 graph.getModel().endUpdate(); 1990 } 1991 1992 if (cell != null) 1993 { 1994 graph.setSelectionCell(cell); 1995 graph.scrollCellToVisible(cell); 1996 } 1997 }, function(e) 1998 { 1999 editorUi.handleError(e); 2000 }); 2001 } 2002 } 2003 else if (type == 'table') 2004 { 2005 var tableCell = null; 2006 var cells = []; 2007 var dx = 0; 2008 var pkMap = {}; 2009 2010 //First pass to find primary keys 2011 for (var i = 0; i < lines.length; i++) 2012 { 2013 var line = mxUtils.trim(lines[i]); 2014 2015 if (line.substring(0, 11).toLowerCase() == 'primary key') 2016 { 2017 var pk = line.match(/\((.+)\)/); 2018 2019 if (pk && pk[1]) 2020 { 2021 pkMap[pk[1]] = true; 2022 } 2023 2024 lines.splice(i, 1); 2025 } 2026 else if (line.toLowerCase().indexOf('primary key') > 0) 2027 { 2028 pkMap[line.split(' ')[0]] = true; 2029 lines[i] = mxUtils.trim(line.replace(/primary key/i, '')); 2030 } 2031 } 2032 2033 for (var i = 0; i < lines.length; i++) 2034 { 2035 var tmp = mxUtils.trim(lines[i]); 2036 2037 if (tmp.substring(0, 12).toLowerCase() == 'create table') 2038 { 2039 var name = mxUtils.trim(tmp.substring(12)); 2040 2041 if (name.charAt(name.length - 1) == '(') 2042 { 2043 name = mxUtils.trim(name.substring(0, name.length - 1)); 2044 } 2045 2046 tableCell = new mxCell(name, new mxGeometry(dx, 0, 160, 40), 2047 'shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;'); 2048 tableCell.vertex = true; 2049 cells.push(tableCell); 2050 2051 var size = editorUi.editor.graph.getPreferredSizeForCell(rowCell); 2052 2053 if (size != null) 2054 { 2055 tableCell.geometry.width = size.width + 10; 2056 } 2057 } 2058 else if (tableCell != null && tmp.charAt(0) == ')') 2059 { 2060 dx += tableCell.geometry.width + 40; 2061 tableCell = null; 2062 } 2063 else if (tmp != '(' && tableCell != null) 2064 { 2065 var name = tmp.substring(0, (tmp.charAt(tmp.length - 1) == ',') ? tmp.length - 1 : tmp.length); 2066 2067 var pk = pkMap[name.split(' ')[0]]; 2068 var rowCell = new mxCell('', new mxGeometry(0, 0, 160, 30), 2069 'shape=partialRectangle;collapsible=0;dropTarget=0;pointerEvents=0;fillColor=none;' + 2070 'points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=' + 2071 (pk ? '1' : '0') + ';'); 2072 rowCell.vertex = true; 2073 2074 var left = new mxCell(pk ? 'PK' : '', new mxGeometry(0, 0, 30, 30), 2075 'shape=partialRectangle;overflow=hidden;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;' + (pk ? 'fontStyle=1;' : '')); 2076 left.vertex = true; 2077 rowCell.insert(left); 2078 2079 var right = new mxCell(name, new mxGeometry(30, 0, 130, 30), 2080 'shape=partialRectangle;overflow=hidden;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;' + (pk ? 'fontStyle=5;' : '')); 2081 right.vertex = true; 2082 rowCell.insert(right); 2083 2084 var size = editorUi.editor.graph.getPreferredSizeForCell(right); 2085 2086 if (size != null && tableCell.geometry.width < size.width + 30) 2087 { 2088 tableCell.geometry.width = Math.min(320, Math.max(tableCell.geometry.width, size.width + 30)); 2089 } 2090 2091 tableCell.insert(rowCell, pk? 0 : null); 2092 tableCell.geometry.height += 30; 2093 } 2094 } 2095 2096 if (cells.length > 0) 2097 { 2098 var graph = editorUi.editor.graph; 2099 insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : 2100 graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true)); 2101 graph.setSelectionCells(graph.importCells(cells, insertPoint.x, insertPoint.y)); 2102 graph.scrollCellToVisible(graph.getSelectionCell()); 2103 } 2104 } 2105 else if (type == 'list') 2106 { 2107 if (lines.length > 0) 2108 { 2109 var graph = editorUi.editor.graph; 2110 var listCell = null; 2111 var cells = []; 2112 var x0 = 0; 2113 2114 for (var i = 0; i < lines.length; i++) 2115 { 2116 if (lines[i].charAt(0) != ';') 2117 { 2118 if (lines[i].length == 0) 2119 { 2120 listCell = null; 2121 } 2122 else 2123 { 2124 if (listCell == null) 2125 { 2126 listCell = new mxCell(lines[i], new mxGeometry(x0, 0, 160, 26 + 4), 2127 'swimlane;fontStyle=1;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;'); 2128 listCell.vertex = true; 2129 cells.push(listCell); 2130 2131 var size = graph.getPreferredSizeForCell(listCell); 2132 2133 if (size != null && listCell.geometry.width < size.width + 10) 2134 { 2135 listCell.geometry.width = size.width + 10; 2136 } 2137 2138 x0 += listCell.geometry.width + 40; 2139 } 2140 else if (lines[i] == '--') 2141 { 2142 var divider = new mxCell('', new mxGeometry(0, 0, 40, 8), 'line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;'); 2143 divider.vertex = true; 2144 listCell.geometry.height += divider.geometry.height; 2145 listCell.insert(divider); 2146 } 2147 else if (lines[i].length > 0) 2148 { 2149 var field = new mxCell(lines[i], new mxGeometry(0, 0, 60, 26), 'text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;'); 2150 field.vertex = true; 2151 2152 var size = graph.getPreferredSizeForCell(field); 2153 2154 if (size != null && field.geometry.width < size.width) 2155 { 2156 field.geometry.width = size.width; 2157 } 2158 2159 listCell.geometry.width = Math.max(listCell.geometry.width, field.geometry.width); 2160 listCell.geometry.height += field.geometry.height; 2161 listCell.insert(field); 2162 } 2163 } 2164 } 2165 } 2166 2167 if (cells.length > 0) 2168 { 2169 insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : 2170 graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true)); 2171 2172 graph.getModel().beginUpdate(); 2173 try 2174 { 2175 cells = graph.importCells(cells, insertPoint.x, insertPoint.y); 2176 var inserted = []; 2177 2178 for (var i = 0; i < cells.length; i++) 2179 { 2180 inserted.push(cells[i]); 2181 inserted = inserted.concat(cells[i].children); 2182 } 2183 2184 graph.fireEvent(new mxEventObject('cellsInserted', 'cells', inserted)); 2185 } 2186 finally 2187 { 2188 graph.getModel().endUpdate(); 2189 } 2190 2191 graph.setSelectionCells(cells); 2192 graph.scrollCellToVisible(graph.getSelectionCell()); 2193 } 2194 } 2195 } 2196 else 2197 { 2198 var vertices = new Object(); 2199 var cells = []; 2200 2201 function getOrCreateVertex(id) 2202 { 2203 var vertex = vertices[id]; 2204 2205 if (vertex == null) 2206 { 2207 vertex = new mxCell(id, new mxGeometry(0, 0, 80, 30), 'whiteSpace=wrap;html=1;'); 2208 vertex.vertex = true; 2209 vertices[id] = vertex; 2210 cells.push(vertex); 2211 } 2212 2213 return vertex; 2214 }; 2215 2216 for (var i = 0; i < lines.length; i++) 2217 { 2218 if (lines[i].charAt(0) != ';') 2219 { 2220 var values = lines[i].split('->'); 2221 2222 if (values.length >= 2) 2223 { 2224 var source = getOrCreateVertex(values[0]); 2225 var target = getOrCreateVertex(values[values.length - 1]); 2226 2227 var edge = new mxCell((values.length > 2) ? values[1] : '', new mxGeometry()); 2228 edge.edge = true; 2229 source.insertEdge(edge, true); 2230 target.insertEdge(edge, false); 2231 cells.push(edge); 2232 } 2233 } 2234 } 2235 2236 if (cells.length > 0) 2237 { 2238 var container = document.createElement('div'); 2239 container.style.visibility = 'hidden'; 2240 document.body.appendChild(container); 2241 2242 // Temporary graph for running the layout 2243 var graph = new Graph(container); 2244 2245 graph.getModel().beginUpdate(); 2246 try 2247 { 2248 cells = graph.importCells(cells); 2249 2250 for (var i = 0; i < cells.length; i++) 2251 { 2252 if (graph.getModel().isVertex(cells[i])) 2253 { 2254 var size = graph.getPreferredSizeForCell(cells[i]); 2255 cells[i].geometry.width = Math.max(cells[i].geometry.width, size.width); 2256 cells[i].geometry.height = Math.max(cells[i].geometry.height, size.height); 2257 } 2258 } 2259 2260 var layout = new mxFastOrganicLayout(graph); 2261 layout.disableEdgeStyle = false; 2262 layout.forceConstant = 120; 2263 layout.execute(graph.getDefaultParent()); 2264 2265 var edgeLayout = new mxParallelEdgeLayout(graph); 2266 edgeLayout.spacing = 20; 2267 edgeLayout.execute(graph.getDefaultParent()); 2268 } 2269 finally 2270 { 2271 graph.getModel().endUpdate(); 2272 } 2273 2274 graph.clearCellOverlays(); 2275 2276 // Copy to actual graph 2277 var inserted = []; 2278 2279 editorUi.editor.graph.getModel().beginUpdate(); 2280 try 2281 { 2282 cells = graph.getModel().getChildren(graph.getDefaultParent()); 2283 insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : 2284 editorUi.editor.graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true)); 2285 inserted = editorUi.editor.graph.importCells(cells, insertPoint.x, insertPoint.y) 2286 editorUi.editor.graph.fireEvent(new mxEventObject('cellsInserted', 'cells', inserted)); 2287 } 2288 finally 2289 { 2290 editorUi.editor.graph.getModel().endUpdate(); 2291 } 2292 2293 editorUi.editor.graph.setSelectionCells(inserted); 2294 editorUi.editor.graph.scrollCellToVisible(editorUi.editor.graph.getSelectionCell()); 2295 graph.destroy(); 2296 container.parentNode.removeChild(container); 2297 } 2298 } 2299 }; 2300 2301 var div = document.createElement('div'); 2302 div.style.textAlign = 'right'; 2303 2304 var textarea = document.createElement('textarea'); 2305 textarea.style.resize = 'none'; 2306 textarea.style.width = '100%'; 2307 textarea.style.height = '354px'; 2308 textarea.style.marginBottom = '16px'; 2309 2310 var typeSelect = document.createElement('select'); 2311 2312 if (defaultType == 'formatSql' || defaultType == 'mermaid') 2313 { 2314 typeSelect.style.display = 'none'; 2315 } 2316 2317 var listOption = document.createElement('option'); 2318 listOption.setAttribute('value', 'list'); 2319 mxUtils.write(listOption, mxResources.get('list')); 2320 2321 if (defaultType != 'plantUml') 2322 { 2323 typeSelect.appendChild(listOption); 2324 } 2325 2326 if (defaultType == null || defaultType == 'fromText') 2327 { 2328 listOption.setAttribute('selected', 'selected'); 2329 } 2330 2331 var tableOption = document.createElement('option'); 2332 tableOption.setAttribute('value', 'table'); 2333 mxUtils.write(tableOption, mxResources.get('formatSql')); 2334 2335 if (defaultType == 'formatSql') 2336 { 2337 typeSelect.appendChild(tableOption); 2338 tableOption.setAttribute('selected', 'selected'); 2339 } 2340 2341 var mermaidOption = document.createElement('option'); 2342 mermaidOption.setAttribute('value', 'mermaid'); 2343 mxUtils.write(mermaidOption, mxResources.get('formatSql')); 2344 2345 if (defaultType == 'mermaid') 2346 { 2347 typeSelect.appendChild(mermaidOption); 2348 mermaidOption.setAttribute('selected', 'selected'); 2349 } 2350 2351 var diagramOption = document.createElement('option'); 2352 diagramOption.setAttribute('value', 'diagram'); 2353 mxUtils.write(diagramOption, mxResources.get('diagram')); 2354 2355 if (defaultType != 'plantUml') 2356 { 2357 typeSelect.appendChild(diagramOption); 2358 } 2359 2360 var plantUmlSvgOption = document.createElement('option'); 2361 plantUmlSvgOption.setAttribute('value', 'plantUmlSvg'); 2362 mxUtils.write(plantUmlSvgOption, mxResources.get('plantUml') + ' (' + mxResources.get('formatSvg') + ')'); 2363 2364 if (defaultType == 'plantUml') 2365 { 2366 plantUmlSvgOption.setAttribute('selected', 'selected'); 2367 } 2368 2369 var plantUmlPngOption = document.createElement('option'); 2370 plantUmlPngOption.setAttribute('value', 'plantUmlPng'); 2371 mxUtils.write(plantUmlPngOption, mxResources.get('plantUml') + ' (' + mxResources.get('formatPng') + ')'); 2372 2373 var plantUmlTxtOption = document.createElement('option'); 2374 plantUmlTxtOption.setAttribute('value', 'plantUmlTxt'); 2375 mxUtils.write(plantUmlTxtOption, mxResources.get('plantUml') + ' (' + mxResources.get('text') + ')'); 2376 2377 // Disabled for invalid hosts via CORS headers 2378 if (EditorUi.enablePlantUml && Graph.fileSupport && 2379 !editorUi.isOffline() && defaultType == 'plantUml') 2380 { 2381 typeSelect.appendChild(plantUmlSvgOption); 2382 typeSelect.appendChild(plantUmlPngOption); 2383 typeSelect.appendChild(plantUmlTxtOption); 2384 } 2385 2386 function getDefaultValue() 2387 { 2388 if (typeSelect.value == 'list') 2389 { 2390 return 'Person\n-name: String\n-birthDate: Date\n--\n+getName(): String\n+setName(String): void\n+isBirthday(): boolean\n\n' + 2391 'Address\n-street: String\n-city: String\n-state: String'; 2392 } 2393 else if (typeSelect.value == 'mermaid') 2394 { 2395 return 'graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;'; 2396 } 2397 else if (typeSelect.value == 'table') 2398 { 2399 return 'CREATE TABLE Suppliers\n(\nsupplier_id int NOT NULL PRIMARY KEY,\n' + 2400 'supplier_name char(50) NOT NULL,\ncontact_name char(50),\n);\n' + 2401 'CREATE TABLE Customers\n(\ncustomer_id int NOT NULL PRIMARY KEY,\n' + 2402 'customer_name char(50) NOT NULL,\naddress char(50),\n' + 2403 'city char(50),\nstate char(25),\nzip_code char(10)\n);\n'; 2404 } 2405 else if (typeSelect.value == 'plantUmlPng') 2406 { 2407 return '@startuml\nskinparam backgroundcolor transparent\nskinparam shadowing false\nAlice -> Bob: Authentication Request\nBob --> Alice: Authentication Response\n\nAlice -> Bob: Another authentication Request\nAlice <-- Bob: Another authentication Response\n@enduml'; 2408 } 2409 else if (typeSelect.value == 'plantUmlSvg' || typeSelect.value == 'plantUmlTxt') 2410 { 2411 return plantUmlExample; 2412 } 2413 else 2414 { 2415 return ';Example:\na->b\nb->edge label->c\nc->a\n'; 2416 } 2417 }; 2418 2419 var defaultValue = getDefaultValue(); 2420 textarea.value = defaultValue; 2421 div.appendChild(textarea); 2422 2423 this.init = function() 2424 { 2425 textarea.focus(); 2426 }; 2427 2428 // Enables dropping files 2429 if (Graph.fileSupport) 2430 { 2431 function handleDrop(evt) 2432 { 2433 evt.stopPropagation(); 2434 evt.preventDefault(); 2435 2436 if (evt.dataTransfer.files.length > 0) 2437 { 2438 var file = evt.dataTransfer.files[0]; 2439 2440 var reader = new FileReader(); 2441 reader.onload = function(e) { textarea.value = e.target.result; }; 2442 reader.readAsText(file); 2443 } 2444 }; 2445 2446 function handleDragOver(evt) 2447 { 2448 evt.stopPropagation(); 2449 evt.preventDefault(); 2450 }; 2451 2452 // Setup the dnd listeners. 2453 textarea.addEventListener('dragover', handleDragOver, false); 2454 textarea.addEventListener('drop', handleDrop, false); 2455 } 2456 2457 div.appendChild(typeSelect); 2458 2459 mxEvent.addListener(typeSelect, 'change', function() 2460 { 2461 var newDefaultValue = getDefaultValue(); 2462 2463 if (textarea.value.length == 0 || textarea.value == defaultValue) 2464 { 2465 defaultValue = newDefaultValue; 2466 textarea.value = defaultValue; 2467 } 2468 }); 2469 2470 if (!editorUi.isOffline() && (defaultType == 'mermaid' || defaultType == 'plantUml')) 2471 { 2472 var helpBtn = mxUtils.button(mxResources.get('help'), function() 2473 { 2474 editorUi.openLink((defaultType == 'mermaid') ? 2475 'https://mermaid-js.github.io/mermaid/#/' : 2476 'https://plantuml.com/'); 2477 }); 2478 2479 helpBtn.className = 'geBtn'; 2480 div.appendChild(helpBtn); 2481 } 2482 2483 var cancelBtn = mxUtils.button(mxResources.get('close'), function() 2484 { 2485 if (textarea.value == defaultValue) 2486 { 2487 editorUi.hideDialog(); 2488 } 2489 else 2490 { 2491 editorUi.confirm(mxResources.get('areYouSure'), function() 2492 { 2493 editorUi.hideDialog(); 2494 }); 2495 } 2496 }); 2497 2498 cancelBtn.className = 'geBtn'; 2499 2500 if (editorUi.editor.cancelFirst) 2501 { 2502 div.appendChild(cancelBtn); 2503 } 2504 2505 var okBtn = mxUtils.button(mxResources.get('insert'), function(evt) 2506 { 2507 editorUi.hideDialog(); 2508 parse(textarea.value, typeSelect.value, evt); 2509 }); 2510 div.appendChild(okBtn); 2511 2512 okBtn.className = 'geBtn gePrimaryBtn'; 2513 2514 if (!editorUi.editor.cancelFirst) 2515 { 2516 div.appendChild(cancelBtn); 2517 } 2518 2519 this.container = div; 2520}; 2521 2522/** 2523 * Constructs a new dialog for creating files from templates. 2524 */ 2525var NewDialog = function(editorUi, compact, showName, callback, createOnly, cancelCallback, 2526 leftHighlight, rightHighlight, rightHighlightBorder, itemPadding, templateFile, 2527 recentDocsCallback, searchDocsCallback, openExtDocCallback, showImport, createButtonLabel, customTempCallback, withoutType) 2528{ 2529 var ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 2530 var smallScreen = ww < 500; 2531 showName = (showName != null) ? showName : true; 2532 createOnly = (createOnly != null) ? createOnly : false; 2533 leftHighlight = (leftHighlight != null) ? leftHighlight : '#ebf2f9'; 2534 rightHighlight = (rightHighlight != null) ? rightHighlight : (Editor.isDarkMode() ? '#a2a2a2' : '#e6eff8'); 2535 rightHighlightBorder = (rightHighlightBorder != null) ? rightHighlightBorder : (Editor.isDarkMode() ? '1px dashed #00a8ff' : '1px solid #ccd9ea'); 2536 templateFile = (templateFile != null) ? templateFile : EditorUi.templateFile; 2537 2538 var outer = document.createElement('div'); 2539 outer.style.userSelect = 'none'; 2540 outer.style.height = '100%'; 2541 2542 var header = document.createElement('div'); 2543 header.style.whiteSpace = 'nowrap'; 2544 header.style.height = '46px'; 2545 2546 if (showName) 2547 { 2548 outer.appendChild(header); 2549 } 2550 2551 var logo = document.createElement('img'); 2552 logo.setAttribute('border', '0'); 2553 logo.setAttribute('align', 'absmiddle'); 2554 logo.style.width = '40px'; 2555 logo.style.height = '40px'; 2556 logo.style.marginRight = '10px'; 2557 logo.style.paddingBottom = '4px'; 2558 2559 if (editorUi.mode == App.MODE_GOOGLE) 2560 { 2561 logo.src = IMAGE_PATH + '/google-drive-logo.svg'; 2562 } 2563 else if (editorUi.mode == App.MODE_DROPBOX) 2564 { 2565 logo.src = IMAGE_PATH + '/dropbox-logo.svg'; 2566 } 2567 else if (editorUi.mode == App.MODE_ONEDRIVE) 2568 { 2569 logo.src = IMAGE_PATH + '/onedrive-logo.svg'; 2570 } 2571 else if (editorUi.mode == App.MODE_GITHUB) 2572 { 2573 logo.src = IMAGE_PATH + '/github-logo.svg'; 2574 } 2575 else if (editorUi.mode == App.MODE_GITLAB) 2576 { 2577 logo.src = IMAGE_PATH + '/gitlab-logo.svg'; 2578 } 2579 else if (editorUi.mode == App.MODE_NOTION) 2580 { 2581 logo.src = IMAGE_PATH + '/notion-logo.svg'; 2582 } 2583 else if (editorUi.mode == App.MODE_TRELLO) 2584 { 2585 logo.src = IMAGE_PATH + '/trello-logo.svg'; 2586 } 2587 else if (editorUi.mode == App.MODE_BROWSER) 2588 { 2589 logo.src = IMAGE_PATH + '/osa_database.png'; 2590 } 2591 else 2592 { 2593 logo.src = IMAGE_PATH + '/osa_drive-harddisk.png'; 2594 } 2595 2596 if (!compact && !smallScreen && showName) 2597 { 2598 header.appendChild(logo); 2599 } 2600 2601 if (showName) 2602 { 2603 mxUtils.write(header, (smallScreen? mxResources.get('name') : ((editorUi.mode == null || editorUi.mode == App.MODE_GOOGLE || 2604 editorUi.mode == App.MODE_BROWSER) ? mxResources.get('diagramName') : mxResources.get('filename'))) + ':'); 2605 } 2606 2607 var ext = '.drawio'; 2608 2609 if (editorUi.mode == App.MODE_GOOGLE && editorUi.drive != null) 2610 { 2611 ext = editorUi.drive.extension; 2612 } 2613 else if (editorUi.mode == App.MODE_DROPBOX && editorUi.dropbox != null) 2614 { 2615 ext = editorUi.dropbox.extension; 2616 } 2617 else if (editorUi.mode == App.MODE_ONEDRIVE && editorUi.oneDrive != null) 2618 { 2619 ext = editorUi.oneDrive.extension; 2620 } 2621 else if (editorUi.mode == App.MODE_GITHUB && editorUi.gitHub != null) 2622 { 2623 ext = editorUi.gitHub.extension; 2624 } 2625 else if (editorUi.mode == App.MODE_GITLAB && editorUi.gitLab != null) 2626 { 2627 ext = editorUi.gitLab.extension; 2628 } 2629 else if (editorUi.mode == App.MODE_NOTION && editorUi.notion != null) 2630 { 2631 ext = editorUi.notion.extension; 2632 } 2633 else if (editorUi.mode == App.MODE_TRELLO && editorUi.trello != null) 2634 { 2635 ext = editorUi.trello.extension; 2636 } 2637 2638 var nameInput = document.createElement('input'); 2639 nameInput.setAttribute('value', editorUi.defaultFilename + ext); 2640 nameInput.style.marginLeft = '10px'; 2641 nameInput.style.width = (compact || smallScreen) ? '144px' : '244px'; 2642 2643 this.init = function() 2644 { 2645 if (showName) 2646 { 2647 nameInput.focus(); 2648 2649 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 2650 { 2651 nameInput.select(); 2652 } 2653 else 2654 { 2655 document.execCommand('selectAll', false, null); 2656 } 2657 } 2658 2659 if (div.parentNode != null && div.parentNode.parentNode != null) 2660 { 2661 mxEvent.addGestureListeners(div.parentNode.parentNode, mxUtils.bind(this, function(evt) 2662 { 2663 editorUi.sidebar.hideTooltip(); 2664 }), null, null); 2665 } 2666 }; 2667 2668 // Adds filetype dropdown 2669 if (showName) 2670 { 2671 header.appendChild(nameInput); 2672 2673 if (withoutType) 2674 { 2675 nameInput.style.width = (compact || smallScreen) ? '350px' : '450px'; 2676 } 2677 else 2678 { 2679 if (editorUi.editor.diagramFileTypes != null) 2680 { 2681 var typeSelect = FilenameDialog.createFileTypes(editorUi, nameInput, editorUi.editor.diagramFileTypes); 2682 typeSelect.style.marginLeft = '6px'; 2683 typeSelect.style.width = (compact || smallScreen) ? '80px' : '180px'; 2684 header.appendChild(typeSelect); 2685 } 2686 2687 if (editorUi.editor.fileExtensions != null) 2688 { 2689 var hint = FilenameDialog.createTypeHint(editorUi, 2690 nameInput, editorUi.editor.fileExtensions); 2691 hint.style.marginTop = '12px'; 2692 2693 header.appendChild(hint); 2694 } 2695 } 2696 } 2697 2698 var hasTabs = false; 2699 var i0 = 0; 2700 2701 // Dynamic loading 2702 function addTemplates(smallSize) 2703 { 2704 //smallSize: Reduce template button size to fit 4 in a row 2705 if (smallSize != null) 2706 { 2707 w = h = smallSize? 135 : 140; 2708 } 2709 2710 var first = true; 2711 2712 //TODO support paging of external templates 2713 if (templates != null) 2714 { 2715 while (i0 < templates.length && (first || mxUtils.mod(i0, 30) != 0)) 2716 { 2717 var tmp = templates[i0++]; 2718 var btn = addButton(tmp.url, tmp.libs, tmp.title, tmp.tooltip? tmp.tooltip : tmp.title, 2719 tmp.select, tmp.imgUrl, tmp.info, tmp.onClick, tmp.preview, tmp.noImg, tmp.clibs); 2720 2721 if (first) 2722 { 2723 btn.click(); 2724 } 2725 2726 first = false; 2727 } 2728 } 2729 }; 2730 2731 var spinner = new Spinner({ 2732 lines: 12, // The number of lines to draw 2733 length: 10, // The length of each line 2734 width: 5, // The line thickness 2735 radius: 10, // The radius of the inner circle 2736 rotate: 0, // The rotation offset 2737 color: '#000', // #rgb or #rrggbb 2738 speed: 1.5, // Rounds per second 2739 trail: 60, // Afterglow percentage 2740 shadow: false, // Whether to render a shadow 2741 hwaccel: false, // Whether to use hardware acceleration 2742 top: '40%', 2743 zIndex: 2e9 // The z-index (defaults to 2000000000) 2744 }); 2745 2746 var createButton = mxUtils.button(createButtonLabel || mxResources.get('create'), function() 2747 { 2748 createButton.setAttribute('disabled', 'disabled'); 2749 create(); 2750 createButton.removeAttribute('disabled'); 2751 }); 2752 2753 createButton.className = 'geBtn gePrimaryBtn'; 2754 2755 if (recentDocsCallback || searchDocsCallback) 2756 { 2757 var tabsEl = []; 2758 var oldTemplates = null, origCategories = null, origCustomCatCount = null; 2759 2760 var setActiveTab = function(index) 2761 { 2762 createButton.setAttribute('disabled', 'disabled'); 2763 2764 for (var i = 0; i < tabsEl.length; i++) 2765 { 2766 if (i == index) 2767 tabsEl[i].className = 'geBtn gePrimaryBtn'; 2768 else 2769 tabsEl[i].className = 'geBtn'; 2770 } 2771 } 2772 2773 hasTabs = true; 2774 var tabs = document.createElement('div'); 2775 tabs.style.whiteSpace = 'nowrap'; 2776 tabs.style.height = '30px'; 2777 outer.appendChild(tabs); 2778 2779 var templatesTab = mxUtils.button(mxResources.get('Templates', null, 'Templates'), function() 2780 { 2781 list.style.display = ''; 2782 searchBox.style.display = ''; 2783 div.style.left = '160px'; 2784 setActiveTab(0); 2785 2786 div.scrollTop = 0; 2787 div.innerHTML = ''; 2788 i0 = 0; 2789 2790 if (oldTemplates != templates) 2791 { 2792 templates = oldTemplates; 2793 categories = origCategories; 2794 customCatCount = origCustomCatCount; 2795 list.innerHTML = ''; 2796 initUi(); 2797 oldTemplates = null; 2798 } 2799 }); 2800 2801 tabsEl.push(templatesTab); 2802 tabs.appendChild(templatesTab); 2803 2804 var getExtTemplates = function(isSearch) 2805 { 2806 list.style.display = 'none'; 2807 searchBox.style.display = 'none'; 2808 div.style.left = '30px'; 2809 2810 setActiveTab(isSearch? -1 : 1); //deselect all of them if isSearch 2811 2812 if (oldTemplates == null) 2813 { 2814 oldTemplates = templates; 2815 } 2816 2817 div.scrollTop = 0; 2818 div.innerHTML = ''; 2819 spinner.spin(div); 2820 2821 var callback2 = function(docList, errorMsg, searchImportCats) 2822 { 2823 i0 = 0; 2824 spinner.stop(); 2825 templates = docList; 2826 searchImportCats = searchImportCats || {}; 2827 var importListsCount = 0; 2828 2829 for (var cat in searchImportCats) 2830 { 2831 importListsCount += searchImportCats[cat].length; 2832 } 2833 2834 if (errorMsg) 2835 { 2836 div.innerHTML = errorMsg; 2837 } 2838 else if (docList.length == 0 && importListsCount == 0) 2839 { 2840 div.innerHTML = mxUtils.htmlEntities(mxResources.get('noDiagrams', null, 'No Diagrams Found')); 2841 } 2842 else 2843 { 2844 div.innerHTML = ''; 2845 2846 if (importListsCount > 0) 2847 { 2848 list.style.display = ''; 2849 div.style.left = '160px'; 2850 list.innerHTML = ''; 2851 2852 customCatCount = 0; 2853 categories = {'draw.io': docList}; 2854 2855 for (var cat in searchImportCats) 2856 { 2857 categories[cat] = searchImportCats[cat]; 2858 } 2859 2860 initUi(); 2861 } 2862 else 2863 { 2864 addTemplates(true); 2865 } 2866 } 2867 } 2868 2869 if (isSearch) 2870 { 2871 searchDocsCallback(searchInput.value, callback2); 2872 } 2873 else 2874 { 2875 recentDocsCallback(callback2); 2876 } 2877 } 2878 2879 if (recentDocsCallback) 2880 { 2881 var recentTab = mxUtils.button(mxResources.get('Recent', null, 'Recent'), function() 2882 { 2883 getExtTemplates(); 2884 }); 2885 2886 tabs.appendChild(recentTab); 2887 tabsEl.push(recentTab); 2888 } 2889 2890 if (searchDocsCallback) 2891 { 2892 var searchTab = document.createElement('span'); 2893 searchTab.style.marginLeft = '10px'; 2894 searchTab.innerHTML = mxUtils.htmlEntities(mxResources.get('search') + ':'); 2895 tabs.appendChild(searchTab); 2896 2897 var searchInput = document.createElement('input'); 2898 searchInput.style.marginRight = '10px'; 2899 searchInput.style.marginLeft = '10px'; 2900 searchInput.style.width = '220px'; 2901 2902 mxEvent.addListener(searchInput, 'keypress', function(e) 2903 { 2904 if (e.keyCode == 13) 2905 { 2906 getExtTemplates(true); 2907 } 2908 }); 2909 2910 tabs.appendChild(searchInput); 2911 2912 var searchBtn = mxUtils.button(mxResources.get('search'), function() 2913 { 2914 getExtTemplates(true); 2915 }); 2916 2917 searchBtn.className = 'geBtn'; 2918 2919 tabs.appendChild(searchBtn); 2920 } 2921 2922 setActiveTab(0); 2923 } 2924 2925 var templateLibs = null; 2926 var templateClibs = null; 2927 var templateXml = null; 2928 var selectedElt = null; 2929 var templateExtUrl = null; 2930 var templateRealUrl = null; 2931 var templateInfoObj = null; 2932 2933 function create() 2934 { 2935 if (templateExtUrl && openExtDocCallback != null) 2936 { 2937 if (!showName) 2938 { 2939 editorUi.hideDialog(); 2940 } 2941 2942 openExtDocCallback(templateExtUrl, templateInfoObj, nameInput.value); 2943 } 2944 else if (callback) 2945 { 2946 if (!showName) 2947 { 2948 editorUi.hideDialog(); 2949 } 2950 2951 callback(templateXml, nameInput.value, templateRealUrl, templateLibs); 2952 } 2953 else 2954 { 2955 var title = nameInput.value; 2956 2957 if (title != null && title.length > 0) 2958 { 2959 editorUi.pickFolder(editorUi.mode, function(folderId) 2960 { 2961 editorUi.createFile(title, templateXml, (templateLibs != null && 2962 templateLibs.length > 0) ? templateLibs : null, null, function() 2963 { 2964 editorUi.hideDialog(); 2965 }, null, folderId, null, (templateClibs != null && 2966 templateClibs.length > 0) ? templateClibs : null); 2967 }, editorUi.mode != App.MODE_GOOGLE || 2968 editorUi.stateArg == null || 2969 editorUi.stateArg.folderId == null); 2970 } 2971 } 2972 }; 2973 2974 var div = document.createElement('div'); 2975 div.style.border = '1px solid #d3d3d3'; 2976 div.style.position = 'absolute'; 2977 div.style.left = '160px'; 2978 div.style.right = '34px'; 2979 var divTop = (showName) ? 72 : 40; 2980 divTop += hasTabs? 30 : 0; 2981 div.style.top = divTop + 'px'; 2982 div.style.bottom = '68px'; 2983 div.style.margin = '6px 0 0 -1px'; 2984 div.style.padding = '6px'; 2985 div.style.overflow = 'auto'; 2986 2987// mxEvent.addListener(div, 'dragstart', function(evt) 2988// { 2989// if (!mxEvent.isTouchEvent(evt)) 2990// { 2991// mxEvent.consume(evt); 2992// } 2993// }); 2994 2995 var searchBox = document.createElement('div'); 2996 searchBox.style.cssText = 'position:absolute;left:30px;width:128px;top:' + divTop + 'px;height:22px;margin-top: 6px;white-space: nowrap'; 2997 var tmplSearchInput = document.createElement('input'); 2998 tmplSearchInput.style.cssText = 'width:105px;height:16px;border:1px solid #d3d3d3;padding: 3px 20px 3px 3px;font-size: 12px'; 2999 tmplSearchInput.setAttribute('placeholder', mxResources.get('search')); 3000 tmplSearchInput.setAttribute('type', 'text'); 3001 searchBox.appendChild(tmplSearchInput); 3002 3003 var cross = document.createElement('img'); 3004 var searchImg = typeof Sidebar != 'undefined'? Sidebar.prototype.searchImage : IMAGE_PATH + '/search.png'; 3005 cross.setAttribute('src', searchImg); 3006 cross.setAttribute('title', mxResources.get('search')); 3007 cross.style.position = 'relative'; 3008 cross.style.left = '-18px'; 3009 cross.style.top = '1px'; 3010 // Needed to block event transparency in IE 3011 cross.style.background = 'url(\'' + editorUi.editor.transparentImage + '\')'; 3012 searchBox.appendChild(cross); 3013 3014 mxEvent.addListener(cross, 'click', function() 3015 { 3016 if (cross.getAttribute('src') == Dialog.prototype.closeImage) 3017 { 3018 cross.setAttribute('src', searchImg); 3019 cross.setAttribute('title', mxResources.get('search')); 3020 tmplSearchInput.value = ''; 3021 resetTemplates(); 3022 } 3023 3024 tmplSearchInput.focus(); 3025 }); 3026 3027 mxEvent.addListener(tmplSearchInput, 'keydown', mxUtils.bind(this, function(evt) 3028 { 3029 if (evt.keyCode == 13 /* Enter */) 3030 { 3031 filterTemplates(); 3032 mxEvent.consume(evt); 3033 } 3034 })); 3035 3036 mxEvent.addListener(tmplSearchInput, 'keyup', mxUtils.bind(this, function(evt) 3037 { 3038 if (tmplSearchInput.value == '') 3039 { 3040 cross.setAttribute('src', searchImg); 3041 cross.setAttribute('title', mxResources.get('search')); 3042 } 3043 else 3044 { 3045 cross.setAttribute('src', Dialog.prototype.closeImage); 3046 cross.setAttribute('title', mxResources.get('reset')); 3047 } 3048 })); 3049 3050 divTop += 23; 3051 3052 var list = document.createElement('div'); 3053 list.style.cssText = 'position:absolute;left:30px;width:128px;top:' + divTop + 'px;bottom:68px;margin-top:6px;overflow:auto;border:1px solid #d3d3d3;'; 3054 3055 mxEvent.addListener(div, 'scroll', function() 3056 { 3057 editorUi.sidebar.hideTooltip(); 3058 }); 3059 3060 var w = 140; 3061 var h = 140; 3062 3063 function selectElement(elt, xml, libs, extUrl, infoObj, clibs, realUrl) 3064 { 3065 if (selectedElt != null) 3066 { 3067 selectedElt.style.backgroundColor = 'transparent'; 3068 selectedElt.style.border = '1px solid transparent'; 3069 } 3070 3071 createButton.removeAttribute('disabled'); 3072 3073 templateXml = xml; 3074 templateLibs = libs; 3075 templateClibs = clibs; 3076 selectedElt = elt; 3077 templateExtUrl = extUrl; 3078 templateRealUrl = realUrl; 3079 templateInfoObj = infoObj; 3080 3081 selectedElt.style.backgroundColor = rightHighlight; 3082 selectedElt.style.border = rightHighlightBorder; 3083 }; 3084 3085 function addButton(url, libs, title, tooltip, select, imgUrl, infoObj, onClick, preview, noImg, clibs) 3086 { 3087 var elt = document.createElement('div'); 3088 elt.className = 'geTemplate'; 3089 elt.style.position = 'relative'; 3090 elt.style.height = w + 'px'; 3091 elt.style.width = h + 'px'; 3092 var xmlData = null; 3093 3094 if (Editor.isDarkMode()) 3095 { 3096 elt.style.filter = 'invert(100%)'; 3097 } 3098 3099 if (title != null) 3100 { 3101 elt.setAttribute('title', mxResources.get(title, null, title)); 3102 } 3103 else if (tooltip != null && tooltip.length > 0) 3104 { 3105 elt.setAttribute('title', tooltip); 3106 } 3107 3108 function loadXmlData(url, callback) 3109 { 3110 if (xmlData == null) 3111 { 3112 var realUrl = url; 3113 3114 if (/^https?:\/\//.test(realUrl) && !editorUi.editor.isCorsEnabledForUrl(realUrl)) 3115 { 3116 realUrl = PROXY_URL + '?url=' + encodeURIComponent(realUrl); 3117 } 3118 else 3119 { 3120 realUrl = TEMPLATE_PATH + '/' + realUrl; 3121 } 3122 3123 mxUtils.get(realUrl, mxUtils.bind(this, function(req) 3124 { 3125 if (req.getStatus() >= 200 && req.getStatus() <= 299) 3126 { 3127 xmlData = req.getText(); 3128 callback(xmlData); 3129 } 3130 else 3131 { 3132 callback(xmlData); 3133 } 3134 })); 3135 } 3136 else 3137 { 3138 callback(xmlData); 3139 } 3140 } 3141 3142 // Shows a tooltip with the rendered template 3143 var loading = false; 3144 3145 function showTooltip(xml, x, y) 3146 { 3147 // Checks if dialog still visible 3148 if (xml != null && mxUtils.isAncestorNode(document.body, elt)) 3149 { 3150 var doc = mxUtils.parseXml(xml); 3151 var tempNode = Editor.parseDiagramNode(doc.documentElement); 3152 var codec = new mxCodec(tempNode.ownerDocument); 3153 var model = new mxGraphModel(); 3154 codec.decode(tempNode, model); 3155 var cells = model.root.getChildAt(0).children; 3156 3157 var ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 3158 var wh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; 3159 3160 // TODO: Use maxscreensize 3161 editorUi.sidebar.createTooltip(elt, cells, Math.min(ww - 80, 1000), Math.min(wh - 80, 800), 3162 (title != null) ? mxResources.get(title, null, title) : null, 3163 true, new mxPoint(x, y), true, function() 3164 { 3165 wasVisible = editorUi.sidebar.tooltip != null && 3166 editorUi.sidebar.tooltip.style.display != 'none'; 3167 selectElement(elt, null, null, url, infoObj, clibs); 3168 }, true, false); 3169 } 3170 }; 3171 3172 function loadTooltip(evt, magElt) 3173 { 3174 if (url != null && !loading && editorUi.sidebar.currentElt != elt) 3175 { 3176 editorUi.sidebar.hideTooltip(); 3177 editorUi.sidebar.currentElt = elt; 3178 loading = true; 3179 3180 loadXmlData(url, function(xml) 3181 { 3182 if (loading && editorUi.sidebar.currentElt == elt) 3183 { 3184 showTooltip(xml, mxEvent.getClientX(evt), mxEvent.getClientY(evt)); 3185 } 3186 3187 loading = false; 3188 }); 3189 } 3190 else 3191 { 3192 editorUi.sidebar.hideTooltip(); 3193 } 3194 }; 3195 3196 if (imgUrl != null) 3197 { 3198 elt.style.display = 'inline-flex'; 3199 elt.style.justifyContent = 'center'; 3200 elt.style.alignItems = 'center'; 3201 var img = document.createElement('img'); 3202 img.setAttribute('src', imgUrl); 3203 img.setAttribute('alt', tooltip); 3204 img.style.maxWidth = w + 'px'; 3205 img.style.maxHeight = h + 'px'; 3206 3207 var fallbackImgUrl = imgUrl.replace('.drawio.xml', '').replace('.drawio', '').replace('.xml', ''); 3208 elt.appendChild(img); 3209 3210 img.onerror = function() 3211 { 3212 if (this.src != fallbackImgUrl) 3213 { 3214 this.src = fallbackImgUrl; 3215 } 3216 else 3217 { 3218 this.src = Editor.errorImage; 3219 this.onerror = null; 3220 } 3221 }; 3222 3223 mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt) 3224 { 3225 selectElement(elt, null, null, url, infoObj, clibs); 3226 }), null, null); 3227 3228 mxEvent.addListener(elt, 'dblclick', function(evt) 3229 { 3230 create(); 3231 mxEvent.consume(evt); 3232 }); 3233 } 3234 else if (!noImg && url != null && url.length > 0) 3235 { 3236 var png = preview || (TEMPLATE_PATH + '/' + url.substring(0, url.length - 4) + '.png'); 3237 3238 elt.style.backgroundImage = 'url(' + png + ')'; 3239 elt.style.backgroundPosition = 'center center'; 3240 elt.style.backgroundRepeat = 'no-repeat'; 3241 3242 if (title != null) 3243 { 3244 elt.innerHTML = '<table width="100%" height="100%" style="line-height:1.3em;' + (Editor.isDarkMode() ? '' : 'background:rgba(255,255,255,0.85);') + 3245 'border:inherit;"><tr><td align="center" valign="middle"><span style="display:inline-block;padding:4px 8px 4px 8px;user-select:none;' + 3246 'border-radius:3px;background:rgba(255,255,255,0.85);overflow:hidden;text-overflow:ellipsis;max-width:' + (w - 34) + 'px;">' + 3247 mxUtils.htmlEntities(mxResources.get(title, null, title)) + '</span></td></tr></table>'; 3248 } 3249 3250 function activate(doCreate) 3251 { 3252 createButton.setAttribute('disabled', 'disabled'); 3253 elt.style.backgroundColor = 'transparent'; 3254 elt.style.border = '1px solid transparent'; 3255 spinner.spin(div); 3256 3257 loadXmlData(url, function(xml) 3258 { 3259 spinner.stop(); 3260 3261 if (xml != null) 3262 { 3263 selectElement(elt, xml, libs, null, null, clibs, realUrl); 3264 3265 if (doCreate) 3266 { 3267 create(); 3268 } 3269 } 3270 }); 3271 }; 3272 3273 mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt) 3274 { 3275 activate(); 3276 }), null, null); 3277 3278 mxEvent.addListener(elt, 'dblclick', function(evt) 3279 { 3280 activate(true); 3281 mxEvent.consume(evt); 3282 }); 3283 } 3284 else 3285 { 3286 elt.innerHTML = '<table width="100%" height="100%" style="line-height:1.3em;"><tr>' + 3287 '<td align="center" valign="middle"><span style="display:inline-block;padding:4px 8px 4px 8px;user-select:none;' + 3288 'border-radius:3px;background:#ffffff;overflow:hidden;text-overflow:ellipsis;max-width:' + (w - 34) + 'px;">' + 3289 mxUtils.htmlEntities(mxResources.get(title, null, title)) + '</span></td></tr></table>'; 3290 3291 if (select) 3292 { 3293 selectElement(elt); 3294 } 3295 3296 mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt) 3297 { 3298 selectElement(elt, null, null, url, infoObj); 3299 }), null, null); 3300 3301 if (onClick != null) 3302 { 3303 mxEvent.addListener(elt, 'click', onClick); 3304 } 3305 else 3306 { 3307 mxEvent.addListener(elt, 'click', function(evt) 3308 { 3309 selectElement(elt, null, null, url, infoObj); 3310 }); 3311 3312 mxEvent.addListener(elt, 'dblclick', function(evt) 3313 { 3314 create(); 3315 mxEvent.consume(evt); 3316 }); 3317 } 3318 } 3319 3320 // Adds preview button 3321 if (url != null) 3322 { 3323 var magnify = document.createElement('img'); 3324 magnify.setAttribute('src', Sidebar.prototype.searchImage); 3325 magnify.setAttribute('title', mxResources.get('preview')); 3326 magnify.className = 'geActiveButton'; 3327 magnify.style.position = 'absolute'; 3328 magnify.style.cursor = 'default'; 3329 magnify.style.padding = '8px'; 3330 magnify.style.right = '0px'; 3331 magnify.style.top = '0px'; 3332 elt.appendChild(magnify); 3333 3334 var wasVisible = false; 3335 3336 mxEvent.addGestureListeners(magnify, mxUtils.bind(this, function(evt) 3337 { 3338 wasVisible = editorUi.sidebar.currentElt == elt; 3339 }), null, null); 3340 3341 mxEvent.addListener(magnify, 'click', mxUtils.bind(this, function(evt) 3342 { 3343 if (!wasVisible) 3344 { 3345 loadTooltip(evt, magnify); 3346 } 3347 3348 mxEvent.consume(evt); 3349 })); 3350 } 3351 3352 div.appendChild(elt); 3353 return elt; 3354 }; 3355 3356 var categories = {}, subCategories = {}, customCats = {}; 3357 var customCatCount = 0, firstInitUi = true; 3358 var currentEntry = null, lastEntry = null; 3359 3360 // Adds local basic templates 3361 categories['basic'] = [{title: 'blankDiagram', select: true}]; 3362 var templates = categories['basic']; 3363 3364 function resetTemplates() 3365 { 3366 if (lastEntry != null) 3367 { 3368 lastEntry.click(); 3369 lastEntry = null; 3370 } 3371 }; 3372 3373 function filterTemplates() 3374 { 3375 var searchTerms = tmplSearchInput.value; 3376 3377 if (searchTerms == '') 3378 { 3379 resetTemplates(); 3380 return; 3381 } 3382 3383 if (NewDialog.tagsList[templateFile] == null) 3384 { 3385 var tagsList = {}; 3386 3387 for (var cat in categories) 3388 { 3389 var templateList = categories[cat]; 3390 3391 for (var i = 0; i < templateList.length; i++) 3392 { 3393 var temp = templateList[i]; 3394 3395 if (temp.tags != null) 3396 { 3397 var tags = temp.tags.toLowerCase().split(';'); 3398 3399 for (var j = 0; j < tags.length; j++) 3400 { 3401 if (tagsList[tags[j]] == null) 3402 { 3403 tagsList[tags[j]] = []; 3404 } 3405 3406 tagsList[tags[j]].push(temp); 3407 } 3408 } 3409 } 3410 } 3411 3412 NewDialog.tagsList[templateFile] = tagsList; 3413 } 3414 3415 var tmp = searchTerms.toLowerCase().split(' '); 3416 tagsList = NewDialog.tagsList[templateFile]; 3417 3418 if (customCatCount > 0 && tagsList.__tagsList__ == null) 3419 { 3420 for (var cat in customCats) 3421 { 3422 var templateList = customCats[cat]; 3423 3424 for (var i = 0; i < templateList.length; i++) 3425 { 3426 var temp = templateList[i]; 3427 var tags = temp.title.split(' '); 3428 tags.push(cat); 3429 3430 for (var j = 0; j < tags.length; j++) 3431 { 3432 var tag = tags[j].toLowerCase(); 3433 3434 if (tagsList[tag] == null) 3435 { 3436 tagsList[tag] = []; 3437 } 3438 3439 tagsList[tag].push(temp); 3440 } 3441 } 3442 } 3443 3444 tagsList.__tagsList__ = true; 3445 } 3446 3447 var results = [], resMap = {}, index = 0; 3448 3449 for (var i = 0; i < tmp.length; i++) 3450 { 3451 if (tmp[i].length > 0) 3452 { 3453 var list = tagsList[tmp[i]]; 3454 var tmpResMap = {}; 3455 results = []; 3456 3457 if (list != null) 3458 { 3459 for (var j = 0; j < list.length; j++) 3460 { 3461 var temp = list[j]; 3462 3463 //ANDing terms 3464 if ((index == 0) == (resMap[temp.url] == null)) 3465 { 3466 tmpResMap[temp.url] = true; 3467 results.push(temp); 3468 } 3469 } 3470 } 3471 3472 resMap = tmpResMap; 3473 index++; 3474 } 3475 } 3476 3477 div.scrollTop = 0; 3478 div.innerHTML = ''; 3479 i0 = 0; 3480 var msgDiv = document.createElement('div'); 3481 msgDiv.style.cssText = 'border: 1px solid #D3D3D3; padding: 6px; background: #F5F5F5;'; 3482 mxUtils.write(msgDiv, mxResources.get(results.length == 0 ? 'noResultsFor' : 'resultsFor', [searchTerms])); 3483 div.appendChild(msgDiv); 3484 3485 if (currentEntry != null && lastEntry == null) 3486 { 3487 currentEntry.style.backgroundColor = ''; 3488 lastEntry = currentEntry; 3489 currentEntry = msgDiv; //To prevebt NPE later 3490 } 3491 3492 templates = results; 3493 oldTemplates = null; 3494 addTemplates(false); 3495 }; 3496 3497 function initUi() 3498 { 3499 if (firstInitUi) 3500 { 3501 firstInitUi = false; 3502 3503 mxEvent.addListener(div, 'scroll', function(evt) 3504 { 3505 if (div.scrollTop + div.clientHeight >= div.scrollHeight) 3506 { 3507 addTemplates(); 3508 mxEvent.consume(evt); 3509 } 3510 }); 3511 } 3512 3513 if (customCatCount > 0) 3514 { 3515 var titleCss = 'font-weight: bold;background: #f9f9f9;padding: 5px 0 5px 0;text-align: center;'; 3516 var title = document.createElement('div'); 3517 title.style.cssText = titleCss; 3518 mxUtils.write(title, mxResources.get('custom')); 3519 list.appendChild(title); 3520 3521 for (var cat in customCats) 3522 { 3523 var entry = document.createElement('div'); 3524 var label = cat; 3525 var templateList = customCats[cat]; 3526 3527 if (label.length > 18) 3528 { 3529 label = label.substring(0, 18) + '…'; 3530 } 3531 3532 entry.style.cssText = 'display:block;cursor:pointer;padding:6px;white-space:nowrap;margin-bottom:-1px;overflow:hidden;text-overflow:ellipsis;user-select:none;'; 3533 entry.setAttribute('title', label + ' (' + templateList.length + ')'); 3534 mxUtils.write(entry, entry.getAttribute('title')); 3535 3536 if (itemPadding != null) 3537 { 3538 entry.style.padding = itemPadding; 3539 } 3540 3541 list.appendChild(entry); 3542 3543 (function(cat2, entry2) 3544 { 3545 mxEvent.addListener(entry, 'click', function() 3546 { 3547 if (currentEntry != entry2) 3548 { 3549 currentEntry.style.backgroundColor = ''; 3550 currentEntry = entry2; 3551 currentEntry.style.backgroundColor = leftHighlight; 3552 3553 div.scrollTop = 0; 3554 div.innerHTML = ''; 3555 i0 = 0; 3556 3557 templates = customCats[cat2]; 3558 oldTemplates = null; 3559 addTemplates(false); 3560 } 3561 }); 3562 })(cat, entry); 3563 } 3564 3565 title = document.createElement('div'); 3566 title.style.cssText = titleCss; 3567 mxUtils.write(title, 'draw.io'); 3568 list.appendChild(title); 3569 } 3570 3571 function getEntryTitle(cat, templateList) 3572 { 3573 var label = mxResources.get(cat); 3574 3575 if (label == null) 3576 { 3577 label = cat.substring(0, 1).toUpperCase() + cat.substring(1); 3578 } 3579 3580 if (label.length > 18) 3581 { 3582 label = label.substring(0, 18) + '…'; 3583 } 3584 3585 return label + ' (' + templateList.length + ')'; 3586 }; 3587 3588 function addEntryHandler(cat, entry, subCat) 3589 { 3590 mxEvent.addListener(entry, 'click', function() 3591 { 3592 if (currentEntry != entry) 3593 { 3594 currentEntry.style.backgroundColor = ''; 3595 currentEntry = entry; 3596 currentEntry.style.backgroundColor = leftHighlight; 3597 3598 div.scrollTop = 0; 3599 div.innerHTML = ''; 3600 i0 = 0; 3601 3602 templates = subCat? subCategories[cat][subCat] : categories[cat]; 3603 oldTemplates = null; 3604 addTemplates(false); 3605 } 3606 }); 3607 }; 3608 3609 for (var cat in categories) 3610 { 3611 var subCats = subCategories[cat]; 3612 var entry = document.createElement(subCats? 'ul' : 'div'); 3613 var clickElem = entry; 3614 var templateList = categories[cat]; 3615 var entryTitle = getEntryTitle(cat, templateList); 3616 3617 if (subCats != null) 3618 { 3619 var entryLi = document.createElement('li'); 3620 var entryDiv = document.createElement('div'); 3621 entryDiv.className = 'geTempTreeCaret'; 3622 entryDiv.setAttribute('title', entryTitle); 3623 mxUtils.write(entryDiv, entryTitle); 3624 clickElem = entryDiv; 3625 entryLi.appendChild(entryDiv); 3626 //We support one level deep only 3627 var subUl = document.createElement('ul'); 3628 subUl.className = 'geTempTreeNested'; 3629 subUl.style.visibility = 'hidden'; 3630 3631 for (var subCat in subCats) 3632 { 3633 var subLi = document.createElement('li'); 3634 var subTitle = getEntryTitle(subCat, subCats[subCat]); 3635 subLi.setAttribute('title', subTitle); 3636 mxUtils.write(subLi, subTitle); 3637 addEntryHandler(cat, subLi, subCat); 3638 subUl.appendChild(subLi); 3639 } 3640 3641 entryLi.appendChild(subUl); 3642 entry.className = 'geTempTree'; 3643 entry.appendChild(entryLi); 3644 3645 (function(subUl2, entryDiv2) 3646 { 3647 mxEvent.addListener(entryDiv2, 'click', function() 3648 { 3649 subUl2.style.visibility = 'visible'; 3650 subUl2.classList.toggle('geTempTreeActive'); 3651 3652 if (subUl2.classList.toggle('geTempTreeNested')) 3653 { 3654 //Must hide sub elements to allow click on elements above it 3655 setTimeout(function() 3656 { 3657 subUl2.style.visibility = 'hidden'; 3658 }, 550); 3659 } 3660 3661 entryDiv2.classList.toggle('geTempTreeCaret-down'); 3662 }); 3663 })(subUl, entryDiv); 3664 } 3665 else 3666 { 3667 entry.style.cssText = 'display:block;cursor:pointer;padding:6px;white-space:nowrap;margin-bottom:-1px;overflow:hidden;text-overflow:ellipsis;user-select:none;transition: all 0.5s;'; 3668 entry.setAttribute('title', entryTitle); 3669 mxUtils.write(entry, entryTitle); 3670 } 3671 3672 if (itemPadding != null) 3673 { 3674 entry.style.padding = itemPadding; 3675 } 3676 3677 list.appendChild(entry); 3678 3679 if (currentEntry == null && templateList.length > 0) 3680 { 3681 currentEntry = entry; 3682 currentEntry.style.backgroundColor = leftHighlight; 3683 templates = templateList; 3684 } 3685 3686 addEntryHandler(cat, clickElem); 3687 } 3688 3689 addTemplates(false); 3690 }; 3691 3692 if (!compact) 3693 { 3694 outer.appendChild(searchBox); 3695 outer.appendChild(list); 3696 outer.appendChild(div); 3697 var indexLoaded = false; 3698 var realUrl = templateFile; 3699 3700 if (/^https?:\/\//.test(realUrl) && !editorUi.editor.isCorsEnabledForUrl(realUrl)) 3701 { 3702 realUrl = PROXY_URL + '?url=' + encodeURIComponent(realUrl); 3703 } 3704 3705 function loadDrawioTemplates() 3706 { 3707 mxUtils.get(realUrl, function(req) 3708 { 3709 // Workaround for index loaded 3 times in iOS offline mode 3710 if (!indexLoaded) 3711 { 3712 indexLoaded = true; 3713 var tmpDoc = req.getXml(); 3714 var node = tmpDoc.documentElement.firstChild; 3715 var clibs = {}; 3716 3717 while (node != null) 3718 { 3719 if (typeof(node.getAttribute) !== 'undefined') 3720 { 3721 if (node.nodeName == 'clibs') 3722 { 3723 var name = node.getAttribute('name'); 3724 var adds = node.getElementsByTagName('add'); 3725 var temp = []; 3726 3727 for (var i = 0; i < adds.length; i++) 3728 { 3729 temp.push(encodeURIComponent(mxUtils.getTextContent(adds[i]))); 3730 } 3731 3732 if (name != null && temp.length > 0) 3733 { 3734 clibs[name] = temp.join(';'); 3735 } 3736 } 3737 else 3738 { 3739 var url = node.getAttribute('url'); 3740 3741 if (url != null) 3742 { 3743 var category = node.getAttribute('section'); 3744 var subCategory = node.getAttribute('subsection'); 3745 3746 if (category == null) 3747 { 3748 var slash = url.indexOf('/'); 3749 category = url.substring(0, slash); 3750 3751 if (subCategory == null) 3752 { 3753 var nextSlash = url.indexOf('/', slash + 1); 3754 3755 if (nextSlash > -1) 3756 { 3757 subCategory = url.substring(slash + 1, nextSlash); 3758 } 3759 } 3760 } 3761 3762 var list = categories[category]; 3763 3764 if (list == null) 3765 { 3766 list = []; 3767 categories[category] = list; 3768 } 3769 3770 var tempLibs = node.getAttribute('clibs'); 3771 3772 if (clibs[tempLibs] != null) 3773 { 3774 tempLibs = clibs[tempLibs]; 3775 } 3776 3777 var tempObj = {url: node.getAttribute('url'), libs: node.getAttribute('libs'), 3778 title: node.getAttribute('title'), tooltip: node.getAttribute('name') || node.getAttribute('url'), 3779 preview: node.getAttribute('preview'), clibs: tempLibs, tags: node.getAttribute('tags')}; 3780 list.push(tempObj); 3781 3782 if (subCategory != null) 3783 { 3784 var subCats = subCategories[category]; 3785 3786 if (subCats == null) 3787 { 3788 subCats = {}; 3789 subCategories[category] = subCats; 3790 } 3791 3792 var subCatList = subCats[subCategory]; 3793 3794 if (subCatList == null) 3795 { 3796 subCatList = []; 3797 subCats[subCategory] = subCatList; 3798 } 3799 3800 subCatList.push(tempObj); 3801 } 3802 } 3803 } 3804 } 3805 3806 node = node.nextSibling; 3807 } 3808 3809 3810 spinner.stop(); 3811 initUi(); 3812 } 3813 }); 3814 }; 3815 3816 spinner.spin(div); 3817 3818 if (customTempCallback != null) 3819 { 3820 customTempCallback(function(cats, count) 3821 { 3822 customCats = cats; 3823 customCatCount = count; 3824 //Custom templates doesn't change after being loaded, so cache them here. Also, only count is overridden 3825 origCustomCatCount = count; 3826 3827 loadDrawioTemplates(); 3828 }, 3829 3830 loadDrawioTemplates); //In case of an error, just load draw.io templates only 3831 } 3832 else 3833 { 3834 loadDrawioTemplates(); 3835 } 3836 3837 //draw.io templates doesn't change after being loaded, so cache them here 3838 origCategories = categories; 3839 } 3840 3841 mxEvent.addListener(nameInput, 'keypress', function(e) 3842 { 3843 if (editorUi.dialog.container.firstChild == outer && 3844 e.keyCode == 13) 3845 { 3846 create(); 3847 } 3848 }); 3849 3850 var btns = document.createElement('div'); 3851 btns.style.marginTop = (compact) ? '4px' : '16px'; 3852 btns.style.textAlign = 'right'; 3853 btns.style.position = 'absolute'; 3854 btns.style.left = '40px'; 3855 btns.style.bottom = '24px'; 3856 btns.style.right = '40px'; 3857 3858 if (!compact && !editorUi.isOffline() && showName && callback == null && !createOnly) 3859 { 3860 var helpBtn = mxUtils.button(mxResources.get('help'), function() 3861 { 3862 editorUi.openLink('https://support.draw.io/display/DO/Creating+and+Opening+Files'); 3863 }); 3864 3865 helpBtn.className = 'geBtn'; 3866 btns.appendChild(helpBtn); 3867 } 3868 3869 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 3870 { 3871 if (cancelCallback != null) 3872 { 3873 cancelCallback(); 3874 } 3875 3876 editorUi.hideDialog(true); 3877 }); 3878 3879 cancelBtn.className = 'geBtn'; 3880 3881 if (editorUi.editor.cancelFirst && (!createOnly || cancelCallback != null)) 3882 { 3883 btns.appendChild(cancelBtn); 3884 } 3885 3886 if (!compact && urlParams['embed'] != '1' && !createOnly && 3887 !mxClient.IS_ANDROID && !mxClient.IS_IOS && urlParams['noDevice'] != '1') 3888 { 3889 var fromTmpBtn = mxUtils.button(mxResources.get('fromTemplateUrl'), function() 3890 { 3891 var dlg = new FilenameDialog(editorUi, '', mxResources.get('create'), function(fileUrl) 3892 { 3893 if (fileUrl != null && fileUrl.length > 0) 3894 { 3895 var url = editorUi.getUrl(window.location.pathname + '?mode=' + editorUi.mode + 3896 '&title=' + encodeURIComponent(nameInput.value) + 3897 '&create=' + encodeURIComponent(fileUrl)); 3898 3899 if (editorUi.getCurrentFile() == null) 3900 { 3901 window.location.href = url; 3902 } 3903 else 3904 { 3905 window.openWindow(url); 3906 } 3907 } 3908 }, mxResources.get('url')); 3909 editorUi.showDialog(dlg.container, 300, 80, true, true); 3910 dlg.init(); 3911 }); 3912 fromTmpBtn.className = 'geBtn'; 3913 btns.appendChild(fromTmpBtn); 3914 } 3915 3916 if (Graph.fileSupport && showImport) 3917 { 3918 var importBtn = mxUtils.button(mxResources.get('import'), function() 3919 { 3920 if (editorUi.newDlgFileInputElt == null) 3921 { 3922 var fileInput = document.createElement('input'); 3923 fileInput.setAttribute('multiple', 'multiple'); 3924 fileInput.setAttribute('type', 'file'); 3925 3926 mxEvent.addListener(fileInput, 'change', function(evt) 3927 { 3928 editorUi.openFiles(fileInput.files, true); 3929 fileInput.value = ''; 3930 }); 3931 3932 fileInput.style.display = 'none'; 3933 document.body.appendChild(fileInput); 3934 editorUi.newDlgFileInputElt = fileInput; 3935 } 3936 3937 editorUi.newDlgFileInputElt.click(); 3938 }); 3939 3940 importBtn.className = 'geBtn'; 3941 btns.appendChild(importBtn); 3942 } 3943 3944 btns.appendChild(createButton); 3945 3946 if (!editorUi.editor.cancelFirst && callback == null && (!createOnly || cancelCallback != null)) 3947 { 3948 btns.appendChild(cancelBtn); 3949 } 3950 3951 outer.appendChild(btns); 3952 3953 this.container = outer; 3954}; 3955 3956NewDialog.tagsList = {}; 3957/** 3958 * Constructs a dialog for creating new files from a template URL. 3959 * Also used for dialog choosing where to save or export resources 3960 */ 3961var CreateDialog = function(editorUi, title, createFn, cancelFn, dlgTitle, btnLabel, overrideExtension, allowBrowser, 3962 allowTab, helpLink, showDeviceButton, rowLimit, data, mimeType, base64Encoded, hints, hideDialog) 3963{ 3964 showDeviceButton = urlParams['noDevice'] == '1'? false : showDeviceButton; 3965 overrideExtension = (overrideExtension != null) ? overrideExtension : true; 3966 allowBrowser = (allowBrowser != null) ? allowBrowser : true; 3967 rowLimit = (rowLimit != null) ? rowLimit : 4; 3968 hideDialog = (hideDialog != null) ? hideDialog : true; 3969 3970 var div = document.createElement('div'); 3971 div.style.whiteSpace = 'nowrap'; 3972 3973 var showButtons = true; 3974 3975 if (cancelFn == null) 3976 { 3977 editorUi.addLanguageMenu(div); 3978 } 3979 3980 var h3 = document.createElement('h2'); 3981 mxUtils.write(h3, dlgTitle || mxResources.get('create')); 3982 h3.style.marginTop = '0px'; 3983 h3.style.marginBottom = '24px'; 3984 div.appendChild(h3); 3985 3986 mxUtils.write(div, mxResources.get('filename') + ':'); 3987 3988 var nameInput = document.createElement('input'); 3989 nameInput.setAttribute('value', title); 3990 nameInput.style.width = '200px'; 3991 nameInput.style.marginLeft = '10px'; 3992 nameInput.style.marginBottom = '20px'; 3993 nameInput.style.maxWidth = '70%'; 3994 3995 this.init = function() 3996 { 3997 nameInput.focus(); 3998 3999 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 4000 { 4001 nameInput.select(); 4002 } 4003 else 4004 { 4005 document.execCommand('selectAll', false, null); 4006 } 4007 }; 4008 4009 div.appendChild(nameInput); 4010 4011 if (hints != null) 4012 { 4013 if (editorUi.editor.diagramFileTypes != null) 4014 { 4015 var typeSelect = FilenameDialog.createFileTypes(editorUi, nameInput, editorUi.editor.diagramFileTypes); 4016 typeSelect.style.marginLeft = '6px'; 4017 typeSelect.style.width = '80px'; 4018 div.appendChild(typeSelect); 4019 } 4020 4021 div.appendChild(FilenameDialog.createTypeHint(editorUi, nameInput, hints)); 4022 } 4023 4024 var copyBtn = null; 4025 4026 // Disables SVG preview if SVG is not supported in browser 4027 if (urlParams['noDevice'] != '1' && data != null && mimeType != null && (mimeType.substring(0, 6) == 'image/' && 4028 (mimeType.substring(0, 9) != 'image/svg' || mxClient.IS_SVG))) 4029 { 4030 nameInput.style.width = '160px'; 4031 var preview = document.createElement('img'); 4032 var temp = (base64Encoded) ? data : btoa(unescape(encodeURIComponent(data))); 4033 preview.setAttribute('src', 'data:' + mimeType + ';base64,' + temp); 4034 preview.style.position = 'absolute'; 4035 preview.style.top = '70px'; 4036 preview.style.right = '100px'; 4037 preview.style.maxWidth = '120px'; 4038 preview.style.maxHeight = '80px'; 4039 mxUtils.setPrefixedStyle(preview.style, 'transform', 4040 'translate(50%,-50%)'); 4041 div.appendChild(preview); 4042 4043 if (!mxClient.IS_FF && navigator.clipboard != null && mimeType == 'image/png') 4044 { 4045 copyBtn = mxUtils.button(mxResources.get('copy'), function(evt) 4046 { 4047 var blob = editorUi.base64ToBlob(temp, 'image/png'); 4048 var html = '<img src="' + 'data:' + mimeType + ';base64,' + temp + '">'; 4049 var cbi = new ClipboardItem({'image/png': blob, 4050 'text/html': new Blob([html], {type: 'text/html'})}); 4051 navigator.clipboard.write([cbi]).then(mxUtils.bind(this, function() 4052 { 4053 editorUi.alert(mxResources.get('copiedToClipboard')); 4054 }))['catch'](mxUtils.bind(this, function(e) 4055 { 4056 editorUi.handleError(e); 4057 })); 4058 }); 4059 4060 copyBtn.style.marginTop = '6px'; 4061 copyBtn.className = 'geBtn'; 4062 } 4063 4064 if (allowTab && Editor.popupsAllowed) 4065 { 4066 preview.style.cursor = 'pointer'; 4067 4068 mxEvent.addGestureListeners(preview, null, null, function(evt) 4069 { 4070 if (!mxEvent.isPopupTrigger(evt)) 4071 { 4072 create('_blank'); 4073 } 4074 }); 4075 } 4076 } 4077 4078 mxUtils.br(div); 4079 4080 var buttons = document.createElement('div'); 4081 buttons.style.textAlign = 'center'; 4082 var count = 0; 4083 4084 function addLogo(img, title, mode, clientName) 4085 { 4086 var button = document.createElement('a'); 4087 button.style.overflow = 'hidden'; 4088 4089 var logo = document.createElement('img'); 4090 logo.src = img; 4091 logo.setAttribute('border', '0'); 4092 logo.setAttribute('align', 'absmiddle'); 4093 logo.style.width = '60px'; 4094 logo.style.height = '60px'; 4095 logo.style.paddingBottom = '6px'; 4096 button.style.display = 'inline-block'; 4097 button.className = 'geBaseButton'; 4098 button.style.position = 'relative'; 4099 button.style.margin = '4px'; 4100 button.style.padding = '8px 8px 10px 8px'; 4101 button.style.whiteSpace = 'nowrap'; 4102 4103 button.appendChild(logo); 4104 4105 button.style.color = 'gray'; 4106 button.style.fontSize = '11px'; 4107 4108 var label = document.createElement('div'); 4109 button.appendChild(label); 4110 mxUtils.write(label, title); 4111 4112 function initButton() 4113 { 4114 mxEvent.addListener(button, 'click', function() 4115 { 4116 // Updates extension 4117 change(mode); 4118 create(mode); 4119 }); 4120 }; 4121 4122 // Supports lazy loading 4123 if (clientName != null && editorUi[clientName] == null) 4124 { 4125 logo.style.visibility = 'hidden'; 4126 mxUtils.setOpacity(label, 10); 4127 var size = 12; 4128 4129 var spinner = new Spinner({ 4130 lines: 12, // The number of lines to draw 4131 length: size, // The length of each line 4132 width: 5, // The line thickness 4133 radius: 10, // The radius of the inner circle 4134 rotate: 0, // The rotation offset 4135 color: '#000', // #rgb or #rrggbb 4136 speed: 1.5, // Rounds per second 4137 trail: 60, // Afterglow percentage 4138 shadow: false, // Whether to render a shadow 4139 hwaccel: false, // Whether to use hardware acceleration 4140 top: '40%', 4141 zIndex: 2e9 // The z-index (defaults to 2000000000) 4142 }); 4143 spinner.spin(button); 4144 4145 // Timeout after 30 secs 4146 var timeout = window.setTimeout(function() 4147 { 4148 if (editorUi[clientName] == null) 4149 { 4150 spinner.stop(); 4151 button.style.display = 'none'; 4152 } 4153 }, 30000); 4154 4155 editorUi.addListener('clientLoaded', mxUtils.bind(this, function() 4156 { 4157 if (editorUi[clientName] != null) 4158 { 4159 window.clearTimeout(timeout); 4160 mxUtils.setOpacity(label, 100); 4161 logo.style.visibility = ''; 4162 spinner.stop(); 4163 initButton(); 4164 } 4165 })); 4166 } 4167 else 4168 { 4169 initButton(); 4170 } 4171 4172 buttons.appendChild(button); 4173 4174 if (++count == rowLimit) 4175 { 4176 mxUtils.br(buttons); 4177 count = 0; 4178 } 4179 }; 4180 4181 if (!showButtons) 4182 { 4183 mxUtils.write(div, mxResources.get('chooseAnOption') + ':'); 4184 } 4185 else 4186 { 4187 buttons.style.marginTop = '6px'; 4188 div.appendChild(buttons); 4189 } 4190 4191 // Adds all papersize options 4192 var serviceSelect = document.createElement('select'); 4193 serviceSelect.style.marginLeft = '10px'; 4194 4195 if (!editorUi.isOfflineApp() && !editorUi.isOffline()) 4196 { 4197 if (typeof window.DriveClient === 'function') 4198 { 4199 var googleOption = document.createElement('option'); 4200 googleOption.setAttribute('value', App.MODE_GOOGLE); 4201 mxUtils.write(googleOption, mxResources.get('googleDrive')); 4202 serviceSelect.appendChild(googleOption); 4203 4204 addLogo(IMAGE_PATH + '/google-drive-logo.svg', mxResources.get('googleDrive'), App.MODE_GOOGLE, 'drive'); 4205 } 4206 4207 if (typeof window.OneDriveClient === 'function') 4208 { 4209 var oneDriveOption = document.createElement('option'); 4210 oneDriveOption.setAttribute('value', App.MODE_ONEDRIVE); 4211 mxUtils.write(oneDriveOption, mxResources.get('oneDrive')); 4212 serviceSelect.appendChild(oneDriveOption); 4213 4214 if (editorUi.mode == App.MODE_ONEDRIVE) 4215 { 4216 oneDriveOption.setAttribute('selected', 'selected'); 4217 } 4218 4219 addLogo(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), App.MODE_ONEDRIVE, 'oneDrive'); 4220 } 4221 4222 if (typeof window.DropboxClient === 'function') 4223 { 4224 var dropboxOption = document.createElement('option'); 4225 dropboxOption.setAttribute('value', App.MODE_DROPBOX); 4226 mxUtils.write(dropboxOption, mxResources.get('dropbox')); 4227 serviceSelect.appendChild(dropboxOption); 4228 4229 if (editorUi.mode == App.MODE_DROPBOX) 4230 { 4231 dropboxOption.setAttribute('selected', 'selected'); 4232 } 4233 4234 addLogo(IMAGE_PATH + '/dropbox-logo.svg', mxResources.get('dropbox'), App.MODE_DROPBOX, 'dropbox'); 4235 } 4236 4237 if (editorUi.gitHub != null) 4238 { 4239 var gitHubOption = document.createElement('option'); 4240 gitHubOption.setAttribute('value', App.MODE_GITHUB); 4241 mxUtils.write(gitHubOption, mxResources.get('github')); 4242 serviceSelect.appendChild(gitHubOption); 4243 4244 addLogo(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), App.MODE_GITHUB, 'gitHub'); 4245 } 4246 4247 if (editorUi.gitLab != null) 4248 { 4249 var gitLabOption = document.createElement('option'); 4250 gitLabOption.setAttribute('value', App.MODE_GITLAB); 4251 mxUtils.write(gitLabOption, mxResources.get('gitlab')); 4252 serviceSelect.appendChild(gitLabOption); 4253 4254 addLogo(IMAGE_PATH + '/gitlab-logo.svg', mxResources.get('gitlab'), App.MODE_GITLAB, 'gitLab'); 4255 } 4256 4257 if (editorUi.notion != null) 4258 { 4259 var notionOption = document.createElement('option'); 4260 notionOption.setAttribute('value', App.MODE_NOTION); 4261 mxUtils.write(notionOption, mxResources.get('notion')); 4262 serviceSelect.appendChild(notionOption); 4263 4264 addLogo(IMAGE_PATH + '/notion-logo.svg', mxResources.get('notion'), App.MODE_NOTION, 'notion'); 4265 } 4266 4267 if (typeof window.TrelloClient === 'function') 4268 { 4269 var trelloOption = document.createElement('option'); 4270 trelloOption.setAttribute('value', App.MODE_TRELLO); 4271 mxUtils.write(trelloOption, mxResources.get('trello')); 4272 serviceSelect.appendChild(trelloOption); 4273 4274 addLogo(IMAGE_PATH + '/trello-logo.svg', mxResources.get('trello'), App.MODE_TRELLO, 'trello'); 4275 } 4276 } 4277 4278 if (!Editor.useLocalStorage || urlParams['storage'] == 'device' || 4279 (editorUi.getCurrentFile() != null/* && !mxClient.IS_IOS*/ && urlParams['noDevice'] != '1')) 4280 { 4281 var deviceOption = document.createElement('option'); 4282 deviceOption.setAttribute('value', App.MODE_DEVICE); 4283 mxUtils.write(deviceOption, mxResources.get('device')); 4284 serviceSelect.appendChild(deviceOption); 4285 4286 if (editorUi.mode == App.MODE_DEVICE || !allowBrowser) 4287 { 4288 deviceOption.setAttribute('selected', 'selected'); 4289 } 4290 4291 if (showDeviceButton) 4292 { 4293 addLogo(IMAGE_PATH + '/osa_drive-harddisk.png', mxResources.get('device'), App.MODE_DEVICE); 4294 } 4295 } 4296 4297 if (allowBrowser && isLocalStorage && urlParams['browser'] != '0') 4298 { 4299 var browserOption = document.createElement('option'); 4300 browserOption.setAttribute('value', App.MODE_BROWSER); 4301 mxUtils.write(browserOption, mxResources.get('browser')); 4302 serviceSelect.appendChild(browserOption); 4303 4304 if (editorUi.mode == App.MODE_BROWSER) 4305 { 4306 browserOption.setAttribute('selected', 'selected'); 4307 } 4308 4309 addLogo(IMAGE_PATH + '/osa_database.png', mxResources.get('browser'), App.MODE_BROWSER); 4310 } 4311 4312 function change(newMode) 4313 { 4314 if (overrideExtension) 4315 { 4316 var fn = nameInput.value; 4317 var idx = fn.lastIndexOf('.'); 4318 4319 if (title.lastIndexOf('.') < 0 && (!showButtons || idx < 0)) 4320 { 4321 newMode = (newMode != null) ? newMode : serviceSelect.value; 4322 var ext = ''; 4323 4324 if (newMode == App.MODE_GOOGLE) 4325 { 4326 ext = editorUi.drive.extension; 4327 } 4328 else if (newMode == App.MODE_GITHUB) 4329 { 4330 ext = editorUi.gitHub.extension; 4331 } 4332 else if (newMode == App.MODE_GITLAB) 4333 { 4334 ext = editorUi.gitLab.extension; 4335 } 4336 else if (newMode == App.MODE_NOTION) 4337 { 4338 ext = editorUi.notion.extension; 4339 } 4340 else if (newMode == App.MODE_TRELLO) 4341 { 4342 ext = editorUi.trello.extension; 4343 } 4344 else if (newMode == App.MODE_DROPBOX) 4345 { 4346 ext = editorUi.dropbox.extension; 4347 } 4348 else if (newMode == App.MODE_ONEDRIVE) 4349 { 4350 ext = editorUi.oneDrive.extension; 4351 } 4352 else if (newMode == App.MODE_DEVICE) 4353 { 4354 ext = '.drawio'; 4355 } 4356 4357 if (idx >= 0) 4358 { 4359 fn = fn.substring(0, idx); 4360 } 4361 4362 nameInput.value = fn + ext; 4363 } 4364 } 4365 }; 4366 4367 var btns = document.createElement('div'); 4368 btns.style.marginTop = (showButtons) ? '26px' : '38px'; 4369 btns.style.textAlign = 'center'; 4370 4371 if (!showButtons) 4372 { 4373 div.appendChild(serviceSelect); 4374 mxEvent.addListener(serviceSelect, 'change', change); 4375 change(); 4376 } 4377 4378 if (helpLink != null) 4379 { 4380 var helpBtn = mxUtils.button(mxResources.get('help'), function() 4381 { 4382 editorUi.openLink(helpLink); 4383 }); 4384 4385 helpBtn.className = 'geBtn'; 4386 btns.appendChild(helpBtn); 4387 } 4388 4389 var cancelBtn = mxUtils.button(mxResources.get((cancelFn != null) ? 'close' : 'cancel'), function() 4390 { 4391 if (cancelFn != null) 4392 { 4393 cancelFn(); 4394 } 4395 else 4396 { 4397 editorUi.fileLoaded(null); 4398 editorUi.hideDialog(); 4399 window.close(); 4400 window.location.href = editorUi.getUrl(); 4401 } 4402 }); 4403 4404 cancelBtn.className = 'geBtn'; 4405 4406 if (editorUi.editor.cancelFirst && cancelFn == null) 4407 { 4408 btns.appendChild(cancelBtn); 4409 } 4410 4411 function create(mode) 4412 { 4413 var title = nameInput.value; 4414 4415 if (mode == null || (title != null && title.length > 0)) 4416 { 4417 if (hideDialog) 4418 { 4419 editorUi.hideDialog(); 4420 } 4421 4422 createFn(title, mode, nameInput); 4423 }; 4424 } 4425 4426 if (cancelFn == null) 4427 { 4428 var laterBtn = mxUtils.button(mxResources.get('decideLater'), function() 4429 { 4430 create(null); 4431 }); 4432 4433 laterBtn.className = 'geBtn'; 4434 btns.appendChild(laterBtn); 4435 } 4436 4437 if (allowTab && Editor.popupsAllowed) 4438 { 4439 var openBtn = mxUtils.button(mxResources.get('openInNewWindow'), function() 4440 { 4441 create('_blank'); 4442 }); 4443 4444 openBtn.className = 'geBtn'; 4445 btns.appendChild(openBtn); 4446 } 4447 4448 if (CreateDialog.showDownloadButton) 4449 { 4450 var downloadButton = mxUtils.button(mxResources.get('download'), function() 4451 { 4452 create('download'); 4453 }); 4454 4455 downloadButton.className = 'geBtn'; 4456 btns.appendChild(downloadButton); 4457 4458 if (copyBtn != null) 4459 { 4460 downloadButton.style.marginTop = '6px'; 4461 btns.style.marginTop = '6px'; 4462 } 4463 } 4464 4465 if (copyBtn != null) 4466 { 4467 mxUtils.br(btns); 4468 btns.appendChild(copyBtn); 4469 } 4470 4471 if (/*!mxClient.IS_IOS || */!showButtons) 4472 { 4473 var createBtn = mxUtils.button(btnLabel || mxResources.get('create'), function() 4474 { 4475 create((showDeviceButton) ? 'download' : ((showButtons) ? App.MODE_DEVICE : serviceSelect.value)); 4476 }); 4477 4478 createBtn.className = 'geBtn gePrimaryBtn'; 4479 btns.appendChild(createBtn); 4480 } 4481 4482 if (!editorUi.editor.cancelFirst || cancelFn != null) 4483 { 4484 btns.appendChild(cancelBtn); 4485 } 4486 4487 mxEvent.addListener(nameInput, 'keypress', function(e) 4488 { 4489 if (e.keyCode == 13) 4490 { 4491 create((showButtons) ? App.MODE_DEVICE : serviceSelect.value); 4492 } 4493 else if (e.keyCode == 27) 4494 { 4495 editorUi.fileLoaded(null); 4496 editorUi.hideDialog(); 4497 window.close(); 4498 } 4499 }); 4500 4501 div.appendChild(btns); 4502 4503 this.container = div; 4504}; 4505 4506/** 4507 * 4508 */ 4509CreateDialog.showDownloadButton = urlParams['noDevice'] != '1'; 4510 4511/** 4512 * Constructs a new popup dialog. 4513 */ 4514var PopupDialog = function(editorUi, url, pre, fallback, hideDialog) 4515{ 4516 hideDialog = (hideDialog != null) ? hideDialog : true; 4517 4518 var div = document.createElement('div'); 4519 div.style.textAlign = 'left'; 4520 div.style.height = '100%'; 4521 4522 mxUtils.write(div, mxResources.get('fileOpenLocation')); 4523 mxUtils.br(div); 4524 mxUtils.br(div); 4525 4526 var replaceBtn = mxUtils.button(mxResources.get('openInThisWindow'), function() 4527 { 4528 if (hideDialog) 4529 { 4530 editorUi.hideDialog(); 4531 } 4532 4533 if (fallback != null) 4534 { 4535 fallback(); 4536 } 4537 }); 4538 replaceBtn.className = 'geBtn'; 4539 replaceBtn.style.marginBottom = '8px'; 4540 replaceBtn.style.width = '280px'; 4541 div.appendChild(replaceBtn); 4542 4543 mxUtils.br(div); 4544 4545 var wndBtn = mxUtils.button(mxResources.get('openInNewWindow'), function() 4546 { 4547 if (hideDialog) 4548 { 4549 editorUi.hideDialog(); 4550 } 4551 4552 if (pre != null) 4553 { 4554 pre(); 4555 } 4556 4557 editorUi.openLink(url, null, true); 4558 }); 4559 wndBtn.className = 'geBtn gePrimaryBtn'; 4560 wndBtn.style.width = replaceBtn.style.width; 4561 div.appendChild(wndBtn); 4562 4563 mxUtils.br(div); 4564 mxUtils.br(div); 4565 mxUtils.write(div, mxResources.get('allowPopups')); 4566 4567 this.container = div; 4568}; 4569 4570/** 4571 * Constructs a new image dialog. 4572 */ 4573var ImageDialog = function(editorUi, title, initialValue, fn, ignoreExisting, convertDataUri) 4574{ 4575 convertDataUri = (convertDataUri != null) ? convertDataUri : true; 4576 4577 var graph = editorUi.editor.graph; 4578 var div = document.createElement('div'); 4579 mxUtils.write(div, title); 4580 4581 var inner = document.createElement('div'); 4582 inner.className = 'geTitle'; 4583 inner.style.backgroundColor = 'transparent'; 4584 inner.style.borderColor = 'transparent'; 4585 inner.style.whiteSpace = 'nowrap'; 4586 inner.style.textOverflow = 'clip'; 4587 inner.style.cursor = 'default'; 4588 inner.style.paddingRight = '20px'; 4589 4590 var linkInput = document.createElement('input'); 4591 linkInput.setAttribute('value', initialValue); 4592 linkInput.setAttribute('type', 'text'); 4593 linkInput.setAttribute('spellcheck', 'false'); 4594 linkInput.setAttribute('autocorrect', 'off'); 4595 linkInput.setAttribute('autocomplete', 'off'); 4596 linkInput.setAttribute('autocapitalize', 'off'); 4597 linkInput.style.marginTop = '6px'; 4598 var realWidth = (Graph.fileSupport) ? 460 : 340; 4599 linkInput.style.width = realWidth - 20 + 'px'; 4600 linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')'; 4601 linkInput.style.backgroundRepeat = 'no-repeat'; 4602 linkInput.style.backgroundPosition = '100% 50%'; 4603 linkInput.style.paddingRight = '14px'; 4604 4605 var cross = document.createElement('div'); 4606 cross.setAttribute('title', mxResources.get('reset')); 4607 cross.style.position = 'relative'; 4608 cross.style.left = '-16px'; 4609 cross.style.width = '12px'; 4610 cross.style.height = '14px'; 4611 cross.style.cursor = 'pointer'; 4612 4613 // Workaround for inline-block not supported in IE 4614 cross.style.display = 'inline-block'; 4615 cross.style.top = '3px'; 4616 4617 // Needed to block event transparency in IE 4618 cross.style.background = 'url(\'' + editorUi.editor.transparentImage + '\')'; 4619 4620 mxEvent.addListener(cross, 'click', function() 4621 { 4622 linkInput.value = ''; 4623 linkInput.focus(); 4624 }); 4625 4626 inner.appendChild(linkInput); 4627 inner.appendChild(cross); 4628 div.appendChild(inner); 4629 4630 var insertImage = function(newValue, w, h, resize) 4631 { 4632 var dataUri = newValue.substring(0, 5) == 'data:'; 4633 4634 if (!editorUi.isOffline() || (dataUri && typeof chrome === 'undefined')) 4635 { 4636 if (newValue.length > 0 && editorUi.spinner.spin(document.body, mxResources.get('inserting'))) 4637 { 4638 var maxSize = 520; 4639 4640 editorUi.loadImage(newValue, function(img) 4641 { 4642 editorUi.spinner.stop(); 4643 editorUi.hideDialog(); 4644 var s = (resize === false) ? 1 : 4645 (w != null && h != null) ? Math.max(w / img.width, h / img.height) : 4646 Math.min(1, Math.min(maxSize / img.width, maxSize / img.height)); 4647 4648 // Handles special case of data URI which needs to be rewritten 4649 // to be used in a cell style to remove the semicolon 4650 if (convertDataUri) 4651 { 4652 newValue = editorUi.convertDataUri(newValue); 4653 } 4654 4655 fn(newValue, Math.round(Number(img.width) * s), Math.round(Number(img.height) * s)); 4656 }, function() 4657 { 4658 editorUi.spinner.stop(); 4659 fn(null); 4660 editorUi.showError(mxResources.get('error'), mxResources.get('fileNotFound'), mxResources.get('ok')); 4661 }); 4662 } 4663 else 4664 { 4665 editorUi.hideDialog(); 4666 fn(newValue); 4667 } 4668 } 4669 else 4670 { 4671 newValue = editorUi.convertDataUri(newValue); 4672 w = (w == null) ? 120 : w; 4673 h = (h == null) ? 100 : h; 4674 4675 editorUi.hideDialog(); 4676 fn(newValue, w, h); 4677 } 4678 }; 4679 4680 var apply = function(newValue, resize) 4681 { 4682 if (newValue != null) 4683 { 4684 var geo = (ignoreExisting) ? null : graph.getModel().getGeometry(graph.getSelectionCell()); 4685 4686 // Reuses width and height of existing cell 4687 if (geo != null) 4688 { 4689 insertImage(newValue, geo.width, geo.height, resize); 4690 } 4691 else 4692 { 4693 insertImage(newValue, null, null, resize); 4694 } 4695 } 4696 else 4697 { 4698 editorUi.hideDialog(); 4699 fn(null); 4700 } 4701 }; 4702 4703 this.init = function() 4704 { 4705 linkInput.focus(); 4706 4707 // Installs drag and drop handler for local images and links 4708 if (Graph.fileSupport) 4709 { 4710 linkInput.setAttribute('placeholder', mxResources.get('dragImagesHere')); 4711 4712 // Setup the dnd listeners 4713 var dlg = div.parentNode; 4714 var graph = editorUi.editor.graph; 4715 var dropElt = null; 4716 4717 mxEvent.addListener(dlg, 'dragleave', function(evt) 4718 { 4719 if (dropElt != null) 4720 { 4721 dropElt.parentNode.removeChild(dropElt); 4722 dropElt = null; 4723 } 4724 4725 evt.stopPropagation(); 4726 evt.preventDefault(); 4727 }); 4728 4729 mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt) 4730 { 4731 // IE 10 does not implement pointer-events so it can't have a drop highlight 4732 if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10)) 4733 { 4734 dropElt = editorUi.highlightElement(dlg); 4735 } 4736 4737 evt.stopPropagation(); 4738 evt.preventDefault(); 4739 })); 4740 4741 mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt) 4742 { 4743 if (dropElt != null) 4744 { 4745 dropElt.parentNode.removeChild(dropElt); 4746 dropElt = null; 4747 } 4748 4749 if (evt.dataTransfer.files.length > 0) 4750 { 4751 editorUi.importFiles(evt.dataTransfer.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h, fileName, resize) 4752 { 4753 apply(data, resize); 4754 }, function() 4755 { 4756 // No post processing 4757 }, function(file) 4758 { 4759 // Handles only images 4760 return file.type.substring(0, 6) == 'image/'; 4761 }, function(queue) 4762 { 4763 // Invokes elements of queue in order 4764 for (var i = 0; i < queue.length; i++) 4765 { 4766 queue[i](); 4767 } 4768 }, !mxEvent.isControlDown(evt), null, null, true); 4769 } 4770 else if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0) 4771 { 4772 var uri = evt.dataTransfer.getData('text/uri-list'); 4773 4774 if ((/\.(gif|jpg|jpeg|tiff|png|svg)($|\?)/i).test(uri)) 4775 { 4776 apply(decodeURIComponent(uri)); 4777 } 4778 } 4779 4780 evt.stopPropagation(); 4781 evt.preventDefault(); 4782 }), false); 4783 } 4784 }; 4785 4786 var btns = document.createElement('div'); 4787 btns.style.marginTop = '14px'; 4788 btns.style.textAlign = 'center'; 4789 4790 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 4791 { 4792 // Just in case a spinner is spinning, has no effect otherwise 4793 editorUi.spinner.stop(); 4794 editorUi.hideDialog(); 4795 }); 4796 4797 cancelBtn.className = 'geBtn'; 4798 4799 if (editorUi.editor.cancelFirst) 4800 { 4801 btns.appendChild(cancelBtn); 4802 } 4803 4804 ImageDialog.filePicked = function(data) 4805 { 4806 if (data.action == google.picker.Action.PICKED) 4807 { 4808 if (data.docs[0].thumbnails != null) 4809 { 4810 var thumb = data.docs[0].thumbnails[data.docs[0].thumbnails.length - 1]; 4811 4812 if (thumb != null) 4813 { 4814 linkInput.value = thumb.url; 4815 } 4816 } 4817 } 4818 4819 linkInput.focus(); 4820 }; 4821 4822 if (Graph.fileSupport) 4823 { 4824 if (editorUi.imgDlgFileInputElt == null) 4825 { 4826 var fileInput = document.createElement('input'); 4827 fileInput.setAttribute('multiple', 'multiple'); 4828 fileInput.setAttribute('type', 'file'); 4829 4830 mxEvent.addListener(fileInput, 'change', function(evt) 4831 { 4832 if (fileInput.files != null) 4833 { 4834 editorUi.importFiles(fileInput.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h) 4835 { 4836 apply(data); 4837 }, function() 4838 { 4839 // No post processing 4840 }, function(file) 4841 { 4842 // Handles only images 4843 return file.type.substring(0, 6) == 'image/'; 4844 }, function(queue) 4845 { 4846 // Invokes elements of queue in order 4847 for (var i = 0; i < queue.length; i++) 4848 { 4849 queue[i](); 4850 } 4851 }, true); 4852 4853 // Resets input to force change event for same file (type reset required for IE) 4854 fileInput.type = ''; 4855 fileInput.type = 'file'; 4856 fileInput.value = ''; 4857 } 4858 }); 4859 4860 fileInput.style.display = 'none'; 4861 document.body.appendChild(fileInput); 4862 editorUi.imgDlgFileInputElt = fileInput; 4863 } 4864 4865 var btn = mxUtils.button(mxResources.get('open'), function() 4866 { 4867 editorUi.imgDlgFileInputElt.click(); 4868 }); 4869 4870 btn.className = 'geBtn'; 4871 btns.appendChild(btn); 4872 } 4873 4874 // Image cropping (experimental) 4875 if (!!document.createElement('canvas').getContext && linkInput.value.substring(0, 11) == 'data:image/' && 4876 linkInput.value.substring(0, 14) != 'data:image/svg') 4877 { 4878 var cropBtn = mxUtils.button(mxResources.get('crop'), function() 4879 { 4880 var dlg = new CropImageDialog(editorUi, linkInput.value, function(image) 4881 { 4882 linkInput.value = image; 4883 }); 4884 4885 editorUi.showDialog(dlg.container, 300, 380, true, true); 4886 dlg.init(); 4887 }); 4888 4889 cropBtn.className = 'geBtn'; 4890 btns.appendChild(cropBtn); 4891 } 4892 4893 mxEvent.addListener(linkInput, 'keypress', function(e) 4894 { 4895 if (e.keyCode == 13) 4896 { 4897 apply(linkInput.value); 4898 } 4899 }); 4900 4901 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 4902 { 4903 apply(linkInput.value); 4904 }); 4905 4906 applyBtn.className = 'geBtn gePrimaryBtn'; 4907 btns.appendChild(applyBtn); 4908 4909 if (!editorUi.editor.cancelFirst) 4910 { 4911 btns.appendChild(cancelBtn); 4912 } 4913 4914 // Shows drop icon in dialog background 4915 if (Graph.fileSupport) 4916 { 4917 btns.style.marginTop = '120px'; 4918 div.style.backgroundImage = 'url(\'' + IMAGE_PATH + '/droptarget.png\')'; 4919 div.style.backgroundPosition = 'center 65%'; 4920 div.style.backgroundRepeat = 'no-repeat'; 4921 4922 var bg = document.createElement('div'); 4923 bg.style.position = 'absolute'; 4924 bg.style.width = '420px'; 4925 bg.style.top = '58%'; 4926 bg.style.textAlign = 'center'; 4927 bg.style.fontSize = '18px'; 4928 bg.style.color = '#a0c3ff'; 4929 mxUtils.write(bg, mxResources.get('dragImagesHere')); 4930 div.appendChild(bg); 4931 } 4932 4933 div.appendChild(btns); 4934 4935 this.container = div; 4936}; 4937 4938/** 4939 * Overrides link dialog to add Google Picker. 4940 */ 4941var LinkDialog = function(editorUi, initialValue, btnLabel, fn, showPages, showNewWindowOption, linkTarget) 4942{ 4943 var div = document.createElement('div'); 4944 div.style.height = '100%'; 4945 mxUtils.write(div, mxResources.get('editLink') + ':'); 4946 4947 var inner = document.createElement('div'); 4948 inner.className = 'geTitle'; 4949 inner.style.backgroundColor = 'transparent'; 4950 inner.style.borderColor = 'transparent'; 4951 inner.style.whiteSpace = 'nowrap'; 4952 inner.style.textOverflow = 'clip'; 4953 inner.style.cursor = 'default'; 4954 inner.style.paddingRight = '20px'; 4955 4956 var linkInput = document.createElement('input'); 4957 linkInput.setAttribute('placeholder', mxResources.get('dragUrlsHere')); 4958 linkInput.setAttribute('type', 'text'); 4959 linkInput.style.marginTop = '6px'; 4960 linkInput.style.width = '100%'; 4961 linkInput.style.boxSizing = 'border-box'; 4962 linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')'; 4963 linkInput.style.backgroundRepeat = 'no-repeat'; 4964 linkInput.style.backgroundPosition = '100% 50%'; 4965 linkInput.style.paddingRight = '14px'; 4966 linkInput.style.marginBottom = '4px'; 4967 4968 var cross = document.createElement('div'); 4969 cross.setAttribute('title', mxResources.get('reset')); 4970 cross.style.position = 'relative'; 4971 cross.style.left = '-16px'; 4972 cross.style.width = '12px'; 4973 cross.style.height = '14px'; 4974 cross.style.cursor = 'pointer'; 4975 4976 // Workaround for inline-block not supported in IE 4977 cross.style.display = 'inline-block'; 4978 cross.style.top = '3px'; 4979 4980 // Needed to block event transparency in IE 4981 cross.style.background = 'url(\'' + editorUi.editor.transparentImage + '\')'; 4982 4983 mxEvent.addListener(cross, 'click', function() 4984 { 4985 linkInput.value = ''; 4986 linkInput.focus(); 4987 }); 4988 4989 var urlRadio = document.createElement('input'); 4990 urlRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 4991 urlRadio.setAttribute('value', 'url'); 4992 urlRadio.setAttribute('type', 'radio'); 4993 urlRadio.setAttribute('name', 'geLinkDialogOption'); 4994 4995 var pageRadio = document.createElement('input'); 4996 pageRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 4997 pageRadio.setAttribute('value', 'url'); 4998 pageRadio.setAttribute('type', 'radio'); 4999 pageRadio.setAttribute('name', 'geLinkDialogOption'); 5000 5001 var pageSelect = document.createElement('select'); 5002 pageSelect.style.width = '520px'; 5003 5004 var newWindowCheckbox = document.createElement('input'); 5005 newWindowCheckbox.setAttribute('type', 'checkbox'); 5006 5007 newWindowCheckbox.style.margin = '0 6p 0 6px'; 5008 5009 if (linkTarget != null) 5010 { 5011 newWindowCheckbox.setAttribute('checked', 'checked'); 5012 newWindowCheckbox.defaultChecked = true; 5013 } 5014 5015 linkTarget = (linkTarget != null) ? linkTarget : '_blank'; 5016 newWindowCheckbox.setAttribute('title', linkTarget); 5017 5018 if (showNewWindowOption) 5019 { 5020 linkInput.style.width = '340px'; 5021 } 5022 5023 if (showPages && editorUi.pages != null) 5024 { 5025 if (initialValue != null && Graph.isPageLink(initialValue)) 5026 { 5027 pageRadio.setAttribute('checked', 'checked'); 5028 pageRadio.defaultChecked = true; 5029 } 5030 else 5031 { 5032 linkInput.setAttribute('value', initialValue); 5033 urlRadio.setAttribute('checked', 'checked'); 5034 urlRadio.defaultChecked = true; 5035 } 5036 5037 inner.appendChild(urlRadio); 5038 inner.appendChild(linkInput); 5039 inner.appendChild(cross); 5040 5041 if (showNewWindowOption) 5042 { 5043 inner.appendChild(newWindowCheckbox); 5044 mxUtils.write(inner, mxResources.get('openInNewWindow')); 5045 } 5046 5047 mxUtils.br(inner); 5048 inner.appendChild(pageRadio); 5049 5050 var pageFound = false; 5051 5052 for (var i = 0; i < editorUi.pages.length; i++) 5053 { 5054 var pageOption = document.createElement('option'); 5055 mxUtils.write(pageOption, editorUi.pages[i].getName() || 5056 mxResources.get('pageWithNumber', [i + 1])); 5057 pageOption.setAttribute('value', 'data:page/id,' + 5058 editorUi.pages[i].getId()); 5059 5060 if (initialValue == pageOption.getAttribute('value')) 5061 { 5062 pageOption.setAttribute('selected', 'selected'); 5063 pageFound = true; 5064 } 5065 5066 pageSelect.appendChild(pageOption); 5067 } 5068 5069 if (!pageFound && pageRadio.checked) 5070 { 5071 var notFoundOption = document.createElement('option'); 5072 mxUtils.write(notFoundOption, mxResources.get('pageNotFound')); 5073 notFoundOption.setAttribute('disabled', 'disabled'); 5074 notFoundOption.setAttribute('selected', 'selected'); 5075 notFoundOption.setAttribute('value', 'pageNotFound'); 5076 pageSelect.appendChild(notFoundOption); 5077 5078 mxEvent.addListener(pageSelect, 'change', function() 5079 { 5080 if (notFoundOption.parentNode != null && !notFoundOption.selected) 5081 { 5082 notFoundOption.parentNode.removeChild(notFoundOption); 5083 } 5084 }); 5085 } 5086 5087 inner.appendChild(pageSelect); 5088 } 5089 else 5090 { 5091 linkInput.setAttribute('value', initialValue); 5092 inner.appendChild(linkInput); 5093 inner.appendChild(cross); 5094 } 5095 5096 div.appendChild(inner); 5097 5098 var mainBtn = mxUtils.button(btnLabel, function() 5099 { 5100 editorUi.hideDialog(); 5101 var value = (pageRadio.checked) ? ((pageSelect.value !== 'pageNotFound') ? 5102 pageSelect.value : initialValue) : linkInput.value; 5103 fn(value, LinkDialog.selectedDocs, (newWindowCheckbox.checked) ? linkTarget : null); 5104 }); 5105 mainBtn.style.verticalAlign = 'middle'; 5106 mainBtn.className = 'geBtn gePrimaryBtn'; 5107 5108 this.init = function() 5109 { 5110 if (pageRadio.checked) 5111 { 5112 pageSelect.focus(); 5113 } 5114 else 5115 { 5116 linkInput.focus(); 5117 5118 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 5119 { 5120 linkInput.select(); 5121 } 5122 else 5123 { 5124 document.execCommand('selectAll', false, null); 5125 } 5126 } 5127 5128 mxEvent.addListener(pageSelect, 'focus', function() 5129 { 5130 urlRadio.removeAttribute('checked'); 5131 pageRadio.setAttribute('checked', 'checked'); 5132 pageRadio.checked = true; 5133 }); 5134 5135 mxEvent.addListener(linkInput, 'focus', function() 5136 { 5137 pageRadio.removeAttribute('checked'); 5138 urlRadio.setAttribute('checked', 'checked'); 5139 urlRadio.checked = true; 5140 }); 5141 5142 // Installs drag and drop handler for links 5143 if (Graph.fileSupport) 5144 { 5145 // Setup the dnd listeners 5146 var dlg = div.parentNode; 5147 var graph = editorUi.editor.graph; 5148 var dropElt = null; 5149 5150 mxEvent.addListener(dlg, 'dragleave', function(evt) 5151 { 5152 if (dropElt != null) 5153 { 5154 dropElt.parentNode.removeChild(dropElt); 5155 dropElt = null; 5156 } 5157 5158 evt.stopPropagation(); 5159 evt.preventDefault(); 5160 }); 5161 5162 mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt) 5163 { 5164 // IE 10 does not implement pointer-events so it can't have a drop highlight 5165 if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10)) 5166 { 5167 dropElt = editorUi.highlightElement(dlg); 5168 } 5169 5170 evt.stopPropagation(); 5171 evt.preventDefault(); 5172 })); 5173 5174 mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt) 5175 { 5176 if (dropElt != null) 5177 { 5178 dropElt.parentNode.removeChild(dropElt); 5179 dropElt = null; 5180 } 5181 5182 if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0) 5183 { 5184 linkInput.value = decodeURIComponent(evt.dataTransfer.getData('text/uri-list')); 5185 urlRadio.setAttribute('checked', 'checked'); 5186 urlRadio.checked = true; 5187 mainBtn.click(); 5188 } 5189 5190 evt.stopPropagation(); 5191 evt.preventDefault(); 5192 }), false); 5193 } 5194 }; 5195 5196 var btns = document.createElement('div'); 5197 btns.style.marginTop = '18px'; 5198 btns.style.textAlign = 'center'; 5199 5200 var helpBtn = mxUtils.button(mxResources.get('help'), function() 5201 { 5202 editorUi.openLink('https://www.diagrams.net/doc/faq/custom-links'); 5203 }); 5204 5205 helpBtn.style.verticalAlign = 'middle'; 5206 helpBtn.className = 'geBtn'; 5207 btns.appendChild(helpBtn); 5208 5209 if (editorUi.isOffline() && !mxClient.IS_CHROMEAPP) 5210 { 5211 helpBtn.style.display = 'none'; 5212 } 5213 5214 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 5215 { 5216 editorUi.hideDialog(); 5217 }); 5218 cancelBtn.style.verticalAlign = 'middle'; 5219 cancelBtn.className = 'geBtn'; 5220 5221 if (editorUi.editor.cancelFirst) 5222 { 5223 btns.appendChild(cancelBtn); 5224 } 5225 5226 LinkDialog.selectedDocs = null; 5227 5228 LinkDialog.filePicked = function(data) 5229 { 5230 if (data.action == google.picker.Action.PICKED) 5231 { 5232 LinkDialog.selectedDocs = data.docs; 5233 var href = data.docs[0].url; 5234 5235 if (data.docs[0].mimeType == 'application/mxe' || (data.docs[0].mimeType != null && 5236 data.docs[0].mimeType.substring(0, 23) == 'application/vnd.jgraph.')) 5237 { 5238 href = 'https://www.draw.io/#G' + data.docs[0].id; 5239 } 5240 else if (data.docs[0].mimeType == 'application/vnd.google-apps.folder') 5241 { 5242 // Do not use folderview in data.docs[0].url link to Google Drive instead 5243 href = 'https://drive.google.com/#folders/' + data.docs[0].id; 5244 } 5245 5246 linkInput.value = href; 5247 linkInput.focus(); 5248 } 5249 else 5250 { 5251 LinkDialog.selectedDocs = null; 5252 } 5253 5254 linkInput.focus(); 5255 }; 5256 5257 function addButton(src, tooltip, fn) 5258 { 5259 var btn = mxUtils.button('', fn); 5260 btn.className = 'geBtn'; 5261 btn.setAttribute('title', tooltip); 5262 var img = document.createElement('img'); 5263 img.style.height = '26px'; 5264 img.style.width = '26px'; 5265 img.setAttribute('src', src); 5266 btn.style.minWidth = '42px'; 5267 btn.style.verticalAlign = 'middle'; 5268 btn.appendChild(img); 5269 btns.appendChild(btn); 5270 }; 5271 5272 if (typeof(google) != 'undefined' && typeof(google.picker) != 'undefined' && editorUi.drive != null) 5273 { 5274 addButton(IMAGE_PATH + '/google-drive-logo.svg', mxResources.get('googlePlus'), function() 5275 { 5276 if (editorUi.spinner.spin(document.body, mxResources.get('authorizing'))) 5277 { 5278 editorUi.drive.checkToken(mxUtils.bind(this, function() 5279 { 5280 editorUi.spinner.stop(); 5281 5282 // Creates one picker and reuses it to avoid polluting the DOM 5283 if (editorUi.linkPicker == null) 5284 { 5285 var picker = editorUi.drive.createLinkPicker(); 5286 5287 editorUi.linkPicker = picker.setCallback(function(data) 5288 { 5289 LinkDialog.filePicked(data); 5290 }).build(); 5291 } 5292 5293 editorUi.linkPicker.setVisible(true); 5294 })); 5295 } 5296 }); 5297 } 5298 5299 if (typeof(Dropbox) != 'undefined' && typeof(Dropbox.choose) != 'undefined') 5300 { 5301 addButton(IMAGE_PATH + '/dropbox-logo.svg', mxResources.get('dropbox'), function() 5302 { 5303 // Authentication will be carried out on open to make sure the 5304 // autosave does not show an auth dialog. Showing it here will 5305 // block the second dialog (the file picker) so it's too early. 5306 Dropbox.choose( 5307 { 5308 linkType : 'direct', 5309 cancel: function() 5310 { 5311 // do nothing 5312 }, 5313 success : function(files) 5314 { 5315 linkInput.value = files[0].link; 5316 linkInput.focus(); 5317 } 5318 }); 5319 }); 5320 } 5321 5322 if (editorUi.oneDrive != null) 5323 { 5324 addButton(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), function() 5325 { 5326 editorUi.oneDrive.pickFile(function(id, files) 5327 { 5328 linkInput.value = files.value[0].webUrl; 5329 linkInput.focus(); 5330 }); 5331 }); 5332 } 5333 5334 if (editorUi.gitHub != null) 5335 { 5336 addButton(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), function() 5337 { 5338 editorUi.gitHub.pickFile(function(path) 5339 { 5340 if (path != null) 5341 { 5342 var tokens = path.split('/'); 5343 var org = tokens[0]; 5344 var repo = tokens[1]; 5345 var ref = tokens[2]; 5346 var path = tokens.slice(3, tokens.length).join('/'); 5347 5348 linkInput.value = 'https://github.com/' + org + '/' + 5349 repo + '/blob/' + ref + '/' + path; 5350 linkInput.focus(); 5351 } 5352 }); 5353 }); 5354 } 5355 5356 if (editorUi.gitLab != null) 5357 { 5358 addButton(IMAGE_PATH + '/gitlab-logo.svg', mxResources.get('gitlab'), function() 5359 { 5360 editorUi.gitLab.pickFile(function(path) 5361 { 5362 if (path != null) 5363 { 5364 var tokens = path.split('/'); 5365 var org = tokens[0]; 5366 var repo = tokens[1]; 5367 var ref = tokens[2]; 5368 var path = tokens.slice(3, tokens.length).join('/'); 5369 5370 linkInput.value = DRAWIO_GITLAB_URL + '/' + org + '/' + 5371 repo + '/blob/' + ref + '/' + path; 5372 linkInput.focus(); 5373 } 5374 }); 5375 }); 5376 } 5377 5378 //TODO should Notion support this? 5379 //TODO should Trello support this? 5380 5381 mxEvent.addListener(linkInput, 'keypress', function(e) 5382 { 5383 if (e.keyCode == 13) 5384 { 5385 editorUi.hideDialog(); 5386 var value = (pageRadio.checked) ? pageSelect.value : linkInput.value; 5387 fn(value, LinkDialog.selectedDocs); 5388 } 5389 }); 5390 5391 btns.appendChild(mainBtn); 5392 5393 if (!editorUi.editor.cancelFirst) 5394 { 5395 btns.appendChild(cancelBtn); 5396 } 5397 5398 div.appendChild(btns); 5399 5400 this.container = div; 5401}; 5402 5403/** 5404 * Constructs a new about dialog 5405 */ 5406var FeedbackDialog = function(editorUi, subject, emailOptional, diagramData) 5407{ 5408 var div = document.createElement('div'); 5409 5410 var label = document.createElement('div'); 5411 mxUtils.write(label, mxResources.get('sendYourFeedback')); 5412 label.style.fontSize = '18px'; 5413 label.style.marginBottom = '18px'; 5414 5415 div.appendChild(label); 5416 5417 label = document.createElement('div'); 5418 mxUtils.write(label, mxResources.get('yourEmailAddress') + 5419 ((emailOptional) ? '' : ' (' + mxResources.get('required') + ')')); 5420 5421 div.appendChild(label); 5422 5423 var email = document.createElement('input'); 5424 email.setAttribute('type', 'text'); 5425 email.style.marginTop = '6px'; 5426 email.style.width = '600px'; 5427 5428 var sendButton = mxUtils.button(mxResources.get('sendMessage'), function() 5429 { 5430 var diagram = textarea.value + 5431 ((cb.checked) ? '\nDiagram:\n' + ((diagramData != null) ? 5432 diagramData : mxUtils.getXml(editorUi.getXmlFileData())) : '') + 5433 '\nuserAgent:\n' + navigator.userAgent + 5434 '\nappVersion:\n' + navigator.appVersion + 5435 '\nappName:\n' + navigator.appName + 5436 '\nplatform:\n' + navigator.platform; 5437 5438 if (diagram.length > FeedbackDialog.maxAttachmentSize) 5439 { 5440 editorUi.alert(mxResources.get('drawingTooLarge')); 5441 } 5442 else 5443 { 5444 editorUi.hideDialog(); 5445 5446 if (editorUi.spinner.spin(document.body)) 5447 { 5448 var postUrl = (FeedbackDialog.feedbackUrl != null) ? FeedbackDialog.feedbackUrl : '/email'; 5449 mxUtils.post(postUrl, 'email=' + encodeURIComponent(email.value) + 5450 '&version=' + encodeURIComponent(EditorUi.VERSION) + 5451 '&url=' + encodeURIComponent(window.location.href) + 5452 '&body=' + encodeURIComponent(((subject != null) ? 5453 subject : 'Feedback') + ':\n' + diagram), 5454 function(req) 5455 { 5456 editorUi.spinner.stop(); 5457 5458 if (req.getStatus() >= 200 && req.getStatus() <= 299) 5459 { 5460 editorUi.alert(mxResources.get('feedbackSent')); 5461 } 5462 else 5463 { 5464 editorUi.alert(mxResources.get('errorSendingFeedback')); 5465 } 5466 }, 5467 function() 5468 { 5469 editorUi.spinner.stop(); 5470 editorUi.alert(mxResources.get('errorSendingFeedback')); 5471 }); 5472 } 5473 } 5474 }); 5475 sendButton.className = 'geBtn gePrimaryBtn'; 5476 5477 if (!emailOptional) 5478 { 5479 sendButton.setAttribute('disabled', 'disabled'); 5480 5481 var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 5482 5483 mxEvent.addListener(email, 'change', function() 5484 { 5485 if (email.value.length > 0 && re.test(email.value) > 0) 5486 { 5487 sendButton.removeAttribute('disabled'); 5488 } 5489 else 5490 { 5491 sendButton.setAttribute('disabled', 'disabled'); 5492 } 5493 }); 5494 5495 mxEvent.addListener(email, 'keyup', function() 5496 { 5497 if (email.value.length > 0 && re.test(email.value)) 5498 { 5499 sendButton.removeAttribute('disabled'); 5500 } 5501 else 5502 { 5503 sendButton.setAttribute('disabled', 'disabled'); 5504 } 5505 }); 5506 } 5507 5508 div.appendChild(email); 5509 5510 this.init = function() 5511 { 5512 email.focus(); 5513 }; 5514 5515 var cb = document.createElement('input'); 5516 cb.setAttribute('type', 'checkbox'); 5517 cb.setAttribute('checked', 'checked'); 5518 cb.defaultChecked = true; 5519 5520 var p2 = document.createElement('p'); 5521 p2.style.marginTop = '14px'; 5522 p2.appendChild(cb); 5523 5524 var span = document.createElement('span'); 5525 mxUtils.write(span, ' ' + mxResources.get('includeCopyOfMyDiagram')); 5526 p2.appendChild(span); 5527 5528 mxEvent.addListener(span, 'click', function(evt) 5529 { 5530 cb.checked = !cb.checked; 5531 mxEvent.consume(evt); 5532 }); 5533 5534 div.appendChild(p2); 5535 5536 label = document.createElement('div'); 5537 mxUtils.write(label, mxResources.get('feedback')); 5538 5539 div.appendChild(label); 5540 5541 var textarea = document.createElement('textarea'); 5542 textarea.style.resize = 'none'; 5543 textarea.style.width = '600px'; 5544 textarea.style.height = '140px'; 5545 textarea.style.marginTop = '6px'; 5546 5547 textarea.setAttribute('placeholder', mxResources.get('comments')); 5548 5549 div.appendChild(textarea); 5550 5551 var buttons = document.createElement('div'); 5552 buttons.style.marginTop = '26px'; 5553 buttons.style.textAlign = 'right'; 5554 5555 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 5556 { 5557 editorUi.hideDialog(); 5558 }); 5559 cancelBtn.className = 'geBtn'; 5560 5561 if (editorUi.editor.cancelFirst) 5562 { 5563 buttons.appendChild(cancelBtn); 5564 buttons.appendChild(sendButton); 5565 } 5566 else 5567 { 5568 buttons.appendChild(sendButton); 5569 buttons.appendChild(cancelBtn); 5570 } 5571 5572 div.appendChild(buttons); 5573 this.container = div; 5574}; 5575 5576/** 5577 * Maximum size of attachments in bytes. Default is 1000000. 5578 */ 5579FeedbackDialog.maxAttachmentSize = 1000000; 5580 5581/** 5582 * Constructs a new revision dialog 5583 */ 5584var RevisionDialog = function(editorUi, revs, restoreFn) 5585{ 5586 var div = document.createElement('div'); 5587 5588 var title = document.createElement('h3'); 5589 title.style.marginTop = '0px'; 5590 mxUtils.write(title, mxResources.get('revisionHistory')); 5591 div.appendChild(title); 5592 5593 var list = document.createElement('div'); 5594 list.style.position = 'absolute'; 5595 list.style.overflow = 'auto'; 5596 list.style.width = '170px'; 5597 list.style.height = '378px'; 5598 div.appendChild(list); 5599 5600 var container = document.createElement('div'); 5601 container.style.position = 'absolute'; 5602 container.style.border = '1px solid lightGray'; 5603 container.style.left = '199px'; 5604 container.style.width = '470px'; 5605 container.style.height = '376px'; 5606 container.style.overflow = 'hidden'; 5607 5608 // Contains possible error messages 5609 var errorNode = document.createElement('div'); 5610 errorNode.style.cssText = 'position:absolute;left:0;right:0;top:0;bottom:20px;text-align:center;transform:translate(0,50%);pointer-events:none;'; 5611 container.appendChild(errorNode); 5612 5613 mxEvent.disableContextMenu(container); 5614 div.appendChild(container); 5615 5616 var graph = new Graph(container); 5617 graph.setTooltips(false); 5618 graph.setEnabled(false); 5619 graph.setPanning(true); 5620 graph.panningHandler.ignoreCell = true; 5621 graph.panningHandler.useLeftButtonForPanning = true; 5622 graph.minFitScale = null; 5623 graph.maxFitScale = null; 5624 graph.centerZoom = true; 5625 5626 // Handles placeholders for pages 5627 var currentPage = 0; 5628 var diagrams = null; 5629 var realPage = 0; 5630 5631 var graphGetGlobalVariable = graph.getGlobalVariable; 5632 5633 graph.getGlobalVariable = function(name) 5634 { 5635 if (name == 'page' && diagrams != null && diagrams[realPage] != null) 5636 { 5637 return diagrams[realPage].getAttribute('name'); 5638 } 5639 else if (name == 'pagenumber') 5640 { 5641 return realPage + 1; 5642 } 5643 else if (name == 'pagecount') 5644 { 5645 return (diagrams != null) ? diagrams.length : 1; 5646 } 5647 5648 return graphGetGlobalVariable.apply(this, arguments); 5649 }; 5650 5651 // Disables hyperlinks 5652 graph.getLinkForCell = function() 5653 { 5654 return null; 5655 }; 5656 5657 if (Editor.MathJaxRender) 5658 { 5659 graph.addListener(mxEvent.SIZE, mxUtils.bind(this, function(sender, evt) 5660 { 5661 // LATER: Math support is used if current graph has math enabled 5662 // should use switch from history instead but requires setting the 5663 // global mxClient.NO_FO switch 5664 if (editorUi.editor.graph.mathEnabled) 5665 { 5666 Editor.MathJaxRender(graph.container); 5667 } 5668 })); 5669 } 5670 5671 var opts = { 5672 lines: 11, // The number of lines to draw 5673 length: 15, // The length of each line 5674 width: 6, // The line thickness 5675 radius: 10, // The radius of the inner circle 5676 corners: 1, // Corner roundness (0..1) 5677 rotate: 0, // The rotation offset 5678 direction: 1, // 1: clockwise, -1: counterclockwise 5679 color: Editor.isDarkMode() ? '#c0c0c0' : '#000', // #rgb or #rrggbb 5680 speed: 1.4, // Rounds per second 5681 trail: 60, // Afterglow percentage 5682 shadow: false, // Whether to render a shadow 5683 hwaccel: false, // Whether to use hardware acceleration 5684 className: 'spinner', // The CSS class to assign to the spinner 5685 zIndex: 2e9, // The z-index (defaults to 2000000000) 5686 top: '50%', // Top position relative to parent 5687 left: '50%' // Left position relative to parent 5688 }; 5689 5690 var spinner = new Spinner(opts); 5691 5692 var file = editorUi.getCurrentFile(); 5693 var fileNode = editorUi.getXmlFileData(true, false, true); 5694 var tmp = fileNode.getElementsByTagName('diagram'); 5695 var currentDiagrams = {}; 5696 5697 for (var i = 0; i < tmp.length; i++) 5698 { 5699 currentDiagrams[tmp[i].getAttribute('id')] = tmp[i]; 5700 } 5701 5702 var currentRow = null; 5703 var currentRev = null; 5704 var currentDoc = null; 5705 var currentXml = null; 5706 5707 var zoomInBtn = mxUtils.button('', function() 5708 { 5709 if (currentDoc != null) 5710 { 5711 graph.zoomIn(); 5712 } 5713 }); 5714 zoomInBtn.className = 'geSprite geSprite-zoomin'; 5715 zoomInBtn.setAttribute('title', mxResources.get('zoomIn')); 5716 zoomInBtn.style.outline = 'none'; 5717 zoomInBtn.style.border = 'none'; 5718 zoomInBtn.style.margin = '2px'; 5719 zoomInBtn.setAttribute('disabled', 'disabled'); 5720 mxUtils.setOpacity(zoomInBtn, 20); 5721 5722 var zoomOutBtn = mxUtils.button('', function() 5723 { 5724 if (currentDoc != null) 5725 { 5726 graph.zoomOut(); 5727 } 5728 }); 5729 zoomOutBtn.className = 'geSprite geSprite-zoomout'; 5730 zoomOutBtn.setAttribute('title', mxResources.get('zoomOut')); 5731 zoomOutBtn.style.outline = 'none'; 5732 zoomOutBtn.style.border = 'none'; 5733 zoomOutBtn.style.margin = '2px'; 5734 zoomOutBtn.setAttribute('disabled', 'disabled'); 5735 mxUtils.setOpacity(zoomOutBtn, 20); 5736 5737 var zoomFitBtn = mxUtils.button('', function() 5738 { 5739 if (currentDoc != null) 5740 { 5741 graph.maxFitScale = 8; 5742 graph.fit(8); 5743 graph.center(); 5744 } 5745 }); 5746 zoomFitBtn.className = 'geSprite geSprite-fit'; 5747 zoomFitBtn.setAttribute('title', mxResources.get('fit')); 5748 zoomFitBtn.style.outline = 'none'; 5749 zoomFitBtn.style.border = 'none'; 5750 zoomFitBtn.style.margin = '2px'; 5751 zoomFitBtn.setAttribute('disabled', 'disabled'); 5752 mxUtils.setOpacity(zoomFitBtn, 20); 5753 5754 var zoomActualBtn = mxUtils.button('', function() 5755 { 5756 if (currentDoc != null) 5757 { 5758 graph.zoomActual(); 5759 graph.center(); 5760 } 5761 }); 5762 zoomActualBtn.className = 'geSprite geSprite-actualsize'; 5763 zoomActualBtn.setAttribute('title', mxResources.get('actualSize')); 5764 zoomActualBtn.style.outline = 'none'; 5765 zoomActualBtn.style.border = 'none'; 5766 zoomActualBtn.style.margin = '2px'; 5767 zoomActualBtn.setAttribute('disabled', 'disabled'); 5768 mxUtils.setOpacity(zoomActualBtn, 20); 5769 5770 // Gesture listener added below to handle pressed state 5771 var compareBtn = mxUtils.button('', function() { }); 5772 compareBtn.className = 'geSprite geSprite-middle'; 5773 compareBtn.setAttribute('title', mxResources.get('compare')); 5774 compareBtn.style.outline = 'none'; 5775 compareBtn.style.border = 'none'; 5776 compareBtn.style.margin = '2px'; 5777 mxUtils.setOpacity(compareBtn, 60); 5778 5779 var cmpContainer = container.cloneNode(false); 5780 cmpContainer.style.pointerEvent = 'none'; 5781 container.parentNode.appendChild(cmpContainer); 5782 5783 var cmpGraph = new Graph(cmpContainer); 5784 cmpGraph.setTooltips(false); 5785 cmpGraph.setEnabled(false); 5786 cmpGraph.setPanning(true); 5787 cmpGraph.panningHandler.ignoreCell = true; 5788 cmpGraph.panningHandler.useLeftButtonForPanning = true; 5789 cmpGraph.minFitScale = null; 5790 cmpGraph.maxFitScale = null; 5791 cmpGraph.centerZoom = true; 5792 5793 mxEvent.addGestureListeners(compareBtn, function(e) 5794 { 5795 // Gets current state of page with given ID 5796 var curr = currentDiagrams[diagrams[currentPage].getAttribute('id')]; 5797 mxUtils.setOpacity(compareBtn, 20); 5798 errorNode.innerHTML = ''; 5799 5800 if (curr == null) 5801 { 5802 mxUtils.write(errorNode, mxResources.get('pageNotFound')); 5803 } 5804 else 5805 { 5806 fileInfo.style.display = 'none'; 5807 container.style.display = 'none'; 5808 cmpContainer.style.display = ''; 5809 cmpContainer.style.backgroundColor = container.style.backgroundColor; 5810 5811 var tempNode = Editor.parseDiagramNode(curr); 5812 var codec = new mxCodec(tempNode.ownerDocument); 5813 codec.decode(tempNode, cmpGraph.getModel()); 5814 cmpGraph.view.scaleAndTranslate(graph.view.scale, 5815 graph.view.translate.x, graph.view.translate.y); 5816 } 5817 }, null, function() 5818 { 5819 mxUtils.setOpacity(compareBtn, 60); 5820 errorNode.innerHTML = ''; 5821 5822 if (container.style.display == 'none') 5823 { 5824 fileInfo.style.display = ''; 5825 container.style.display = ''; 5826 cmpContainer.style.display = 'none'; 5827 } 5828 }); 5829 5830 var fileInfo = document.createElement('div'); 5831 fileInfo.style.position = 'absolute'; 5832 fileInfo.style.textAlign = 'right'; 5833 fileInfo.style.color = 'gray'; 5834 fileInfo.style.marginTop = '10px'; 5835 fileInfo.style.backgroundColor = 'transparent'; 5836 fileInfo.style.top = '440px'; 5837 fileInfo.style.right = '32px'; 5838 fileInfo.style.maxWidth = '380px'; 5839 fileInfo.style.cursor = 'default'; 5840 5841 var downloadBtn = mxUtils.button(mxResources.get('download'), function() 5842 { 5843 if (currentDoc != null) 5844 { 5845 var data = mxUtils.getXml(currentDoc.documentElement); 5846 var filename = editorUi.getBaseFilename() + '.drawio'; 5847 5848 if (editorUi.isLocalFileSave()) 5849 { 5850 editorUi.saveLocalFile(data, filename, 'text/xml'); 5851 } 5852 else 5853 { 5854 var param = (typeof(pako) === 'undefined') ? '&xml=' + encodeURIComponent(data) : 5855 '&data=' + encodeURIComponent(Graph.compress(data)); 5856 new mxXmlRequest(SAVE_URL, 'filename=' + encodeURIComponent(filename) + 5857 '&format=xml' + param).simulate(document, '_blank'); 5858 } 5859 } 5860 }); 5861 downloadBtn.className = 'geBtn'; 5862 downloadBtn.setAttribute('disabled', 'disabled'); 5863 5864 var restoreBtn = mxUtils.button(mxResources.get('restore'), function(e) 5865 { 5866 if (currentDoc != null && currentXml != null) 5867 { 5868 if (mxEvent.isShiftDown(e)) 5869 { 5870 if (currentDoc != null) 5871 { 5872 var pages = editorUi.getPagesForNode(currentDoc.documentElement); 5873 var patch = editorUi.diffPages(editorUi.pages, pages); 5874 5875 var dlg = new TextareaDialog(editorUi, mxResources.get('compare'), 5876 JSON.stringify(patch, null, 2), function(newValue) 5877 { 5878 if (newValue.length > 0) 5879 { 5880 try 5881 { 5882 // TODO: Make add/remove pages undoable 5883 editorUi.confirm(mxResources.get('areYouSure'), function() 5884 { 5885 file.patch([JSON.parse(newValue)], null, true); 5886 5887 // Hides compare dialog 5888 editorUi.hideDialog(); 5889 5890 // Hides revision history dialog 5891 editorUi.hideDialog(); 5892 }); 5893 } 5894 catch (e) 5895 { 5896 editorUi.handleError(e); 5897 } 5898 } 5899 }, null, null, null, null, null, true, null, mxResources.get('merge')); 5900 5901 dlg.textarea.style.width = '600px'; 5902 dlg.textarea.style.height = '380px'; 5903 editorUi.showDialog(dlg.container, 620, 460, true, true); 5904 dlg.init(); 5905 } 5906 } 5907 else 5908 { 5909 editorUi.confirm(mxResources.get('areYouSure'), function() 5910 { 5911 if (restoreFn != null) 5912 { 5913 restoreFn(currentXml); 5914 } 5915 else 5916 { 5917 if (editorUi.spinner.spin(document.body, mxResources.get('restoring'))) 5918 { 5919 file.save(true, function(resp) 5920 { 5921 editorUi.spinner.stop(); 5922 editorUi.replaceFileData(currentXml); 5923 editorUi.hideDialog(); 5924 }, function(resp) 5925 { 5926 editorUi.spinner.stop(); 5927 editorUi.editor.setStatus(''); 5928 editorUi.handleError(resp, (resp != null) ? mxResources.get('errorSavingFile') : null); 5929 }); 5930 } 5931 } 5932 }); 5933 } 5934 } 5935 }); 5936 restoreBtn.className = 'geBtn'; 5937 restoreBtn.setAttribute('disabled', 'disabled'); 5938 restoreBtn.setAttribute('title', 'Shift+Click for Diff'); 5939 5940 var pageSelect = document.createElement('select'); 5941 pageSelect.setAttribute('disabled', 'disabled'); 5942 pageSelect.style.maxWidth = '80px'; 5943 pageSelect.style.position = 'relative'; 5944 pageSelect.style.top = '-2px'; 5945 pageSelect.style.verticalAlign = 'bottom'; 5946 pageSelect.style.marginRight = '6px'; 5947 pageSelect.style.display = 'none'; 5948 5949 var pageSelectFunction = null; 5950 5951 mxEvent.addListener(pageSelect, 'change', function(evt) 5952 { 5953 if (pageSelectFunction != null) 5954 { 5955 pageSelectFunction(evt); 5956 mxEvent.consume(evt); 5957 } 5958 }); 5959 5960 var newBtn = mxUtils.button(mxResources.get('edit'), function() 5961 { 5962 if (currentDoc != null) 5963 { 5964 window.openFile = new OpenFile(function() 5965 { 5966 window.openFile = null; 5967 }); 5968 5969 window.openFile.setData(mxUtils.getXml(currentDoc.documentElement)); 5970 editorUi.openLink(editorUi.getUrl(), null, true); 5971 } 5972 }); 5973 newBtn.className = 'geBtn'; 5974 newBtn.setAttribute('disabled', 'disabled'); 5975 5976 if (restoreFn != null) 5977 { 5978 newBtn.style.display = 'none'; 5979 } 5980 5981 var showBtn = mxUtils.button(mxResources.get('show'), function() 5982 { 5983 if (currentRev != null) 5984 { 5985 editorUi.openLink(currentRev.getUrl(pageSelect.selectedIndex)); 5986 } 5987 }); 5988 showBtn.className = 'geBtn gePrimaryBtn'; 5989 showBtn.setAttribute('disabled', 'disabled'); 5990 5991 if (restoreFn != null) 5992 { 5993 showBtn.style.display = 'none'; 5994 restoreBtn.className = 'geBtn gePrimaryBtn'; 5995 } 5996 5997 var buttons = document.createElement('div'); 5998 buttons.style.position = 'absolute'; 5999 buttons.style.top = '482px'; 6000 buttons.style.width = '640px'; 6001 buttons.style.textAlign = 'right'; 6002 6003 var tb = document.createElement('div'); 6004 tb.className = 'geToolbarContainer'; 6005 tb.style.backgroundColor = 'transparent'; 6006 tb.style.padding = '2px'; 6007 tb.style.border = 'none'; 6008 tb.style.left = '199px'; 6009 tb.style.top = '442px'; 6010 6011 var currentElt = null; 6012 6013 if (revs != null && revs.length > 0) 6014 { 6015 container.style.cursor = 'move'; 6016 6017 var table = document.createElement('table'); 6018 table.style.border = '1px solid lightGray'; 6019 table.style.borderCollapse = 'collapse'; 6020 table.style.borderSpacing = '0px'; 6021 table.style.width = '100%'; 6022 var tbody = document.createElement('tbody'); 6023 var today = new Date().toDateString(); 6024 6025 if (editorUi.currentPage != null && editorUi.pages != null) 6026 { 6027 currentPage = mxUtils.indexOf(editorUi.pages, editorUi.currentPage); 6028 } 6029 6030 for (var i = revs.length - 1; i >= 0; i--) 6031 { 6032 var elt = (function(item) 6033 { 6034 var ts = new Date(item.modifiedDate); 6035 var row = null; 6036 var pd = '6px'; 6037 6038 // Workaround for negative timestamps in Dropbox 6039 if (ts.getTime() >= 0) 6040 { 6041 row = document.createElement('tr'); 6042 row.style.borderBottom = '1px solid lightGray'; 6043 row.style.fontSize = '12px'; 6044 row.style.cursor = 'pointer'; 6045 6046 var date = document.createElement('td'); 6047 date.style.padding = pd; 6048 date.style.whiteSpace = 'nowrap'; 6049 6050 if (item == revs[revs.length - 1]) 6051 { 6052 mxUtils.write(date, mxResources.get('current')); 6053 } 6054 else 6055 { 6056 if (ts.toDateString() === today) 6057 { 6058 mxUtils.write(date, ts.toLocaleTimeString()); 6059 } 6060 else 6061 { 6062 mxUtils.write(date, ts.toLocaleDateString() + ' ' + 6063 ts.toLocaleTimeString()); 6064 } 6065 } 6066 6067 row.appendChild(date); 6068 6069 row.setAttribute('title', ts.toLocaleDateString() + ' ' + 6070 ts.toLocaleTimeString() + 6071 ((item.fileSize != null)? ' ' + editorUi.formatFileSize(parseInt(item.fileSize)) : '') + 6072 ((item.lastModifyingUserName != null) ? ' ' + item.lastModifyingUserName : '')); 6073 6074 function updateGraph(xml) 6075 { 6076 spinner.stop(); 6077 errorNode.innerHTML = ''; 6078 var doc = mxUtils.parseXml(xml); 6079 var node = editorUi.editor.extractGraphModel(doc.documentElement, true); 6080 6081 if (node != null) 6082 { 6083 pageSelect.style.display = 'none'; 6084 pageSelect.innerHTML = ''; 6085 currentDoc = doc; 6086 currentXml = xml; 6087 parseSelectFunction = null; 6088 diagrams = null; 6089 realPage = 0; 6090 6091 function parseGraphModel(dataNode) 6092 { 6093 var bg = dataNode.getAttribute('background'); 6094 6095 if (bg == null || bg == '' || bg == mxConstants.NONE) 6096 { 6097 bg = graph.defaultPageBackgroundColor; 6098 } 6099 6100 container.style.backgroundColor = bg; 6101 6102 var codec = new mxCodec(dataNode.ownerDocument); 6103 codec.decode(dataNode, graph.getModel()); 6104 graph.maxFitScale = 1; 6105 graph.fit(8); 6106 graph.center(); 6107 6108 return dataNode; 6109 } 6110 6111 function parseDiagram(diagramNode) 6112 { 6113 if (diagramNode != null) 6114 { 6115 diagramNode = parseGraphModel(Editor.parseDiagramNode(diagramNode)); 6116 } 6117 6118 return diagramNode; 6119 } 6120 6121 if (node.nodeName == 'mxfile') 6122 { 6123 // Workaround for "invalid calling object" error in IE 6124 var tmp = node.getElementsByTagName('diagram'); 6125 diagrams = []; 6126 6127 for (var i = 0; i < tmp.length; i++) 6128 { 6129 diagrams.push(tmp[i]); 6130 } 6131 6132 realPage = Math.min(currentPage, diagrams.length - 1); 6133 6134 if (diagrams.length > 0) 6135 { 6136 parseDiagram(diagrams[realPage]); 6137 } 6138 6139 if (diagrams.length > 1) 6140 { 6141 pageSelect.removeAttribute('disabled'); 6142 pageSelect.style.display = ''; 6143 6144 for (var i = 0; i < diagrams.length; i++) 6145 { 6146 var pageOption = document.createElement('option'); 6147 mxUtils.write(pageOption, diagrams[i].getAttribute('name') || 6148 mxResources.get('pageWithNumber', [i + 1])); 6149 pageOption.setAttribute('value', i); 6150 6151 if (i == realPage) 6152 { 6153 pageOption.setAttribute('selected', 'selected'); 6154 } 6155 6156 pageSelect.appendChild(pageOption); 6157 } 6158 } 6159 6160 pageSelectFunction = function() 6161 { 6162 try 6163 { 6164 var temp = parseInt(pageSelect.value); 6165 currentPage = temp; 6166 realPage = currentPage; 6167 parseDiagram(diagrams[temp]); 6168 } 6169 catch (e) 6170 { 6171 pageSelect.value = currentPage; 6172 editorUi.handleError(e); 6173 } 6174 }; 6175 } 6176 else 6177 { 6178 parseGraphModel(node); 6179 } 6180 6181 var shortUser = item.lastModifyingUserName; 6182 6183 if (shortUser != null && shortUser.length > 20) 6184 { 6185 shortUser = shortUser.substring(0, 20) + '...'; 6186 } 6187 6188 fileInfo.innerHTML = ''; 6189 mxUtils.write(fileInfo, ((shortUser != null) ? 6190 (shortUser + ' ') : '') + ts.toLocaleDateString() + 6191 ' ' + ts.toLocaleTimeString()); 6192 6193 fileInfo.setAttribute('title', row.getAttribute('title')); 6194 zoomInBtn.removeAttribute('disabled'); 6195 zoomOutBtn.removeAttribute('disabled'); 6196 zoomFitBtn.removeAttribute('disabled'); 6197 zoomActualBtn.removeAttribute('disabled'); 6198 compareBtn.removeAttribute('disabled'); 6199 6200 if (file == null || !file.isRestricted()) 6201 { 6202 if (editorUi.editor.graph.isEnabled()) 6203 { 6204 restoreBtn.removeAttribute('disabled'); 6205 } 6206 6207 downloadBtn.removeAttribute('disabled'); 6208 showBtn.removeAttribute('disabled'); 6209 newBtn.removeAttribute('disabled'); 6210 } 6211 6212 mxUtils.setOpacity(zoomInBtn, 60); 6213 mxUtils.setOpacity(zoomOutBtn, 60); 6214 mxUtils.setOpacity(zoomFitBtn, 60); 6215 mxUtils.setOpacity(zoomActualBtn, 60); 6216 mxUtils.setOpacity(compareBtn, 60); 6217 } 6218 else 6219 { 6220 pageSelect.style.display = 'none'; 6221 pageSelect.innerHTML = ''; 6222 fileInfo.innerHTML = ''; 6223 mxUtils.write(fileInfo, mxResources.get('errorLoadingFile')); 6224 mxUtils.write(errorNode, mxResources.get('errorLoadingFile')); 6225 } 6226 }; 6227 6228 mxEvent.addListener(row, 'click', function(evt) 6229 { 6230 if (currentRev != item) 6231 { 6232 spinner.stop(); 6233 6234 if (currentRow != null) 6235 { 6236 currentRow.style.backgroundColor = ''; 6237 } 6238 6239 currentRev = item; 6240 currentRow = row; 6241 currentRow.style.backgroundColor = Editor.isDarkMode() ? '#000000' : '#ebf2f9'; 6242 currentDoc = null; 6243 currentXml = null; 6244 6245 fileInfo.removeAttribute('title'); 6246 fileInfo.innerHTML = mxUtils.htmlEntities(mxResources.get('loading') + '...'); 6247 container.style.backgroundColor = graph.defaultPageBackgroundColor; 6248 errorNode.innerHTML = ''; 6249 graph.getModel().clear(); 6250 6251 restoreBtn.setAttribute('disabled', 'disabled'); 6252 downloadBtn.setAttribute('disabled', 'disabled'); 6253 zoomInBtn.setAttribute('disabled', 'disabled'); 6254 zoomOutBtn.setAttribute('disabled', 'disabled'); 6255 zoomActualBtn.setAttribute('disabled', 'disabled'); 6256 zoomFitBtn.setAttribute('disabled', 'disabled'); 6257 compareBtn.setAttribute('disabled', 'disabled'); 6258 6259 newBtn.setAttribute('disabled', 'disabled'); 6260 showBtn.setAttribute('disabled', 'disabled'); 6261 pageSelect.setAttribute('disabled', 'disabled'); 6262 6263 mxUtils.setOpacity(zoomInBtn, 20); 6264 mxUtils.setOpacity(zoomOutBtn, 20); 6265 mxUtils.setOpacity(zoomFitBtn, 20); 6266 mxUtils.setOpacity(zoomActualBtn, 20); 6267 mxUtils.setOpacity(compareBtn, 20); 6268 6269 spinner.spin(container); 6270 6271 item.getXml(function(xml) 6272 { 6273 if (currentRev == item) 6274 { 6275 try 6276 { 6277 updateGraph(xml); 6278 } 6279 catch (e) 6280 { 6281 fileInfo.innerHTML = mxUtils.htmlEntities( 6282 mxResources.get('error') + ': ' + e.message); 6283 } 6284 } 6285 }, function(err) 6286 { 6287 spinner.stop(); 6288 pageSelect.style.display = 'none'; 6289 pageSelect.innerHTML = ''; 6290 fileInfo.innerHTML = ''; 6291 mxUtils.write(fileInfo, mxResources.get('errorLoadingFile')); 6292 mxUtils.write(errorNode, mxResources.get('errorLoadingFile')); 6293 }); 6294 6295 mxEvent.consume(evt); 6296 } 6297 }); 6298 6299 mxEvent.addListener(row, 'dblclick', function(evt) 6300 { 6301 showBtn.click(); 6302 6303 if (window.getSelection) 6304 { 6305 window.getSelection().removeAllRanges(); 6306 } 6307 else if (document.selection) 6308 { 6309 document.selection.empty(); 6310 } 6311 6312 mxEvent.consume(evt); 6313 }, false); 6314 6315 tbody.appendChild(row); 6316 } 6317 6318 return row; 6319 })(revs[i]); 6320 6321 // Selects and loads first element in list (ie current version) after 6322 // graph container was initialized since there is no loading delay 6323 if (elt != null && i == revs.length - 1) 6324 { 6325 currentElt = elt; 6326 } 6327 } 6328 6329 table.appendChild(tbody); 6330 list.appendChild(table); 6331 } 6332 else if (file == null || (editorUi.drive == null && file.constructor == window.DriveFile) || 6333 (editorUi.dropbox == null && file.constructor == window.DropboxFile)) 6334 { 6335 container.style.display = 'none'; 6336 tb.style.display = 'none'; 6337 mxUtils.write(list, mxResources.get('notAvailable')); 6338 } 6339 else 6340 { 6341 container.style.display = 'none'; 6342 tb.style.display = 'none'; 6343 mxUtils.write(list, mxResources.get('noRevisions')); 6344 } 6345 6346 this.init = function() 6347 { 6348 if (currentElt != null) 6349 { 6350 currentElt.click(); 6351 } 6352 }; 6353 6354 var closeBtn = mxUtils.button(mxResources.get('close'), function() 6355 { 6356 editorUi.hideDialog(); 6357 }); 6358 closeBtn.className = 'geBtn'; 6359 6360 tb.appendChild(pageSelect); 6361 tb.appendChild(zoomInBtn); 6362 tb.appendChild(zoomOutBtn); 6363 tb.appendChild(zoomActualBtn); 6364 tb.appendChild(zoomFitBtn); 6365 tb.appendChild(compareBtn); 6366 6367 if (editorUi.editor.cancelFirst) 6368 { 6369 buttons.appendChild(closeBtn); 6370 buttons.appendChild(downloadBtn); 6371 buttons.appendChild(newBtn); 6372 buttons.appendChild(restoreBtn); 6373 buttons.appendChild(showBtn); 6374 } 6375 else 6376 { 6377 buttons.appendChild(downloadBtn); 6378 buttons.appendChild(newBtn); 6379 buttons.appendChild(restoreBtn); 6380 buttons.appendChild(showBtn); 6381 buttons.appendChild(closeBtn); 6382 } 6383 6384 div.appendChild(buttons); 6385 div.appendChild(tb); 6386 div.appendChild(fileInfo); 6387 6388 this.container = div; 6389}; 6390 6391/** 6392 * Constructs a new revision dialog 6393 */ 6394var DraftDialog = function(editorUi, title, xml, editFn, discardFn, editLabel, discardLabel, ignoreFn, drafts) 6395{ 6396 var div = document.createElement('div'); 6397 6398 var titleDiv = document.createElement('div'); 6399 titleDiv.style.marginTop = '0px'; 6400 titleDiv.style.whiteSpace = 'nowrap'; 6401 titleDiv.style.overflow = 'auto'; 6402 titleDiv.style.lineHeight = 'normal'; 6403 mxUtils.write(titleDiv, title); 6404 div.appendChild(titleDiv); 6405 6406 var select = document.createElement('select'); 6407 6408 var draftSelected = mxUtils.bind(this, function() 6409 { 6410 doc = mxUtils.parseXml(drafts[select.value].data); 6411 node = editorUi.editor.extractGraphModel(doc.documentElement, true); 6412 currentPage = 0; 6413 6414 this.init(); 6415 }); 6416 6417 if (drafts != null) 6418 { 6419 select.style.marginLeft = '4px'; 6420 6421 for (var i = 0; i < drafts.length; i++) 6422 { 6423 var opt = document.createElement('option'); 6424 opt.setAttribute('value', i); 6425 var ts0 = new Date(drafts[i].created); 6426 var ts1 = new Date(drafts[i].modified); 6427 6428 mxUtils.write(opt, ts0.toLocaleDateString() + ' ' + 6429 ts0.toLocaleTimeString() + ' - ' + 6430 ((ts0.toDateString() != ts1.toDateString() || true) ? 6431 ts1.toLocaleDateString() : ' ') + 6432 ' ' + ts1.toLocaleTimeString()); 6433 6434 select.appendChild(opt); 6435 } 6436 6437 titleDiv.appendChild(select); 6438 6439 mxEvent.addListener(select, 'change', draftSelected); 6440 } 6441 6442 if (xml == null) 6443 { 6444 xml = drafts[0].data; 6445 } 6446 6447 var container = document.createElement('div'); 6448 container.style.position = 'absolute'; 6449 container.style.border = '1px solid lightGray'; 6450 container.style.marginTop = '10px'; 6451 container.style.left = '40px'; 6452 container.style.right = '40px'; 6453 container.style.top = '46px'; 6454 container.style.bottom = '74px'; 6455 container.style.overflow = 'hidden'; 6456 6457 mxEvent.disableContextMenu(container); 6458 div.appendChild(container); 6459 6460 var graph = new Graph(container); 6461 graph.setEnabled(false); 6462 graph.setPanning(true); 6463 graph.panningHandler.ignoreCell = true; 6464 graph.panningHandler.useLeftButtonForPanning = true; 6465 graph.minFitScale = null; 6466 graph.maxFitScale = null; 6467 graph.centerZoom = true; 6468 6469 // Handles placeholders for pages 6470 var doc = mxUtils.parseXml(xml); 6471 var node = editorUi.editor.extractGraphModel(doc.documentElement, true); 6472 var currentPage = 0; 6473 var diagrams = null; 6474 var graphGetGlobalVariable = graph.getGlobalVariable; 6475 6476 graph.getGlobalVariable = function(name) 6477 { 6478 if (name == 'page' && diagrams != null && diagrams[currentPage] != null) 6479 { 6480 return diagrams[currentPage].getAttribute('name'); 6481 } 6482 else if (name == 'pagenumber') 6483 { 6484 return currentPage + 1; 6485 } 6486 else if (name == 'pagecount') 6487 { 6488 return (diagrams != null) ? diagrams.length : 1; 6489 } 6490 6491 return graphGetGlobalVariable.apply(this, arguments); 6492 }; 6493 6494 // Disables hyperlinks 6495 graph.getLinkForCell = function() 6496 { 6497 return null; 6498 }; 6499 6500 // TODO: Enable per-page math 6501// if (Editor.MathJaxRender) 6502// { 6503// graph.addListener(mxEvent.SIZE, mxUtils.bind(this, function(sender, evt) 6504// { 6505// // LATER: Math support is used if current graph has math enabled 6506// // should use switch from history instead but requires setting the 6507// // global mxClient.NO_FO switch 6508// if (editorUi.editor.graph.mathEnabled) 6509// { 6510// Editor.MathJaxRender(graph.container); 6511// } 6512// })); 6513// } 6514 6515 var zoomInBtn = mxUtils.button('', function() 6516 { 6517 graph.zoomIn(); 6518 }); 6519 zoomInBtn.className = 'geSprite geSprite-zoomin'; 6520 zoomInBtn.setAttribute('title', mxResources.get('zoomIn')); 6521 zoomInBtn.style.outline = 'none'; 6522 zoomInBtn.style.border = 'none'; 6523 zoomInBtn.style.margin = '2px'; 6524 mxUtils.setOpacity(zoomInBtn, 60); 6525 6526 var zoomOutBtn = mxUtils.button('', function() 6527 { 6528 graph.zoomOut(); 6529 }); 6530 zoomOutBtn.className = 'geSprite geSprite-zoomout'; 6531 zoomOutBtn.setAttribute('title', mxResources.get('zoomOut')); 6532 zoomOutBtn.style.outline = 'none'; 6533 zoomOutBtn.style.border = 'none'; 6534 zoomOutBtn.style.margin = '2px'; 6535 mxUtils.setOpacity(zoomOutBtn, 60); 6536 6537 var zoomFitBtn = mxUtils.button('', function() 6538 { 6539 graph.maxFitScale = 8; 6540 graph.fit(8); 6541 graph.center(); 6542 }); 6543 zoomFitBtn.className = 'geSprite geSprite-fit'; 6544 zoomFitBtn.setAttribute('title', mxResources.get('fit')); 6545 zoomFitBtn.style.outline = 'none'; 6546 zoomFitBtn.style.border = 'none'; 6547 zoomFitBtn.style.margin = '2px'; 6548 mxUtils.setOpacity(zoomFitBtn, 60); 6549 6550 var zoomActualBtn = mxUtils.button('', function() 6551 { 6552 graph.zoomActual(); 6553 graph.center(); 6554 }); 6555 zoomActualBtn.className = 'geSprite geSprite-actualsize'; 6556 zoomActualBtn.setAttribute('title', mxResources.get('actualSize')); 6557 zoomActualBtn.style.outline = 'none'; 6558 zoomActualBtn.style.border = 'none'; 6559 zoomActualBtn.style.margin = '2px'; 6560 mxUtils.setOpacity(zoomActualBtn, 60); 6561 6562 var restoreBtn = mxUtils.button(discardLabel || mxResources.get('discard'), function() 6563 { 6564 discardFn.apply(this, [select.value, mxUtils.bind(this, function() 6565 { 6566 if (select.parentNode != null) 6567 { 6568 select.options[select.selectedIndex].parentNode.removeChild(select.options[select.selectedIndex]); 6569 6570 if (select.options.length > 0) 6571 { 6572 select.value = select.options[0].value; 6573 draftSelected(); 6574 } 6575 else 6576 { 6577 editorUi.hideDialog(true); 6578 } 6579 } 6580 })]); 6581 }); 6582 restoreBtn.className = 'geBtn'; 6583 6584 var pageSelect = document.createElement('select'); 6585 pageSelect.style.maxWidth = '80px'; 6586 pageSelect.style.position = 'relative'; 6587 pageSelect.style.top = '-2px'; 6588 pageSelect.style.verticalAlign = 'bottom'; 6589 pageSelect.style.marginRight = '6px'; 6590 pageSelect.style.display = 'none'; 6591 6592 var showBtn = mxUtils.button(editLabel || mxResources.get('edit'), function() 6593 { 6594 editFn.apply(this, [select.value]) 6595 }); 6596 showBtn.className = 'geBtn gePrimaryBtn'; 6597 6598 var buttons = document.createElement('div'); 6599 buttons.style.position = 'absolute'; 6600 buttons.style.bottom = '30px'; 6601 buttons.style.right = '40px'; 6602 buttons.style.textAlign = 'right'; 6603 6604 var tb = document.createElement('div'); 6605 tb.className = 'geToolbarContainer'; 6606 tb.style.cssText = 'box-shadow:none !important;background-color:transparent;' + 6607 'padding:2px;border-style:none !important;bottom:30px;'; 6608 6609 this.init = function() 6610 { 6611 function parseGraphModel(dataNode) 6612 { 6613 if (dataNode != null) 6614 { 6615 var bg = dataNode.getAttribute('background'); 6616 6617 if (bg == null || bg == '' || bg == mxConstants.NONE) 6618 { 6619 bg = Editor.isDarkMode() ? 'transparent' : '#ffffff'; 6620 } 6621 6622 container.style.backgroundColor = bg; 6623 6624 var codec = new mxCodec(dataNode.ownerDocument); 6625 codec.decode(dataNode, graph.getModel()); 6626 graph.maxFitScale = 1; 6627 graph.fit(8); 6628 graph.center(); 6629 } 6630 6631 return dataNode; 6632 }; 6633 6634 function parseDiagram(diagramNode) 6635 { 6636 if (diagramNode != null) 6637 { 6638 diagramNode = parseGraphModel(Editor.parseDiagramNode(diagramNode)); 6639 } 6640 6641 return diagramNode; 6642 }; 6643 6644 mxEvent.addListener(pageSelect, 'change', function(evt) 6645 { 6646 currentPage = parseInt(pageSelect.value); 6647 parseDiagram(diagrams[currentPage]); 6648 mxEvent.consume(evt); 6649 }); 6650 6651 if (node.nodeName == 'mxfile') 6652 { 6653 // Workaround for "invalid calling object" error in IE 6654 var tmp = node.getElementsByTagName('diagram'); 6655 diagrams = []; 6656 6657 for (var i = 0; i < tmp.length; i++) 6658 { 6659 diagrams.push(tmp[i]); 6660 } 6661 6662 if (diagrams.length > 0) 6663 { 6664 parseDiagram(diagrams[currentPage]); 6665 } 6666 6667 pageSelect.innerHTML = ''; 6668 6669 if (diagrams.length > 1) 6670 { 6671 pageSelect.style.display = ''; 6672 6673 for (var i = 0; i < diagrams.length; i++) 6674 { 6675 var pageOption = document.createElement('option'); 6676 mxUtils.write(pageOption, diagrams[i].getAttribute('name') || 6677 mxResources.get('pageWithNumber', [i + 1])); 6678 pageOption.setAttribute('value', i); 6679 6680 if (i == currentPage) 6681 { 6682 pageOption.setAttribute('selected', 'selected'); 6683 } 6684 6685 pageSelect.appendChild(pageOption); 6686 } 6687 } 6688 else 6689 { 6690 pageSelect.style.display = 'none'; 6691 } 6692 } 6693 else 6694 { 6695 parseGraphModel(node); 6696 } 6697 }; 6698 6699 tb.appendChild(pageSelect); 6700 tb.appendChild(zoomInBtn); 6701 tb.appendChild(zoomOutBtn); 6702 tb.appendChild(zoomActualBtn); 6703 tb.appendChild(zoomFitBtn); 6704 6705 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 6706 { 6707 editorUi.hideDialog(true); 6708 }); 6709 6710 cancelBtn.className = 'geBtn'; 6711 6712 var ignoreBtn = (ignoreFn != null) ? mxUtils.button(mxResources.get('ignore'), ignoreFn) : null; 6713 6714 if (ignoreBtn != null) 6715 { 6716 ignoreBtn.className = 'geBtn'; 6717 } 6718 6719 if (editorUi.editor.cancelFirst) 6720 { 6721 buttons.appendChild(cancelBtn); 6722 6723 if (ignoreBtn != null) 6724 { 6725 buttons.appendChild(ignoreBtn); 6726 } 6727 6728 buttons.appendChild(restoreBtn); 6729 buttons.appendChild(showBtn); 6730 } 6731 else 6732 { 6733 buttons.appendChild(showBtn); 6734 buttons.appendChild(restoreBtn); 6735 6736 if (ignoreBtn != null) 6737 { 6738 buttons.appendChild(ignoreBtn); 6739 } 6740 6741 buttons.appendChild(cancelBtn); 6742 } 6743 6744 div.appendChild(buttons); 6745 div.appendChild(tb); 6746 6747 this.container = div; 6748}; 6749 6750/** 6751 * 6752 */ 6753var FindWindow = function(ui, x, y, w, h, withReplace) 6754{ 6755 var action = ui.actions.get('findReplace'); 6756 6757 var graph = ui.editor.graph; 6758 var lastSearch = null; 6759 var lastFound = null; 6760 var lastSearchSuccessful = false; 6761 var allChecked = false; 6762 var lblMatch = null; 6763 var lblMatchPos = 0; 6764 var marker = 1; 6765 6766 var div = document.createElement('div'); 6767 div.style.userSelect = 'none'; 6768 div.style.overflow = 'hidden'; 6769 div.style.padding = '10px'; 6770 div.style.height = '100%'; 6771 6772 var txtWidth = withReplace? '260px' : '200px'; 6773 var searchInput = document.createElement('input'); 6774 searchInput.setAttribute('placeholder', mxResources.get('find')); 6775 searchInput.setAttribute('type', 'text'); 6776 searchInput.style.marginTop = '4px'; 6777 searchInput.style.marginBottom = '6px'; 6778 searchInput.style.width = txtWidth; 6779 searchInput.style.fontSize = '12px'; 6780 searchInput.style.borderRadius = '4px'; 6781 searchInput.style.padding = '6px'; 6782 div.appendChild(searchInput); 6783 mxUtils.br(div); 6784 6785 var replaceInput; 6786 6787 if (withReplace) 6788 { 6789 replaceInput = document.createElement('input'); 6790 replaceInput.setAttribute('placeholder', mxResources.get('replaceWith')); 6791 replaceInput.setAttribute('type', 'text'); 6792 replaceInput.style.marginTop = '4px'; 6793 replaceInput.style.marginBottom = '6px'; 6794 replaceInput.style.width = txtWidth; 6795 replaceInput.style.fontSize = '12px'; 6796 replaceInput.style.borderRadius = '4px'; 6797 replaceInput.style.padding = '6px'; 6798 div.appendChild(replaceInput); 6799 mxUtils.br(div); 6800 6801 mxEvent.addListener(replaceInput, 'input', updateReplBtns); 6802 } 6803 6804 var regexInput = document.createElement('input'); 6805 regexInput.setAttribute('id', 'geFindWinRegExChck'); 6806 regexInput.setAttribute('type', 'checkbox'); 6807 regexInput.style.marginRight = '4px'; 6808 div.appendChild(regexInput); 6809 6810 var regexLabel = document.createElement('label'); 6811 regexLabel.setAttribute('for', 'geFindWinRegExChck'); 6812 div.appendChild(regexLabel); 6813 mxUtils.write(regexLabel, mxResources.get('regularExpression')); 6814 div.appendChild(regexLabel); 6815 6816 var help = ui.menus.createHelpLink('https://www.diagrams.net/doc/faq/find-shapes'); 6817 help.style.position = 'relative'; 6818 help.style.marginLeft = '6px'; 6819 help.style.top = '-1px'; 6820 div.appendChild(help); 6821 6822 mxUtils.br(div); 6823 6824 var allPagesInput = document.createElement('input'); 6825 allPagesInput.setAttribute('id', 'geFindWinAllPagesChck'); 6826 allPagesInput.setAttribute('type', 'checkbox'); 6827 allPagesInput.style.marginRight = '4px'; 6828 div.appendChild(allPagesInput); 6829 6830 var allPagesLabel = document.createElement('label'); 6831 allPagesLabel.setAttribute('for', 'geFindWinAllPagesChck'); 6832 div.appendChild(allPagesLabel); 6833 mxUtils.write(allPagesLabel, mxResources.get('allPages')); 6834 div.appendChild(allPagesLabel); 6835 6836 var tmp = document.createElement('div'); 6837 6838 function testMeta(re, cell, search, checkIndex) 6839 { 6840 if (typeof cell.value === 'object' && cell.value.attributes != null) 6841 { 6842 var attrs = cell.value.attributes; 6843 6844 for (var i = 0; i < attrs.length; i++) 6845 { 6846 if (attrs[i].nodeName != 'label') 6847 { 6848 var value = mxUtils.trim(attrs[i].nodeValue.replace(/[\x00-\x1F\x7F-\x9F]|\s+/g, ' ')).toLowerCase(); 6849 6850 if ((re == null && ((checkIndex && value.indexOf(search) >= 0) || 6851 (!checkIndex && value.substring(0, search.length) === search))) || 6852 (re != null && re.test(value))) 6853 { 6854 return true; 6855 } 6856 } 6857 } 6858 } 6859 6860 return false; 6861 }; 6862 6863 function updateReplBtns() 6864 { 6865 if (lastSearchSuccessful && replaceInput.value) 6866 { 6867 replaceFindBtn.removeAttribute('disabled'); 6868 replaceBtn.removeAttribute('disabled'); 6869 } 6870 else 6871 { 6872 replaceFindBtn.setAttribute('disabled', 'disabled'); 6873 replaceBtn.setAttribute('disabled', 'disabled'); 6874 } 6875 6876 if (replaceInput.value && searchInput.value) 6877 { 6878 replaceAllBtn.removeAttribute('disabled'); 6879 } 6880 else 6881 { 6882 replaceAllBtn.setAttribute('disabled', 'disabled'); 6883 } 6884 } 6885 6886 function search(internalCall, trySameCell, stayOnPage) 6887 { 6888 replAllNotif.innerHTML = ''; 6889 var cells = graph.model.getDescendants(graph.model.getRoot()); 6890 var searchStr = searchInput.value.toLowerCase(); 6891 var re = (regexInput.checked) ? new RegExp(searchStr) : null; 6892 var firstMatch = null; 6893 lblMatch = null; 6894 6895 if (lastSearch != searchStr) 6896 { 6897 lastSearch = searchStr; 6898 lastFound = null; 6899 allChecked = false; 6900 } 6901 6902 var active = lastFound == null; 6903 6904 if (searchStr.length > 0) 6905 { 6906 if (allChecked) 6907 { 6908 allChecked = false; 6909 6910 //Find current page index 6911 var currentPageIndex; 6912 6913 for (var i = 0; i < ui.pages.length; i++) 6914 { 6915 if (ui.currentPage == ui.pages[i]) 6916 { 6917 currentPageIndex = i; 6918 break; 6919 } 6920 } 6921 6922 var nextPageIndex = (currentPageIndex + 1) % ui.pages.length, nextPage; 6923 lastFound = null; 6924 6925 do 6926 { 6927 allChecked = false; 6928 nextPage = ui.pages[nextPageIndex]; 6929 graph = ui.createTemporaryGraph(graph.getStylesheet()); 6930 ui.updatePageRoot(nextPage); 6931 graph.model.setRoot(nextPage.root); 6932 nextPageIndex = (nextPageIndex + 1) % ui.pages.length; 6933 } 6934 while(!search(true, trySameCell, stayOnPage) && nextPageIndex != currentPageIndex); 6935 6936 if (lastFound) 6937 { 6938 lastFound = null; 6939 6940 if (!stayOnPage) 6941 { 6942 ui.selectPage(nextPage); 6943 } 6944 else 6945 { 6946 ui.editor.graph.model.execute(new SelectPage(ui, nextPage)); 6947 } 6948 } 6949 6950 allChecked = false; 6951 graph = ui.editor.graph; 6952 6953 return search(true, trySameCell, stayOnPage); 6954 } 6955 6956 var i; 6957 6958 for (i = 0; i < cells.length; i++) 6959 { 6960 var state = graph.view.getState(cells[i]); 6961 6962 //Try the same cell with replace to find other occurances 6963 if (trySameCell && re != null) 6964 { 6965 active = active || state == lastFound; 6966 } 6967 6968 if (state != null && state.cell.value != null && (active || firstMatch == null) && 6969 (graph.model.isVertex(state.cell) || graph.model.isEdge(state.cell))) 6970 { 6971 if (state.style != null && state.style['html'] == '1') 6972 { 6973 tmp.innerHTML = graph.sanitizeHtml(graph.getLabel(state.cell)); 6974 label = mxUtils.extractTextWithWhitespace([tmp]); 6975 } 6976 else 6977 { 6978 label = graph.getLabel(state.cell); 6979 } 6980 6981 label = mxUtils.trim(label.replace(/[\x00-\x1F\x7F-\x9F]|\s+/g, ' ')).toLowerCase(); 6982 var lblPosShift = 0; 6983 6984 if (trySameCell && withReplace && re != null && state == lastFound) 6985 { 6986 label = label.substr(lblMatchPos); 6987 lblPosShift = lblMatchPos; 6988 } 6989 6990 var checkMeta = replaceInput.value == ''; 6991 var checkIndex = checkMeta; 6992 6993 if ((re == null && ((checkIndex && label.indexOf(searchStr) >= 0) || 6994 (!checkIndex && label.substring(0, searchStr.length) === searchStr) || 6995 (checkMeta && testMeta(re, state.cell, searchStr, checkIndex)))) || 6996 (re != null && (re.test(label) || (checkMeta && 6997 testMeta(re, state.cell, searchStr, checkIndex))))) 6998 { 6999 if (withReplace) 7000 { 7001 if (re != null) 7002 { 7003 var result = label.match(re); 7004 lblMatch = result[0].toLowerCase(); 7005 lblMatchPos = lblPosShift + result.index + lblMatch.length; 7006 } 7007 else 7008 { 7009 lblMatch = searchStr; 7010 lblMatchPos = lblMatch.length; 7011 } 7012 } 7013 7014 if (active) 7015 { 7016 firstMatch = state; 7017 7018 break; 7019 } 7020 else if (firstMatch == null) 7021 { 7022 firstMatch = state; 7023 } 7024 } 7025 } 7026 7027 active = active || state == lastFound; 7028 } 7029 } 7030 7031 if (firstMatch != null) 7032 { 7033 if (i == cells.length && allPagesInput.checked) 7034 { 7035 lastFound = null; 7036 allChecked = true; 7037 return search(true, trySameCell, stayOnPage); 7038 } 7039 7040 lastFound = firstMatch; 7041 graph.scrollCellToVisible(lastFound.cell); 7042 7043 if (graph.isEnabled() && !graph.isCellLocked(lastFound.cell)) 7044 { 7045 if (!stayOnPage && 7046 (graph.getSelectionCell() != lastFound.cell || 7047 graph.getSelectionCount() != 1)) 7048 { 7049 graph.setSelectionCell(lastFound.cell); 7050 } 7051 } 7052 else 7053 { 7054 graph.highlightCell(lastFound.cell); 7055 } 7056 } 7057 //Check other pages 7058 else if (!internalCall && allPagesInput.checked) 7059 { 7060 allChecked = true; 7061 return search(true, trySameCell, stayOnPage); 7062 } 7063 else if (graph.isEnabled() && !stayOnPage) 7064 { 7065 graph.clearSelection(); 7066 } 7067 7068 lastSearchSuccessful = firstMatch != null; 7069 7070 if (withReplace && !internalCall) 7071 { 7072 updateReplBtns(); 7073 } 7074 7075 return searchStr.length == 0 || firstMatch != null; 7076 }; 7077 7078 mxUtils.br(div); 7079 7080 var btnsCont = document.createElement('div'); 7081 btnsCont.style.left = '0px'; 7082 btnsCont.style.right = '0px'; 7083 btnsCont.style.marginTop = '6px'; 7084 btnsCont.style.padding = '0 6px 0 6px'; 7085 btnsCont.style.textAlign = 'center'; 7086 div.appendChild(btnsCont); 7087 7088 var resetBtn = mxUtils.button(mxResources.get('reset'), function() 7089 { 7090 replAllNotif.innerHTML = ''; 7091 searchInput.value = ''; 7092 searchInput.style.backgroundColor = ''; 7093 7094 if (withReplace) 7095 { 7096 replaceInput.value = ''; 7097 updateReplBtns(); 7098 } 7099 7100 lastFound = null; 7101 lastSearch = null; 7102 allChecked = false; 7103 searchInput.focus(); 7104 }); 7105 7106 resetBtn.setAttribute('title', mxResources.get('reset')); 7107 resetBtn.style.float = 'none'; 7108 resetBtn.style.width = '120px'; 7109 resetBtn.style.marginTop = '6px'; 7110 resetBtn.style.marginLeft = '8px'; 7111 resetBtn.style.overflow = 'hidden'; 7112 resetBtn.style.textOverflow = 'ellipsis'; 7113 resetBtn.className = 'geBtn'; 7114 7115 if (!withReplace) 7116 { 7117 btnsCont.appendChild(resetBtn); 7118 } 7119 7120 var btn = mxUtils.button(mxResources.get('find'), function() 7121 { 7122 try 7123 { 7124 searchInput.style.backgroundColor = search() ? '' : 7125 (Editor.isDarkMode() ? '#ff0000' : '#ffcfcf'); 7126 } 7127 catch (e) 7128 { 7129 ui.handleError(e); 7130 } 7131 }); 7132 7133 // TODO: Reset state after selection change 7134 btn.setAttribute('title', mxResources.get('find') + ' (Enter)'); 7135 btn.style.float = 'none'; 7136 btn.style.width = '120px'; 7137 btn.style.marginTop = '6px'; 7138 btn.style.marginLeft = '8px'; 7139 btn.style.overflow = 'hidden'; 7140 btn.style.textOverflow = 'ellipsis'; 7141 btn.className = 'geBtn gePrimaryBtn'; 7142 7143 btnsCont.appendChild(btn); 7144 7145 var replAllNotif = document.createElement('div'); 7146 replAllNotif.style.marginTop = '10px'; 7147 7148 if (!withReplace) 7149 { 7150 resetBtn.style.width = '90px'; 7151 btn.style.width = '90px'; 7152 } 7153 else 7154 { 7155 function replaceInLabel(str, substr, newSubstr, startIndex, style) 7156 { 7157 if (style == null || style['html'] != '1') 7158 { 7159 var replStart = str.toLowerCase().indexOf(substr, startIndex); 7160 return replStart < 0? str : str.substr(0, replStart) + newSubstr + str.substr(replStart + substr.length); 7161 } 7162 7163 var origStr = str; 7164 substr = mxUtils.htmlEntities(substr); 7165 var tagPos = [], p = -1; 7166 7167 while((p = str.indexOf('<', p + 1)) > -1) 7168 { 7169 tagPos.push(p); 7170 } 7171 7172 var tags = str.match(/<[^>]*>/g); 7173 str = str.replace(/<[^>]*>/g, ''); 7174 var lStr = str.toLowerCase(); 7175 var replStart = lStr.indexOf(substr, startIndex); 7176 7177 if (replStart < 0) 7178 { 7179 return origStr; 7180 } 7181 7182 var replEnd = replStart + substr.length; 7183 var newSubstr = mxUtils.htmlEntities(newSubstr); 7184 7185 //Tags within the replaced text is added before it 7186 var newStr = str.substr(0, replStart) + newSubstr + str.substr(replEnd); 7187 var tagDiff = 0; 7188 7189 for (var i = 0; i < tagPos.length; i++) 7190 { 7191 if (tagPos[i] - tagDiff < replStart) 7192 { 7193 newStr = newStr.substr(0, tagPos[i]) + tags[i] + newStr.substr(tagPos[i]); 7194 } 7195 else if (tagPos[i] - tagDiff < replEnd) 7196 { 7197 var inPos = replStart + tagDiff; 7198 newStr = newStr.substr(0, inPos) + tags[i] + newStr.substr(inPos); 7199 } 7200 else 7201 { 7202 var inPos = tagPos[i] + (newSubstr.length - substr.length); 7203 newStr = newStr.substr(0, inPos) + tags[i] + newStr.substr(inPos); 7204 } 7205 7206 tagDiff += tags[i].length; 7207 } 7208 7209 return newStr; 7210 }; 7211 7212 var replaceFindBtn = mxUtils.button(mxResources.get('replFind'), function() 7213 { 7214 try 7215 { 7216 if (lblMatch != null && lastFound != null && replaceInput.value) 7217 { 7218 var cell = lastFound.cell, lbl = graph.getLabel(cell); 7219 7220 if (graph.isCellEditable(cell)) 7221 { 7222 graph.model.setValue(cell, replaceInLabel(lbl, lblMatch, replaceInput.value, 7223 lblMatchPos - lblMatch.length, graph.getCurrentCellStyle(cell))); 7224 } 7225 7226 searchInput.style.backgroundColor = search(false, true) ? '' : 7227 (Editor.isDarkMode() ? '#ff0000' : '#ffcfcf'); 7228 } 7229 } 7230 catch (e) 7231 { 7232 ui.handleError(e); 7233 } 7234 }); 7235 7236 replaceFindBtn.setAttribute('title', mxResources.get('replFind')); 7237 replaceFindBtn.style.float = 'none'; 7238 replaceFindBtn.style.width = '120px'; 7239 replaceFindBtn.style.marginTop = '6px'; 7240 replaceFindBtn.style.marginLeft = '8px'; 7241 replaceFindBtn.style.overflow = 'hidden'; 7242 replaceFindBtn.style.textOverflow = 'ellipsis'; 7243 replaceFindBtn.className = 'geBtn gePrimaryBtn'; 7244 replaceFindBtn.setAttribute('disabled', 'disabled'); 7245 7246 btnsCont.appendChild(replaceFindBtn); 7247 mxUtils.br(btnsCont); 7248 7249 var replaceBtn = mxUtils.button(mxResources.get('replace'), function() 7250 { 7251 try 7252 { 7253 if (lblMatch != null && lastFound != null && replaceInput.value) 7254 { 7255 var cell = lastFound.cell, lbl = graph.getLabel(cell); 7256 7257 graph.model.setValue(cell, replaceInLabel(lbl, lblMatch, replaceInput.value, lblMatchPos - lblMatch.length, graph.getCurrentCellStyle(cell))); 7258 replaceFindBtn.setAttribute('disabled', 'disabled'); 7259 replaceBtn.setAttribute('disabled', 'disabled'); 7260 } 7261 } 7262 catch (e) 7263 { 7264 ui.handleError(e); 7265 } 7266 }); 7267 7268 replaceBtn.setAttribute('title', mxResources.get('replace')); 7269 replaceBtn.style.float = 'none'; 7270 replaceBtn.style.width = '120px'; 7271 replaceBtn.style.marginTop = '6px'; 7272 replaceBtn.style.marginLeft = '8px'; 7273 replaceBtn.style.overflow = 'hidden'; 7274 replaceBtn.style.textOverflow = 'ellipsis'; 7275 replaceBtn.className = 'geBtn gePrimaryBtn'; 7276 replaceBtn.setAttribute('disabled', 'disabled'); 7277 7278 btnsCont.appendChild(replaceBtn); 7279 7280 var replaceAllBtn = mxUtils.button(mxResources.get('replaceAll'), function() 7281 { 7282 replAllNotif.innerHTML = ''; 7283 7284 if (replaceInput.value) 7285 { 7286 var currentPage = ui.currentPage; 7287 var cells = ui.editor.graph.getSelectionCells(); 7288 ui.editor.graph.rendering = false; 7289 7290 graph.getModel().beginUpdate(); 7291 try 7292 { 7293 var safeguard = 0; 7294 var seen = {}; 7295 7296 while (search(false, true, true) && safeguard < 100) 7297 { 7298 var cell = lastFound.cell, lbl = graph.getLabel(cell); 7299 var oldSeen = seen[cell.id]; 7300 7301 if (oldSeen && oldSeen.replAllMrk == marker && oldSeen.replAllPos >= lblMatchPos) 7302 { 7303 break; 7304 } 7305 7306 seen[cell.id] = {replAllMrk: marker, replAllPos: lblMatchPos}; 7307 7308 if (graph.isCellEditable(cell)) 7309 { 7310 graph.model.setValue(cell, replaceInLabel(lbl, lblMatch, replaceInput.value, 7311 lblMatchPos - lblMatch.length, graph.getCurrentCellStyle(cell))); 7312 safeguard++; 7313 } 7314 } 7315 7316 if (currentPage != ui.currentPage) 7317 { 7318 ui.editor.graph.model.execute(new SelectPage(ui, currentPage)); 7319 } 7320 7321 mxUtils.write(replAllNotif, mxResources.get('matchesRepl', [safeguard])); 7322 } 7323 catch (e) 7324 { 7325 ui.handleError(e); 7326 } 7327 finally 7328 { 7329 graph.getModel().endUpdate(); 7330 ui.editor.graph.setSelectionCells(cells); 7331 ui.editor.graph.rendering = true; 7332 } 7333 7334 marker++; 7335 } 7336 }); 7337 7338 replaceAllBtn.setAttribute('title', mxResources.get('replaceAll')); 7339 replaceAllBtn.style.float = 'none'; 7340 replaceAllBtn.style.width = '120px'; 7341 replaceAllBtn.style.marginTop = '6px'; 7342 replaceAllBtn.style.marginLeft = '8px'; 7343 replaceAllBtn.style.overflow = 'hidden'; 7344 replaceAllBtn.style.textOverflow = 'ellipsis'; 7345 replaceAllBtn.className = 'geBtn gePrimaryBtn'; 7346 replaceAllBtn.setAttribute('disabled', 'disabled'); 7347 7348 btnsCont.appendChild(replaceAllBtn); 7349 mxUtils.br(btnsCont); 7350 btnsCont.appendChild(resetBtn); 7351 7352 var closeBtn = mxUtils.button(mxResources.get('close'), mxUtils.bind(this, function() 7353 { 7354 this.window.setVisible(false); 7355 })); 7356 7357 closeBtn.setAttribute('title', mxResources.get('close')); 7358 closeBtn.style.float = 'none'; 7359 closeBtn.style.width = '120px'; 7360 closeBtn.style.marginTop = '6px'; 7361 closeBtn.style.marginLeft = '8px'; 7362 closeBtn.style.overflow = 'hidden'; 7363 closeBtn.style.textOverflow = 'ellipsis'; 7364 closeBtn.className = 'geBtn'; 7365 7366 btnsCont.appendChild(closeBtn); 7367 mxUtils.br(btnsCont); 7368 btnsCont.appendChild(replAllNotif); 7369 } 7370 7371 mxEvent.addListener(searchInput, 'keyup', function(evt) 7372 { 7373 // Ctrl or Cmd keys 7374 if (evt.keyCode == 91 || evt.keyCode == 93 || evt.keyCode == 17) 7375 { 7376 // Workaround for lost focus on show 7377 mxEvent.consume(evt); 7378 } 7379 else if (evt.keyCode == 27) 7380 { 7381 // Escape closes window 7382 action.funct(); 7383 } 7384 else if (lastSearch != searchInput.value.toLowerCase() || evt.keyCode == 13) 7385 { 7386 try 7387 { 7388 searchInput.style.backgroundColor = search() ? '' : 7389 (Editor.isDarkMode() ? '#ff0000' : '#ffcfcf'); 7390 } 7391 catch (e) 7392 { 7393 searchInput.style.backgroundColor = Editor.isDarkMode() ? '#ff0000' : '#ffcfcf'; 7394 } 7395 } 7396 }); 7397 7398 // Ctrl+F closes window 7399 mxEvent.addListener(div, 'keydown', function(evt) 7400 { 7401 if (evt.keyCode == 70 && ui.keyHandler.isControlDown(evt) && !mxEvent.isShiftDown(evt)) 7402 { 7403 action.funct(); 7404 mxEvent.consume(evt); 7405 } 7406 }); 7407 7408 this.window = new mxWindow(mxResources.get('find') + ((withReplace) ? 7409 '/' + mxResources.get('replace') : ''), 7410 div, x, y, w, h, true, true); 7411 this.window.destroyOnClose = false; 7412 this.window.setMaximizable(false); 7413 this.window.setResizable(false); 7414 this.window.setClosable(true); 7415 7416 this.window.addListener('show', mxUtils.bind(this, function() 7417 { 7418 this.window.fit(); 7419 7420 if (this.window.isVisible()) 7421 { 7422 searchInput.focus(); 7423 7424 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 7425 { 7426 searchInput.select(); 7427 } 7428 else 7429 { 7430 document.execCommand('selectAll', false, null); 7431 } 7432 7433 if (ui.pages != null && ui.pages.length > 1) 7434 { 7435 allPagesInput.removeAttribute('disabled'); 7436 } 7437 else 7438 { 7439 allPagesInput.checked = false; 7440 allPagesInput.setAttribute('disabled', 'disabled'); 7441 } 7442 } 7443 else 7444 { 7445 graph.container.focus(); 7446 } 7447 })); 7448 7449 this.window.setLocation = function(x, y) 7450 { 7451 var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 7452 var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 7453 7454 x = Math.max(0, Math.min(x, iw - this.table.clientWidth)); 7455 y = Math.max(0, Math.min(y, ih - this.table.clientHeight - ((urlParams['sketch'] == '1') ? 3 : 48))); 7456 7457 if (this.getX() != x || this.getY() != y) 7458 { 7459 mxWindow.prototype.setLocation.apply(this, arguments); 7460 } 7461 }; 7462 7463 var resizeListener = mxUtils.bind(this, function() 7464 { 7465 var x = this.window.getX(); 7466 var y = this.window.getY(); 7467 7468 this.window.setLocation(x, y); 7469 }); 7470 7471 mxEvent.addListener(window, 'resize', resizeListener); 7472 7473 this.destroy = function() 7474 { 7475 mxEvent.removeListener(window, 'resize', resizeListener); 7476 this.window.destroy(); 7477 } 7478}; 7479 7480/** 7481 * 7482 */ 7483var FreehandWindow = function(editorUi, x, y, w, h) 7484{ 7485 var graph = editorUi.editor.graph; 7486 7487 var div = document.createElement('div'); 7488 div.style.textAlign = 'center'; 7489 div.style.userSelect = 'none'; 7490 div.style.overflow = 'hidden'; 7491 div.style.height = '100%'; 7492 7493 var startBtn = mxUtils.button(mxResources.get('startDrawing'), function() 7494 { 7495 if (graph.freehand.isDrawing()) 7496 { 7497 graph.freehand.stopDrawing(); 7498 } 7499 else 7500 { 7501 graph.freehand.startDrawing(); 7502 } 7503 }); 7504 7505 startBtn.setAttribute('title', mxResources.get('startDrawing')); 7506 startBtn.style.marginTop = '10px'; 7507 startBtn.style.width = '90%'; 7508 startBtn.style.boxSizing = 'border-box'; 7509 startBtn.style.overflow = 'hidden'; 7510 startBtn.style.textOverflow = 'ellipsis'; 7511 startBtn.style.textAlign = 'center'; 7512 startBtn.className = 'geBtn gePrimaryBtn'; 7513 7514 div.appendChild(startBtn); 7515 7516 this.window = new mxWindow(mxResources.get('freehand'), div, x, y, w, h, true, true); 7517 this.window.destroyOnClose = false; 7518 this.window.setMaximizable(false); 7519 this.window.setResizable(false); 7520 this.window.setClosable(true); 7521 7522 graph.addListener('freehandStateChanged', mxUtils.bind(this, function() 7523 { 7524 startBtn.innerHTML = ''; 7525 mxUtils.write(startBtn, mxResources.get(graph.freehand.isDrawing() ? 'stopDrawing' : 'startDrawing')); 7526 startBtn.setAttribute('title', mxResources.get(graph.freehand.isDrawing() ? 'stopDrawing' : 'startDrawing')); 7527 startBtn.className = 'geBtn' + (!graph.freehand.isDrawing() ? ' gePrimaryBtn' : ''); 7528 })); 7529 7530 this.window.addListener('show', mxUtils.bind(this, function() 7531 { 7532 this.window.fit(); 7533 })); 7534 7535 this.window.addListener('hide', mxUtils.bind(this, function() 7536 { 7537 if (graph.freehand.isDrawing()) 7538 { 7539 graph.freehand.stopDrawing(); 7540 } 7541 })); 7542 7543 this.window.setLocation = function(x, y) 7544 { 7545 var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 7546 var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 7547 7548 x = Math.max(0, Math.min(x, iw - this.table.clientWidth)); 7549 y = Math.max(0, Math.min(y, ih - this.table.clientHeight - ((urlParams['sketch'] == '1') ? 3 : 48))); 7550 7551 if (this.getX() != x || this.getY() != y) 7552 { 7553 mxWindow.prototype.setLocation.apply(this, arguments); 7554 } 7555 }; 7556 7557 var resizeListener = mxUtils.bind(this, function() 7558 { 7559 var x = this.window.getX(); 7560 var y = this.window.getY(); 7561 7562 this.window.setLocation(x, y); 7563 }); 7564 7565 mxEvent.addListener(window, 'resize', resizeListener); 7566 7567 this.destroy = function() 7568 { 7569 mxEvent.removeListener(window, 'resize', resizeListener); 7570 this.window.destroy(); 7571 } 7572}; 7573 7574/** 7575 * 7576 */ 7577var TagsWindow = function(editorUi, x, y, w, h) 7578{ 7579 var graph = editorUi.editor.graph; 7580 7581 var tagsComponent = editorUi.editor.graph.createTagsDialog(mxUtils.bind(this, function() 7582 { 7583 return this.window.isVisible(); 7584 }), null, function(allTags, updateFn) 7585 { 7586 if (graph.isEnabled()) 7587 { 7588 var dlg = new FilenameDialog(editorUi, '', mxResources.get('add'), function(newValue) 7589 { 7590 editorUi.hideDialog(); 7591 7592 if (newValue != null && newValue.length > 0) 7593 { 7594 var temp = newValue.split(' '); 7595 var tags = []; 7596 7597 for (var i = 0; i < temp.length; i++) 7598 { 7599 var token = mxUtils.trim(temp[i]); 7600 7601 if (token != '' && mxUtils.indexOf( 7602 allTags, token) < 0) 7603 { 7604 tags.push(token); 7605 } 7606 } 7607 7608 if (tags.length > 0) 7609 { 7610 if (graph.isSelectionEmpty()) 7611 { 7612 updateFn(allTags.concat(tags)); 7613 } 7614 else 7615 { 7616 graph.addTagsForCells(graph.getSelectionCells(), tags); 7617 } 7618 } 7619 } 7620 }, mxResources.get('enterValue') + ' (' + mxResources.get('tags') + ')'); 7621 7622 editorUi.showDialog(dlg.container, 300, 80, true, true); 7623 dlg.init(); 7624 } 7625 }); 7626 7627 var div = tagsComponent.div; 7628 this.window = new mxWindow(mxResources.get('tags'), div, x, y, w, h, true, true); 7629 this.window.minimumSize = new mxRectangle(0, 0, 212, 120); 7630 this.window.destroyOnClose = false; 7631 this.window.setMaximizable(false); 7632 this.window.setResizable(true); 7633 this.window.setClosable(true); 7634 7635 this.window.addListener('show', mxUtils.bind(this, function() 7636 { 7637 tagsComponent.refresh(); 7638 this.window.fit(); 7639 })); 7640 7641 this.window.setLocation = function(x, y) 7642 { 7643 var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 7644 var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 7645 7646 x = Math.max(0, Math.min(x, iw - this.table.clientWidth)); 7647 y = Math.max(0, Math.min(y, ih - this.table.clientHeight - ((urlParams['sketch'] == '1') ? 3 : 48))); 7648 7649 if (this.getX() != x || this.getY() != y) 7650 { 7651 mxWindow.prototype.setLocation.apply(this, arguments); 7652 } 7653 }; 7654 7655 var resizeListener = mxUtils.bind(this, function() 7656 { 7657 var x = this.window.getX(); 7658 var y = this.window.getY(); 7659 7660 this.window.setLocation(x, y); 7661 }); 7662 7663 mxEvent.addListener(window, 'resize', resizeListener); 7664 7665 this.destroy = function() 7666 { 7667 mxEvent.removeListener(window, 'resize', resizeListener); 7668 this.window.destroy(); 7669 } 7670}; 7671 7672/** 7673 * Constructs a new auth dialog. 7674 */ 7675var AuthDialog = function(editorUi, peer, showRememberOption, fn) 7676{ 7677 var div = document.createElement('div'); 7678 div.style.textAlign = 'center'; 7679 7680 var hd = document.createElement('p'); 7681 hd.style.fontSize = '16pt'; 7682 hd.style.padding = '0px'; 7683 hd.style.margin = '0px'; 7684 hd.style.color = 'gray'; 7685 7686 mxUtils.write(hd, mxResources.get('authorizationRequired')); 7687 7688 var service = 'Unknown'; 7689 7690 var img = document.createElement('img'); 7691 img.setAttribute('border', '0'); 7692 img.setAttribute('align', 'absmiddle'); 7693 img.style.marginRight = '10px'; 7694 7695 if (peer == editorUi.drive) 7696 { 7697 service = mxResources.get('googleDrive'); 7698 img.src = IMAGE_PATH + '/google-drive-logo-white.svg'; 7699 } 7700 else if (peer == editorUi.dropbox) 7701 { 7702 service = mxResources.get('dropbox'); 7703 img.src = IMAGE_PATH + '/dropbox-logo-white.svg'; 7704 } 7705 else if (peer == editorUi.oneDrive) 7706 { 7707 service = mxResources.get('oneDrive'); 7708 img.src = IMAGE_PATH + '/onedrive-logo-white.svg'; 7709 } 7710 else if (peer == editorUi.gitHub) 7711 { 7712 service = mxResources.get('github'); 7713 img.src = IMAGE_PATH + '/github-logo-white.svg'; 7714 } 7715 else if (peer == editorUi.gitLab) 7716 { 7717 service = mxResources.get('gitlab'); 7718 img.src = IMAGE_PATH + '/gitlab-logo.svg'; 7719 img.style.width = '32px'; 7720 } 7721 else if (peer == editorUi.notion) 7722 { 7723 service = mxResources.get('notion'); 7724 img.src = IMAGE_PATH + '/notion-logo-white.svg'; 7725 img.style.width = '32px'; 7726 } 7727 else if (peer == editorUi.trello) 7728 { 7729 service = mxResources.get('trello'); 7730 img.src = IMAGE_PATH + '/trello-logo-white.svg'; 7731 } 7732 7733 var p = document.createElement('p'); 7734 mxUtils.write(p, mxResources.get('authorizeThisAppIn', [service])); 7735 7736 var cb = document.createElement('input'); 7737 cb.setAttribute('type', 'checkbox'); 7738 7739 var button = mxUtils.button(mxResources.get('authorize'), function() 7740 { 7741 fn(cb.checked); 7742 }); 7743 7744 button.insertBefore(img, button.firstChild); 7745 button.style.marginTop = '6px'; 7746 button.className = 'geBigButton'; 7747 button.style.fontSize = '18px'; 7748 button.style.padding = '14px'; 7749 7750 div.appendChild(hd); 7751 div.appendChild(p); 7752 div.appendChild(button); 7753 7754 if (showRememberOption) 7755 { 7756 var p2 = document.createElement('p'); 7757 p2.style.marginTop = '20px'; 7758 p2.appendChild(cb); 7759 var span = document.createElement('span'); 7760 mxUtils.write(span, ' ' + mxResources.get('rememberMe')); 7761 p2.appendChild(span); 7762 div.appendChild(p2); 7763 cb.checked = true; 7764 cb.defaultChecked = true; 7765 7766 mxEvent.addListener(span, 'click', function(evt) 7767 { 7768 cb.checked = !cb.checked; 7769 mxEvent.consume(evt); 7770 }); 7771 } 7772 7773 this.container = div; 7774}; 7775 7776var MoreShapesDialog = function(editorUi, expanded, entries) 7777{ 7778 entries = (entries != null) ? entries : editorUi.sidebar.entries; 7779 var div = document.createElement('div'); 7780 var newEntries = []; 7781 7782 // Adds custom sections first 7783 if (editorUi.sidebar.customEntries != null) 7784 { 7785 for (var i = 0; i < editorUi.sidebar.customEntries.length; i++) 7786 { 7787 var section = editorUi.sidebar.customEntries[i]; 7788 var tmp = {title: editorUi.getResource(section.title), entries: []}; 7789 7790 for (var j = 0; j < section.entries.length; j++) 7791 { 7792 var entry = section.entries[j]; 7793 tmp.entries.push({id: entry.id, title: 7794 editorUi.getResource(entry.title), 7795 desc: editorUi.getResource(entry.desc), 7796 image: entry.preview}); 7797 } 7798 7799 newEntries.push(tmp); 7800 } 7801 } 7802 7803 // Adds built-in sections and filter entries 7804 for (var i = 0; i < entries.length; i++) 7805 { 7806 if (editorUi.sidebar.enabledLibraries == null) 7807 { 7808 newEntries.push(entries[i]); 7809 } 7810 else 7811 { 7812 var tmp = {title: entries[i].title, entries: []}; 7813 7814 for (var j = 0; j < entries[i].entries.length; j++) 7815 { 7816 if (mxUtils.indexOf(editorUi.sidebar.enabledLibraries, 7817 entries[i].entries[j].id) >= 0) 7818 { 7819 tmp.entries.push(entries[i].entries[j]); 7820 } 7821 } 7822 7823 if (tmp.entries.length > 0) 7824 { 7825 newEntries.push(tmp); 7826 } 7827 } 7828 } 7829 7830 entries = newEntries; 7831 7832 if (expanded) 7833 { 7834 var addEntries = mxUtils.bind(this, function(e) 7835 { 7836 for (var i = 0; i < e.length; i++) 7837 { 7838 (function(section) 7839 { 7840 var title = listEntry.cloneNode(false); 7841 title.style.fontWeight = 'bold'; 7842 title.style.backgroundColor = Editor.isDarkMode() ? '#505759' : '#e5e5e5'; 7843 title.style.padding = '6px 0px 6px 20px'; 7844 mxUtils.write(title, section.title); 7845 list.appendChild(title); 7846 7847 for (var j = 0; j < section.entries.length; j++) 7848 { 7849 (function(entry) 7850 { 7851 var option = listEntry.cloneNode(false); 7852 option.style.cursor = 'pointer'; 7853 option.style.padding = '4px 0px 4px 20px'; 7854 option.style.whiteSpace = 'nowrap'; 7855 option.style.overflow = 'hidden'; 7856 option.style.textOverflow = 'ellipsis'; 7857 option.setAttribute('title', entry.title + ' (' + entry.id + ')'); 7858 7859 var checkbox = document.createElement('input'); 7860 checkbox.setAttribute('type', 'checkbox'); 7861 checkbox.checked = editorUi.sidebar.isEntryVisible(entry.id); 7862 checkbox.defaultChecked = checkbox.checked; 7863 option.appendChild(checkbox); 7864 mxUtils.write(option, ' ' + entry.title); 7865 7866 list.appendChild(option); 7867 7868 var itemClicked = function(evt) 7869 { 7870 if (evt == null || mxEvent.getSource(evt).nodeName != 'INPUT') 7871 { 7872 preview.style.textAlign = 'center'; 7873 preview.style.padding = '0px'; 7874 preview.style.color = ''; 7875 preview.innerHTML = ''; 7876 7877 if (entry.desc != null) 7878 { 7879 var pre = document.createElement('pre'); 7880 pre.style.boxSizing = 'border-box'; 7881 pre.style.fontFamily = 'inherit'; 7882 pre.style.margin = '20px'; 7883 pre.style.right = '0px'; 7884 pre.style.textAlign = 'left'; 7885 mxUtils.write(pre, entry.desc); 7886 preview.appendChild(pre); 7887 } 7888 7889 if (entry.imageCallback != null) 7890 { 7891 entry.imageCallback(preview); 7892 } 7893 else if (entry.image != null) 7894 { 7895 preview.innerHTML += '<img border="0" src="' + entry.image + '"/>'; 7896 } 7897 else if (entry.desc == null) 7898 { 7899 preview.style.padding = '20px'; 7900 preview.style.color = 'rgb(179, 179, 179)'; 7901 mxUtils.write(preview, mxResources.get('noPreview')); 7902 } 7903 7904 if (currentListItem != null) 7905 { 7906 currentListItem.style.backgroundColor = ''; 7907 } 7908 7909 currentListItem = option; 7910 currentListItem.style.backgroundColor = Editor.isDarkMode() ? '#000000' : '#ebf2f9'; 7911 7912 if (evt != null) 7913 { 7914 mxEvent.consume(evt); 7915 } 7916 } 7917 }; 7918 7919 mxEvent.addListener(option, 'click', itemClicked); 7920 mxEvent.addListener(option, 'dblclick', function(evt) 7921 { 7922 checkbox.checked = !checkbox.checked; 7923 mxEvent.consume(evt); 7924 }); 7925 7926 applyFunctions.push(function() 7927 { 7928 return (checkbox.checked) ? entry.id : null; 7929 }); 7930 7931 // Selects first entry 7932 if (i == 0 && j == 0) 7933 { 7934 itemClicked(); 7935 } 7936 })(section.entries[j]); 7937 } 7938 })(e[i]); 7939 } 7940 }); 7941 7942 var hd = document.createElement('div'); 7943 hd.className = 'geDialogTitle'; 7944 mxUtils.write(hd, mxResources.get('shapes')); 7945 hd.style.position = 'absolute'; 7946 hd.style.top = '0px'; 7947 hd.style.left = '0px'; 7948 hd.style.lineHeight = '40px'; 7949 hd.style.height = '40px'; 7950 hd.style.right = '0px'; 7951 7952 var list = document.createElement('div'); 7953 var preview = document.createElement('div'); 7954 7955 list.style.position = 'absolute'; 7956 list.style.top = '40px'; 7957 list.style.left = '0px'; 7958 list.style.width = '202px'; 7959 list.style.bottom = '60px'; 7960 list.style.overflow = 'auto'; 7961 7962 preview.style.position = 'absolute'; 7963 preview.style.left = '202px'; 7964 preview.style.right = '0px'; 7965 preview.style.top = '40px'; 7966 preview.style.bottom = '60px'; 7967 preview.style.overflow = 'auto'; 7968 preview.style.borderLeft = '1px solid rgb(211, 211, 211)'; 7969 preview.style.textAlign = 'center'; 7970 7971 var currentListItem = null; 7972 var applyFunctions = []; 7973 7974 var listEntry = document.createElement('div'); 7975 listEntry.style.position = 'relative'; 7976 listEntry.style.left = '0px'; 7977 listEntry.style.right = '0px'; 7978 7979 addEntries(entries); 7980 div.style.padding = '30px'; 7981 7982 div.appendChild(hd); 7983 div.appendChild(list); 7984 div.appendChild(preview); 7985 7986 var buttons = document.createElement('div'); 7987 buttons.className = 'geDialogFooter'; 7988 buttons.style.position = 'absolute'; 7989 buttons.style.paddingRight = '16px'; 7990 buttons.style.color = 'gray'; 7991 buttons.style.left = '0px'; 7992 buttons.style.right = '0px'; 7993 buttons.style.bottom = '0px'; 7994 buttons.style.height = '60px'; 7995 buttons.style.lineHeight = '52px'; 7996 7997 var cb = document.createElement('input'); 7998 cb.setAttribute('type', 'checkbox'); 7999 8000 if (isLocalStorage || mxClient.IS_CHROMEAPP) 8001 { 8002 var span = document.createElement('span'); 8003 span.style.paddingRight = '20px'; 8004 span.appendChild(cb); 8005 mxUtils.write(span, ' ' + mxResources.get('rememberThisSetting')); 8006 cb.checked = true; 8007 cb.defaultChecked = true; 8008 8009 mxEvent.addListener(span, 'click', function(evt) 8010 { 8011 if (mxEvent.getSource(evt) != cb) 8012 { 8013 cb.checked = !cb.checked; 8014 mxEvent.consume(evt); 8015 } 8016 }); 8017 8018 buttons.appendChild(span); 8019 } 8020 8021 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 8022 { 8023 editorUi.hideDialog(); 8024 }); 8025 cancelBtn.className = 'geBtn'; 8026 8027 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 8028 { 8029 editorUi.hideDialog(); 8030 var libs = []; 8031 8032 for (var i = 0; i < applyFunctions.length; i++) 8033 { 8034 var lib = applyFunctions[i].apply(this, arguments); 8035 8036 if (lib != null) 8037 { 8038 libs.push(lib); 8039 } 8040 } 8041 8042 editorUi.sidebar.showEntries(libs.join(';'), cb.checked, true); 8043 }); 8044 applyBtn.className = 'geBtn gePrimaryBtn'; 8045 8046 if (editorUi.editor.cancelFirst) 8047 { 8048 buttons.appendChild(cancelBtn); 8049 buttons.appendChild(applyBtn); 8050 } 8051 else 8052 { 8053 buttons.appendChild(applyBtn); 8054 buttons.appendChild(cancelBtn); 8055 } 8056 8057 div.appendChild(buttons); 8058 } 8059 else 8060 { 8061 var libFS = document.createElement('table'); 8062 var tbody = document.createElement('tbody'); 8063 div.style.height = '100%'; 8064 div.style.overflow = 'auto'; 8065 var row = document.createElement('tr'); 8066 libFS.style.width = '100%'; 8067 8068 var leftDiv = document.createElement('td'); 8069 var midDiv = document.createElement('td'); 8070 var rightDiv = document.createElement('td'); 8071 8072 var addLibCB = mxUtils.bind(this, function(wrapperDiv, title, key) 8073 { 8074 var libCB = document.createElement('input'); 8075 libCB.type = 'checkbox'; 8076 libFS.appendChild(libCB); 8077 8078 libCB.checked = editorUi.sidebar.isEntryVisible(key); 8079 8080 var libSpan = document.createElement('span'); 8081 mxUtils.write(libSpan, title); 8082 8083 var label = document.createElement('div'); 8084 label.style.display = 'block'; 8085 label.appendChild(libCB); 8086 label.appendChild(libSpan); 8087 8088 mxEvent.addListener(libSpan, 'click', function(evt) 8089 { 8090 libCB.checked = !libCB.checked; 8091 mxEvent.consume(evt); 8092 }); 8093 8094 wrapperDiv.appendChild(label); 8095 8096 return function() 8097 { 8098 return (libCB.checked) ? key : null; 8099 }; 8100 }); 8101 8102 row.appendChild(leftDiv); 8103 row.appendChild(midDiv); 8104 row.appendChild(rightDiv); 8105 8106 tbody.appendChild(row); 8107 libFS.appendChild(tbody); 8108 8109 var applyFunctions = []; 8110 var count = 0; 8111 8112 // Counts total number of entries 8113 for (var i = 0; i < entries.length; i++) 8114 { 8115 for (var j = 0; j < entries[i].entries.length; j++) 8116 { 8117 count++; 8118 } 8119 } 8120 8121 // Distributes entries on columns 8122 var cols = [leftDiv, midDiv, rightDiv]; 8123 var counter = 0; 8124 8125 for (var i = 0; i < entries.length; i++) 8126 { 8127 (function(section) 8128 { 8129 for (var j = 0; j < section.entries.length; j++) 8130 { 8131 (function(entry) 8132 { 8133 var index = Math.floor(counter / (count / 3)); 8134 applyFunctions.push(addLibCB(cols[index], entry.title, entry.id)); 8135 counter++; 8136 })(section.entries[j]); 8137 } 8138 })(entries[i]); 8139 } 8140 8141 div.appendChild(libFS); 8142 8143 var remember = document.createElement('div'); 8144 remember.style.marginTop = '18px'; 8145 remember.style.textAlign = 'center'; 8146 8147 var cb = document.createElement('input'); 8148 8149 if (isLocalStorage) 8150 { 8151 cb.setAttribute('type', 'checkbox'); 8152 cb.checked = true; 8153 cb.defaultChecked = true; 8154 remember.appendChild(cb); 8155 var span = document.createElement('span'); 8156 mxUtils.write(span, ' ' + mxResources.get('rememberThisSetting')); 8157 remember.appendChild(span); 8158 8159 mxEvent.addListener(span, 'click', function(evt) 8160 { 8161 cb.checked = !cb.checked; 8162 mxEvent.consume(evt); 8163 }); 8164 } 8165 8166 div.appendChild(remember); 8167 8168 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 8169 { 8170 editorUi.hideDialog(); 8171 }); 8172 cancelBtn.className = 'geBtn'; 8173 8174 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 8175 { 8176 var libs = ['search']; 8177 8178 for (var i = 0; i < applyFunctions.length; i++) 8179 { 8180 var lib = applyFunctions[i].apply(this, arguments); 8181 8182 if (lib != null) 8183 { 8184 libs.push(lib); 8185 } 8186 } 8187 8188 editorUi.sidebar.showEntries((libs.length > 0) ? libs.join(';') : '', cb.checked); 8189 editorUi.hideDialog(); 8190 }); 8191 applyBtn.className = 'geBtn gePrimaryBtn'; 8192 8193 var buttons = document.createElement('div'); 8194 buttons.style.marginTop = '26px'; 8195 buttons.style.textAlign = 'right'; 8196 8197 if (editorUi.editor.cancelFirst) 8198 { 8199 buttons.appendChild(cancelBtn); 8200 buttons.appendChild(applyBtn); 8201 } 8202 else 8203 { 8204 buttons.appendChild(applyBtn); 8205 buttons.appendChild(cancelBtn); 8206 } 8207 8208 div.appendChild(buttons); 8209 } 8210 8211 this.container = div; 8212}; 8213 8214var PluginsDialog = function(editorUi, addFn, delFn) 8215{ 8216 var div = document.createElement('div'); 8217 var inner = document.createElement('div'); 8218 8219 inner.style.height = '120px'; 8220 inner.style.overflow = 'auto'; 8221 8222 var plugins = mxSettings.getPlugins().slice(); 8223 8224 function refresh() 8225 { 8226 if (plugins.length == 0) 8227 { 8228 inner.innerHTML = mxUtils.htmlEntities(mxResources.get('noPlugins')); 8229 } 8230 else 8231 { 8232 inner.innerHTML = ''; 8233 8234 for (var i = 0; i < plugins.length; i++) 8235 { 8236 var span = document.createElement('span'); 8237 span.style.whiteSpace = 'nowrap'; 8238 8239 var img = document.createElement('span'); 8240 img.className = 'geSprite geSprite-delete'; 8241 img.style.position = 'relative'; 8242 img.style.cursor = 'pointer'; 8243 img.style.top = '5px'; 8244 img.style.marginRight = '4px'; 8245 img.style.display = 'inline-block'; 8246 span.appendChild(img); 8247 8248 mxUtils.write(span, plugins[i]); 8249 inner.appendChild(span); 8250 8251 mxUtils.br(inner); 8252 8253 mxEvent.addListener(img, 'click', (function(index) 8254 { 8255 return function() 8256 { 8257 editorUi.confirm(mxResources.get('delete') + ' "' + plugins[index] + '"?', function() 8258 { 8259 if (delFn != null) 8260 { 8261 delFn(plugins[index]); 8262 } 8263 8264 plugins.splice(index, 1); 8265 refresh(); 8266 }); 8267 }; 8268 })(i)); 8269 } 8270 } 8271 } 8272 8273 div.appendChild(inner); 8274 refresh(); 8275 8276 var addBtn = mxUtils.button(mxResources.get('add') + '...', addFn != null? function() 8277 { 8278 addFn(function(newPlugin) 8279 { 8280 if (newPlugin && mxUtils.indexOf(plugins, newPlugin) < 0) 8281 { 8282 plugins.push(newPlugin); 8283 } 8284 8285 refresh(); 8286 }); 8287 } 8288 : function() 8289 { 8290 var div = document.createElement('div'); 8291 8292 var title = document.createElement('span'); 8293 title.style.marginTop = '6px'; 8294 mxUtils.write(title, mxResources.get('builtinPlugins') + ': '); 8295 div.appendChild(title); 8296 8297 var pluginsSelect = document.createElement('select'); 8298 pluginsSelect.style.width = '150px'; 8299 8300 for (var i = 0; i < App.publicPlugin.length; i++) 8301 { 8302 var option = document.createElement('option'); 8303 mxUtils.write(option, App.publicPlugin[i]); 8304 option.value = App.publicPlugin[i]; 8305 pluginsSelect.appendChild(option); 8306 } 8307 8308 div.appendChild(pluginsSelect); 8309 mxUtils.br(div); 8310 mxUtils.br(div); 8311 8312 var customBtn = mxUtils.button(mxResources.get('custom') + '...', function() 8313 { 8314 var dlg = new FilenameDialog(editorUi, '', mxResources.get('add'), function(newValue) 8315 { 8316 editorUi.hideDialog(); 8317 8318 if (newValue != null && newValue.length > 0) 8319 { 8320 var tokens = newValue.split(';'); 8321 8322 for (var i = 0; i < tokens.length; i++) 8323 { 8324 var token = tokens[i]; 8325 var url = App.pluginRegistry[token]; 8326 8327 if (url != null) 8328 { 8329 token = url; 8330 } 8331 8332 if (token.length > 0 && mxUtils.indexOf(plugins, token) < 0) 8333 { 8334 plugins.push(token); 8335 } 8336 } 8337 8338 refresh(); 8339 } 8340 }, mxResources.get('enterValue') + ' (' + mxResources.get('url') + ')'); 8341 8342 editorUi.showDialog(dlg.container, 300, 80, true, true); 8343 dlg.init(); 8344 }); 8345 8346 customBtn.className = 'geBtn'; 8347 8348 var dlg = new CustomDialog(editorUi, div, mxUtils.bind(this, function() 8349 { 8350 var token = App.pluginRegistry[pluginsSelect.value]; 8351 8352 if (mxUtils.indexOf(plugins, token) < 0) 8353 { 8354 plugins.push(token); 8355 refresh(); 8356 } 8357 }), null, null, null, customBtn); 8358 editorUi.showDialog(dlg.container, 300, 100, true, true); 8359 }); 8360 8361 addBtn.className = 'geBtn'; 8362 8363 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 8364 { 8365 editorUi.hideDialog(); 8366 }); 8367 8368 cancelBtn.className = 'geBtn'; 8369 8370 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 8371 { 8372 mxSettings.setPlugins(plugins); 8373 mxSettings.save(); 8374 editorUi.hideDialog(); 8375 editorUi.alert(mxResources.get('restartForChangeRequired')); 8376 }); 8377 8378 applyBtn.className = 'geBtn gePrimaryBtn'; 8379 8380 var buttons = document.createElement('div'); 8381 buttons.style.marginTop = '14px'; 8382 buttons.style.textAlign = 'right'; 8383 8384 var helpBtn = mxUtils.button(mxResources.get('help'), function() 8385 { 8386 editorUi.openLink('https://www.diagrams.net/doc/faq/plugins'); 8387 }); 8388 8389 helpBtn.className = 'geBtn'; 8390 8391 if (editorUi.isOffline() && !mxClient.IS_CHROMEAPP) 8392 { 8393 helpBtn.style.display = 'none'; 8394 } 8395 8396 buttons.appendChild(helpBtn); 8397 8398 if (editorUi.editor.cancelFirst) 8399 { 8400 buttons.appendChild(cancelBtn); 8401 buttons.appendChild(addBtn); 8402 buttons.appendChild(applyBtn); 8403 } 8404 else 8405 { 8406 buttons.appendChild(addBtn); 8407 buttons.appendChild(applyBtn); 8408 buttons.appendChild(cancelBtn); 8409 } 8410 8411 div.appendChild(buttons); 8412 8413 this.container = div; 8414}; 8415 8416var CropImageDialog = function(editorUi, image, fn) 8417{ 8418 var div = document.createElement('div'); 8419 8420 var croppieDiv = document.createElement('div'); 8421 croppieDiv.style.width = '300px'; 8422 croppieDiv.style.height = '300px'; 8423 div.appendChild(croppieDiv); 8424 var croppie = null; 8425 8426 function createCroppie(isCircle) 8427 { 8428 if (croppie != null) 8429 { 8430 croppie.destroy(); 8431 } 8432 8433 if (isCircle) 8434 { 8435 croppie = new Croppie(croppieDiv, { 8436 viewport: { width: 150, height: 150, type: 'circle' }, 8437 enableExif: true, 8438 showZoomer: false, 8439 enableResize: false, 8440 enableOrientation: true 8441 }); 8442 8443 croppie.bind({ 8444 url: image 8445 }); 8446 } 8447 else 8448 { 8449 croppie = new Croppie(croppieDiv, { 8450 viewport: { width: 150, height: 150, type: 'square' }, 8451 enableExif: true, 8452 showZoomer: false, 8453 enableResize: true, 8454 enableOrientation: true 8455 }); 8456 8457 croppie.bind({ 8458 url: image 8459 }); 8460 } 8461 }; 8462 8463 this.init = function() 8464 { 8465 createCroppie(); 8466 }; 8467 8468 var circleInput = document.createElement('input'); 8469 circleInput.setAttribute('type', 'checkbox'); 8470 circleInput.setAttribute('id', 'croppieCircle'); 8471 circleInput.style.margin = '5px'; 8472 div.appendChild(circleInput); 8473 8474 var circleLbl = document.createElement('label'); 8475 circleLbl.setAttribute('for', 'croppieCircle'); 8476 mxUtils.write(circleLbl, mxResources.get('circle')); 8477 div.appendChild(circleLbl); 8478 8479 var wrap, btnLeft, btnRight, iLeft, iRight; 8480 8481 wrap = document.createElement('div'); 8482 btnLeft = document.createElement('button'); 8483 btnRight = document.createElement('button'); 8484 8485 wrap.appendChild(btnLeft); 8486 wrap.appendChild(btnRight); 8487 8488 iLeft = document.createElement('i'); 8489 iRight = document.createElement('i'); 8490 btnLeft.appendChild(iLeft); 8491 btnRight.appendChild(iRight); 8492 8493 wrap.className = 'cr-rotate-controls'; 8494 wrap.style.float = 'right'; 8495 wrap.style.position = 'inherit'; 8496 btnLeft.className = 'cr-rotate-l'; 8497 btnRight.className = 'cr-rotate-r'; 8498 8499 div.appendChild(wrap); 8500 8501 btnLeft.addEventListener('click', function () 8502 { 8503 croppie.rotate(-90); 8504 }); 8505 8506 btnRight.addEventListener('click', function () 8507 { 8508 croppie.rotate(90); 8509 }); 8510 8511 mxEvent.addListener(circleInput, 'change', function() 8512 { 8513 createCroppie(this.checked); 8514 }); 8515 8516 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 8517 { 8518 editorUi.hideDialog(); 8519 }); 8520 cancelBtn.className = 'geBtn'; 8521 8522 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 8523 { 8524 croppie.result({type: 'base64', size: 'original'}).then(function(base64Img) { 8525 fn(base64Img); 8526 editorUi.hideDialog(); 8527 }); 8528 }); 8529 8530 applyBtn.className = 'geBtn gePrimaryBtn'; 8531 8532 var buttons = document.createElement('div'); 8533 buttons.style.marginTop = '20px'; 8534 buttons.style.textAlign = 'right'; 8535 8536 if (editorUi.editor.cancelFirst) 8537 { 8538 buttons.appendChild(cancelBtn); 8539 buttons.appendChild(applyBtn); 8540 } 8541 else 8542 { 8543 buttons.appendChild(applyBtn); 8544 buttons.appendChild(cancelBtn); 8545 } 8546 8547 div.appendChild(buttons); 8548 8549 this.container = div; 8550}; 8551 8552var EditGeometryDialog = function(editorUi, vertices) 8553{ 8554 var graph = editorUi.editor.graph; 8555 var geo = (vertices.length == 1) ? graph.getCellGeometry(vertices[0]) : null; 8556 var div = document.createElement('div'); 8557 8558 var table = document.createElement('table'); 8559 var tbody = document.createElement('tbody'); 8560 var row = document.createElement('tr'); 8561 var left = document.createElement('td'); 8562 var right = document.createElement('td'); 8563 table.style.paddingLeft = '6px'; 8564 8565 mxUtils.write(left, mxResources.get('relative') + ':'); 8566 8567 var relInput = document.createElement('input'); 8568 relInput.setAttribute('type', 'checkbox'); 8569 8570 if (geo != null && geo.relative) 8571 { 8572 relInput.setAttribute('checked', 'checked'); 8573 relInput.defaultChecked = true; 8574 } 8575 8576 this.init = function() 8577 { 8578 relInput.focus(); 8579 }; 8580 8581 right.appendChild(relInput); 8582 8583 row.appendChild(left); 8584 row.appendChild(right); 8585 8586 tbody.appendChild(row); 8587 8588 row = document.createElement('tr'); 8589 left = document.createElement('td'); 8590 right = document.createElement('td'); 8591 8592 mxUtils.write(left, mxResources.get('left') + ':'); 8593 8594 var xInput = document.createElement('input'); 8595 xInput.setAttribute('type', 'text'); 8596 xInput.style.width = '100px'; 8597 xInput.value = (geo != null) ? geo.x : ''; 8598 8599 right.appendChild(xInput); 8600 8601 row.appendChild(left); 8602 row.appendChild(right); 8603 8604 tbody.appendChild(row); 8605 8606 row = document.createElement('tr'); 8607 left = document.createElement('td'); 8608 right = document.createElement('td'); 8609 8610 mxUtils.write(left, mxResources.get('top') + ':'); 8611 8612 var yInput = document.createElement('input'); 8613 yInput.setAttribute('type', 'text'); 8614 yInput.style.width = '100px'; 8615 yInput.value = (geo != null) ? geo.y : ''; 8616 8617 right.appendChild(yInput); 8618 8619 row.appendChild(left); 8620 row.appendChild(right); 8621 8622 tbody.appendChild(row); 8623 8624 row = document.createElement('tr'); 8625 left = document.createElement('td'); 8626 right = document.createElement('td'); 8627 8628 mxUtils.write(left, mxResources.get('dx') + ':'); 8629 8630 var dxInput = document.createElement('input'); 8631 dxInput.setAttribute('type', 'text'); 8632 dxInput.style.width = '100px'; 8633 dxInput.value = (geo != null && geo.offset != null) ? geo.offset.x : ''; 8634 8635 right.appendChild(dxInput); 8636 8637 row.appendChild(left); 8638 row.appendChild(right); 8639 8640 tbody.appendChild(row); 8641 8642 row = document.createElement('tr'); 8643 left = document.createElement('td'); 8644 right = document.createElement('td'); 8645 8646 mxUtils.write(left, mxResources.get('dy') + ':'); 8647 8648 var dyInput = document.createElement('input'); 8649 dyInput.setAttribute('type', 'text'); 8650 dyInput.style.width = '100px'; 8651 dyInput.value = (geo != null && geo.offset != null) ? geo.offset.y : ''; 8652 8653 right.appendChild(dyInput); 8654 8655 row.appendChild(left); 8656 row.appendChild(right); 8657 8658 tbody.appendChild(row); 8659 8660 row = document.createElement('tr'); 8661 left = document.createElement('td'); 8662 right = document.createElement('td'); 8663 8664 mxUtils.write(left, mxResources.get('width') + ':'); 8665 8666 var wInput = document.createElement('input'); 8667 wInput.setAttribute('type', 'text'); 8668 wInput.style.width = '100px'; 8669 wInput.value = (geo != null) ? geo.width : ''; 8670 8671 right.appendChild(wInput); 8672 8673 row.appendChild(left); 8674 row.appendChild(right); 8675 8676 tbody.appendChild(row); 8677 8678 row = document.createElement('tr'); 8679 left = document.createElement('td'); 8680 right = document.createElement('td'); 8681 8682 mxUtils.write(left, mxResources.get('height') + ':'); 8683 8684 var hInput = document.createElement('input'); 8685 hInput.setAttribute('type', 'text'); 8686 hInput.style.width = '100px'; 8687 hInput.value = (geo != null) ? geo.height : ''; 8688 8689 right.appendChild(hInput); 8690 8691 row.appendChild(left); 8692 row.appendChild(right); 8693 8694 tbody.appendChild(row); 8695 8696 row = document.createElement('tr'); 8697 left = document.createElement('td'); 8698 right = document.createElement('td'); 8699 8700 mxUtils.write(left, mxResources.get('rotation') + ':'); 8701 8702 var rotInput = document.createElement('input'); 8703 rotInput.setAttribute('type', 'text'); 8704 rotInput.style.width = '100px'; 8705 rotInput.value = (vertices.length == 1) ? mxUtils.getValue(graph.getCellStyle(vertices[0]), 8706 mxConstants.STYLE_ROTATION, 0) : ''; 8707 8708 right.appendChild(rotInput); 8709 8710 row.appendChild(left); 8711 row.appendChild(right); 8712 8713 tbody.appendChild(row); 8714 8715 table.appendChild(tbody); 8716 div.appendChild(table); 8717 8718 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 8719 { 8720 editorUi.hideDialog(); 8721 }); 8722 8723 cancelBtn.className = 'geBtn'; 8724 8725 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 8726 { 8727 editorUi.hideDialog(); 8728 8729 graph.getModel().beginUpdate(); 8730 try 8731 { 8732 for (var i = 0; i < vertices.length; i++) 8733 { 8734 var g = graph.getCellGeometry(vertices[i]); 8735 8736 if (g != null) 8737 { 8738 g = g.clone(); 8739 8740 if (graph.isCellMovable(vertices[i])) 8741 { 8742 g.relative = relInput.checked; 8743 8744 if (mxUtils.trim(xInput.value).length > 0) 8745 { 8746 g.x = Number(xInput.value); 8747 } 8748 8749 if (mxUtils.trim(yInput.value).length > 0) 8750 { 8751 g.y = Number(yInput.value); 8752 } 8753 8754 if (mxUtils.trim(dxInput.value).length > 0) 8755 { 8756 if (g.offset == null) 8757 { 8758 g.offset = new mxPoint(); 8759 } 8760 8761 g.offset.x = Number(dxInput.value); 8762 } 8763 8764 if (mxUtils.trim(dyInput.value).length > 0) 8765 { 8766 if (g.offset == null) 8767 { 8768 g.offset = new mxPoint(); 8769 } 8770 8771 g.offset.y = Number(dyInput.value); 8772 } 8773 } 8774 8775 if (graph.isCellResizable(vertices[i])) 8776 { 8777 if (mxUtils.trim(wInput.value).length > 0) 8778 { 8779 g.width = Number(wInput.value); 8780 } 8781 8782 if (mxUtils.trim(hInput.value).length > 0) 8783 { 8784 g.height = Number(hInput.value); 8785 } 8786 } 8787 8788 graph.getModel().setGeometry(vertices[i], g); 8789 } 8790 8791 if (mxUtils.trim(rotInput.value).length > 0) 8792 { 8793 graph.setCellStyles(mxConstants.STYLE_ROTATION, Number(rotInput.value), [vertices[i]]); 8794 } 8795 } 8796 } 8797 finally 8798 { 8799 graph.getModel().endUpdate(); 8800 } 8801 }); 8802 8803 applyBtn.className = 'geBtn gePrimaryBtn'; 8804 8805 mxEvent.addListener(div, 'keypress', function(e) 8806 { 8807 if (e.keyCode == 13) 8808 { 8809 applyBtn.click(); 8810 } 8811 }); 8812 8813 var buttons = document.createElement('div'); 8814 buttons.style.marginTop = '20px'; 8815 buttons.style.textAlign = 'right'; 8816 8817 if (editorUi.editor.cancelFirst) 8818 { 8819 buttons.appendChild(cancelBtn); 8820 buttons.appendChild(applyBtn); 8821 } 8822 else 8823 { 8824 buttons.appendChild(applyBtn); 8825 buttons.appendChild(cancelBtn); 8826 } 8827 8828 div.appendChild(buttons); 8829 8830 this.container = div; 8831}; 8832 8833/** 8834 * Constructs a new dialog for creating files from templates. 8835 */ 8836var LibraryDialog = function(editorUi, name, library, initialImages, file, mode) 8837{ 8838 var images = []; 8839 var graph = editorUi.editor.graph; 8840 var outer = document.createElement('div'); 8841 outer.style.height = '100%'; 8842 8843 var header = document.createElement('div'); 8844 header.style.whiteSpace = 'nowrap'; 8845 header.style.height = '40px'; 8846 outer.appendChild(header); 8847 8848 mxUtils.write(header, mxResources.get('filename') + ':'); 8849 8850 var nameValue = name; 8851 8852 if (nameValue == null) 8853 { 8854 nameValue = editorUi.defaultLibraryName + '.xml'; 8855 } 8856 8857 var nameInput = document.createElement('input'); 8858 nameInput.setAttribute('value', nameValue); 8859 nameInput.style.marginRight = '20px'; 8860 nameInput.style.marginLeft = '10px'; 8861 nameInput.style.width = '500px'; 8862 8863 if (file != null && !file.isRenamable()) 8864 { 8865 nameInput.setAttribute('disabled', 'true'); 8866 } 8867 8868 this.init = function() 8869 { 8870 if (file == null || file.isRenamable()) 8871 { 8872 nameInput.focus(); 8873 8874 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 8875 { 8876 nameInput.select(); 8877 } 8878 else 8879 { 8880 document.execCommand('selectAll', false, null); 8881 } 8882 } 8883 }; 8884 8885 header.appendChild(nameInput); 8886 8887 var div = document.createElement('div'); 8888 div.style.borderWidth = '1px 0px 1px 0px'; 8889 div.style.borderColor = '#d3d3d3'; 8890 div.style.borderStyle = 'solid'; 8891 div.style.marginTop = '6px'; 8892 div.style.overflow = 'auto'; 8893 div.style.height = '340px'; 8894 div.style.backgroundPosition = 'center center'; 8895 div.style.backgroundRepeat = 'no-repeat'; 8896 8897 if (images.length == 0 && Graph.fileSupport) 8898 { 8899 div.style.backgroundImage = 'url(\'' + IMAGE_PATH + '/droptarget.png\')'; 8900 } 8901 8902 var bg = document.createElement('div'); 8903 bg.style.position = 'absolute'; 8904 bg.style.width = '640px'; 8905 bg.style.top = '260px'; 8906 bg.style.textAlign = 'center'; 8907 bg.style.fontSize = '22px'; 8908 bg.style.color = '#a0c3ff'; 8909 mxUtils.write(bg, mxResources.get('dragImagesHere')); 8910 outer.appendChild(bg); 8911 8912 var entries = {}; 8913 var ew = 100; 8914 var eh = 100; 8915 8916 var dragSourceIndex = null; 8917 var dropTargetIndex = null; 8918 8919 function getIndexForEvent(evt) 8920 { 8921 var dropTarget = document.elementFromPoint(evt.clientX, evt.clientY); 8922 8923 while (dropTarget != null && dropTarget.parentNode != div) 8924 { 8925 dropTarget = dropTarget.parentNode; 8926 } 8927 8928 var result = null; 8929 8930 if (dropTarget != null) 8931 { 8932 var tmp = div.firstChild; 8933 result = 0; 8934 8935 while (tmp != null && tmp != dropTarget) 8936 { 8937 tmp = tmp.nextSibling; 8938 result++; 8939 } 8940 } 8941 8942 return result; 8943 }; 8944 8945 var stopEditing = null; 8946 var stopWrapper = function(evt) 8947 { 8948 var source = mxEvent.getSource(evt); 8949 8950 if (source.getAttribute('contentEditable') != 'true' && stopEditing != null) 8951 { 8952 stopEditing(); 8953 stopEditing = null; 8954 8955 mxEvent.consume(evt); 8956 } 8957 }; 8958 8959 mxEvent.addListener(div, 'mousedown', stopWrapper); 8960 mxEvent.addListener(div, 'pointerdown', stopWrapper); 8961 mxEvent.addListener(div, 'touchstart', stopWrapper); 8962 8963 // For converting image URLs 8964 var converter = new mxUrlConverter(); 8965 var errorShowed = false; 8966 8967 function addButton(data, mimeType, x, y, w, h, img, aspect, title) 8968 { 8969 // Ignores duplicates 8970 try 8971 { 8972 editorUi.spinner.stop(); 8973 8974 if (mimeType == null || mimeType.substring(0, 6) == 'image/') 8975 { 8976 if ((data == null && img != null) || entries[data] == null) 8977 { 8978 div.style.backgroundImage = ''; 8979 bg.style.display = 'none'; 8980 8981 var iw = w; 8982 var ih = h; 8983 8984 if (w > editorUi.maxImageSize || h > editorUi.maxImageSize) 8985 { 8986 var s = Math.min(1, Math.min(editorUi.maxImageSize / Math.max(1, w)), 8987 editorUi.maxImageSize / Math.max(1, h)); 8988 w *= s; 8989 h *= s; 8990 } 8991 8992 if (iw > ih) 8993 { 8994 ih = Math.round(ih * ew / iw); 8995 iw = ew; 8996 } 8997 else 8998 { 8999 iw = Math.round(iw * eh / ih); 9000 ih = eh; 9001 } 9002 9003 var wrapper = document.createElement('div'); 9004 wrapper.setAttribute('draggable', 'true'); 9005 wrapper.style.display = 'inline-block'; 9006 wrapper.style.position = 'relative'; 9007 wrapper.style.padding = '0 12px'; 9008 wrapper.style.cursor = 'move'; 9009 mxUtils.setPrefixedStyle(wrapper.style, 'transition', 'transform .1s ease-in-out'); 9010 9011 if (data != null) 9012 { 9013 var elt = document.createElement('img'); 9014 elt.setAttribute('src', converter.convert(data)); 9015 elt.style.width = iw + 'px'; 9016 elt.style.height = ih + 'px'; 9017 elt.style.margin = '10px'; 9018 9019 elt.style.paddingBottom = Math.floor((eh - ih) / 2) + 'px'; 9020 elt.style.paddingLeft = Math.floor((ew - iw) / 2) + 'px'; 9021 9022 wrapper.appendChild(elt); 9023 } 9024 else if (img != null) 9025 { 9026 var cells = editorUi.stringToCells(Graph.decompress(img.xml)); 9027 9028 if (cells.length > 0) 9029 { 9030 editorUi.sidebar.createThumb(cells, ew, eh, wrapper, null, true, false); 9031 9032 // Needs inline block on SVG for delete icon to appear on same line 9033 wrapper.firstChild.style.display = 'inline-block'; 9034 wrapper.firstChild.style.cursor = ''; 9035 } 9036 } 9037 9038 var rem = document.createElement('img'); 9039 rem.setAttribute('src', Editor.closeBlackImage); 9040 rem.setAttribute('border', '0'); 9041 rem.setAttribute('title', mxResources.get('delete')); 9042 rem.setAttribute('align', 'top'); 9043 rem.style.paddingTop = '4px'; 9044 rem.style.position = 'absolute'; 9045 rem.style.marginLeft = '-12px'; 9046 rem.style.zIndex = '1'; 9047 rem.style.cursor = 'pointer'; 9048 9049 // Blocks dragging of remove icon 9050 mxEvent.addListener(rem, 'dragstart', function(evt) 9051 { 9052 mxEvent.consume(evt); 9053 }); 9054 9055 (function(wrapperDiv, dataParam, imgParam) 9056 { 9057 mxEvent.addListener(rem, 'click', function(evt) 9058 { 9059 entries[dataParam] = null; 9060 9061 for (var i = 0; i < images.length; i++) 9062 { 9063 if ((images[i].data != null && images[i].data == dataParam) || 9064 (images[i].xml != null && imgParam != null && 9065 images[i].xml == imgParam.xml)) 9066 { 9067 images.splice(i, 1); 9068 break; 9069 } 9070 } 9071 9072 wrapper.parentNode.removeChild(wrapperDiv); 9073 9074 if (images.length == 0) 9075 { 9076 div.style.backgroundImage = 'url(\'' + IMAGE_PATH + '/droptarget.png\')'; 9077 bg.style.display = ''; 9078 } 9079 9080 mxEvent.consume(evt); 9081 }); 9082 // Workaround for accidental select all 9083 mxEvent.addListener(rem, 'dblclick', function(evt) 9084 { 9085 mxEvent.consume(evt); 9086 }); 9087 })(wrapper, data, img); 9088 9089 wrapper.appendChild(rem); 9090 wrapper.style.marginBottom = '30px'; 9091 9092 var label = document.createElement('div'); 9093 label.style.position = 'absolute'; 9094 label.style.boxSizing = 'border-box'; 9095 label.style.bottom = '-18px'; 9096 label.style.left = '10px'; 9097 label.style.right = '10px'; 9098 label.style.backgroundColor = Editor.isDarkMode() ? Editor.darkColor : '#ffffff'; 9099 label.style.overflow = 'hidden'; 9100 label.style.textAlign = 'center'; 9101 9102 var entry = null; 9103 9104 if (data != null) 9105 { 9106 entry = {data: data, w: w, h: h, title: title}; 9107 9108 if (aspect != null) 9109 { 9110 entry.aspect = aspect; 9111 } 9112 9113 entries[data] = elt; 9114 images.push(entry); 9115 } 9116 else if (img != null) 9117 { 9118 img.aspect = 'fixed'; 9119 images.push(img); 9120 entry = img; 9121 } 9122 9123 function updateLabel() 9124 { 9125 label.innerHTML = ''; 9126 label.style.cursor = 'pointer'; 9127 label.style.whiteSpace = 'nowrap'; 9128 label.style.textOverflow = 'ellipsis'; 9129 mxUtils.write(label, (entry.title != null && entry.title.length > 0) ? 9130 entry.title : mxResources.get('untitled')); 9131 9132 if (entry.title == null || entry.title.length == 0) 9133 { 9134 label.style.color = '#d0d0d0'; 9135 } 9136 else 9137 { 9138 label.style.color = ''; 9139 } 9140 }; 9141 9142 mxEvent.addListener(label, 'keydown', function(evt) 9143 { 9144 if (evt.keyCode == 13 && stopEditing != null) 9145 { 9146 stopEditing(); 9147 stopEditing = null; 9148 9149 mxEvent.consume(evt); 9150 } 9151 }); 9152 9153 updateLabel(); 9154 wrapper.appendChild(label); 9155 9156 // Blocks dragging of label 9157 mxEvent.addListener(label, 'mousedown', function(evt) 9158 { 9159 if (label.getAttribute('contentEditable') != 'true') 9160 { 9161 mxEvent.consume(evt); 9162 } 9163 }); 9164 9165 var startEditing = function(evt) 9166 { 9167 // Workaround for various issues in IE 9168 if (!mxClient.IS_IOS && !mxClient.IS_FF && 9169 (document.documentMode == null || document.documentMode > 9)) 9170 { 9171 if (label.getAttribute('contentEditable') != 'true') 9172 { 9173 if (stopEditing != null) 9174 { 9175 stopEditing(); 9176 stopEditing = null; 9177 } 9178 9179 if (entry.title == null || entry.title.length == 0) 9180 { 9181 label.innerHTML = ''; 9182 } 9183 9184 label.style.textOverflow = ''; 9185 label.style.whiteSpace = ''; 9186 label.style.cursor = 'text'; 9187 label.style.color = ''; 9188 label.setAttribute('contentEditable', 'true'); 9189 mxUtils.setPrefixedStyle(label.style, 'user-select', 'text'); 9190 label.focus(); 9191 document.execCommand('selectAll', false, null); 9192 9193 stopEditing = function() 9194 { 9195 label.removeAttribute('contentEditable'); 9196 label.style.cursor = 'pointer'; 9197 entry.title = label.innerHTML; 9198 updateLabel(); 9199 } 9200 9201 mxEvent.consume(evt); 9202 } 9203 } 9204 else 9205 { 9206 var dlg = new FilenameDialog(editorUi, entry.title || '', mxResources.get('ok'), function(newTitle) 9207 { 9208 if (newTitle != null) 9209 { 9210 entry.title = newTitle; 9211 updateLabel(); 9212 } 9213 }, mxResources.get('enterValue')); 9214 editorUi.showDialog(dlg.container, 300, 80, true, true); 9215 dlg.init(); 9216 9217 mxEvent.consume(evt); 9218 } 9219 }; 9220 9221 mxEvent.addListener(label, 'click', startEditing); 9222 mxEvent.addListener(wrapper, 'dblclick', startEditing); 9223 9224 div.appendChild(wrapper); 9225 9226 mxEvent.addListener(wrapper, 'dragstart', function(evt) 9227 { 9228 if (data == null && img != null) 9229 { 9230 rem.style.visibility = 'hidden'; 9231 label.style.visibility = 'hidden'; 9232 } 9233 9234 // Workaround for no DnD on DIV in FF 9235 if (mxClient.IS_FF && img.xml != null) 9236 { 9237 evt.dataTransfer.setData('Text', img.xml); 9238 } 9239 9240 dragSourceIndex = getIndexForEvent(evt); 9241 9242 // Workaround for missing drag preview in Google Chrome 9243 if (mxClient.IS_GC) 9244 { 9245 wrapper.style.opacity = '0.9'; 9246 } 9247 9248 window.setTimeout(function() 9249 { 9250 mxUtils.setPrefixedStyle(wrapper.style, 'transform', 'scale(0.5,0.5)'); 9251 mxUtils.setOpacity(wrapper, 30); 9252 rem.style.visibility = ''; 9253 label.style.visibility = ''; 9254 }, 0); 9255 }); 9256 9257 mxEvent.addListener(wrapper, 'dragend', function(evt) 9258 { 9259 if (rem.style.visibility == 'hidden') 9260 { 9261 rem.style.visibility = ''; 9262 label.style.visibility = ''; 9263 } 9264 9265 dragSourceIndex = null; 9266 mxUtils.setOpacity(wrapper, 100); 9267 mxUtils.setPrefixedStyle(wrapper.style, 'transform', null); 9268 }); 9269 } 9270 else if (!errorShowed) 9271 { 9272 errorShowed = true; 9273 editorUi.handleError({message: mxResources.get('fileExists')}) 9274 } 9275 } 9276 else 9277 { 9278 var done = false; 9279 9280 try 9281 { 9282 var doc = mxUtils.parseXml(data); 9283 9284 if (doc.documentElement.nodeName == 'mxlibrary') 9285 { 9286 var temp = JSON.parse(mxUtils.getTextContent(doc.documentElement)); 9287 9288 if (temp != null && temp.length > 0) 9289 { 9290 for (var i = 0; i < temp.length; i++) 9291 { 9292 if (temp[i].xml != null) 9293 { 9294 addButton(null, null, 0, 0, 0, 0, temp[i]); 9295 } 9296 else 9297 { 9298 addButton(temp[i].data, null, 0, 0, temp[i].w, temp[i].h, null, 'fixed', temp[i].title); 9299 } 9300 } 9301 } 9302 9303 done = true; 9304 } 9305 else if (doc.documentElement.nodeName == 'mxfile') 9306 { 9307 var pages = doc.documentElement.getElementsByTagName('diagram'); 9308 9309 for (var i = 0; i < pages.length; i++) 9310 { 9311 var temp = mxUtils.getTextContent(pages[i]); 9312 var cells = editorUi.stringToCells(Graph.decompress(temp)); 9313 var size = editorUi.editor.graph.getBoundingBoxFromGeometry(cells); 9314 addButton(null, null, 0, 0, 0, 0, {xml: temp, w: size.width, h: size.height}); 9315 } 9316 9317 done = true; 9318 } 9319 } 9320 catch (e) 9321 { 9322 // ignore 9323 } 9324 9325 if (!done) 9326 { 9327 editorUi.spinner.stop(); 9328 editorUi.handleError({message: mxResources.get('errorLoadingFile')}) 9329 } 9330 } 9331 } 9332 catch (e) 9333 { 9334 // ignore 9335 } 9336 9337 return null; 9338 }; 9339 9340 if (initialImages != null) 9341 { 9342 for (var i = 0; i < initialImages.length; i++) 9343 { 9344 var img = initialImages[i]; 9345 addButton(img.data, null, 0, 0, img.w, img.h, img, img.aspect, img.title); 9346 } 9347 } 9348 9349 // Setup the dnd listeners 9350 mxEvent.addListener(div, 'dragleave', function(evt) 9351 { 9352 bg.style.cursor = ''; 9353 var source = mxEvent.getSource(evt); 9354 9355 while (source != null) 9356 { 9357 if (source == div || source == bg) 9358 { 9359 evt.stopPropagation(); 9360 evt.preventDefault(); 9361 break; 9362 } 9363 9364 source = source.parentNode; 9365 } 9366 }); 9367 9368 function dragOver(evt) 9369 { 9370 evt.dataTransfer.dropEffect = (dragSourceIndex != null) ? 'move' : 'copy'; 9371 evt.stopPropagation(); 9372 evt.preventDefault(); 9373 }; 9374 9375 var createImportHandler = function(evt) 9376 { 9377 return function(data, mimeType, x, y, w, h, img, doneFn, file) 9378 { 9379 if (file != null && (/(\.v(dx|sdx?))($|\?)/i.test(file.name) || /(\.vs(x|sx?))($|\?)/i.test(file.name))) 9380 { 9381 editorUi.importVisio(file, mxUtils.bind(this, function(xml) 9382 { 9383 addButton(xml, mimeType, x, y, w, h, img, 'fixed', (mxEvent.isAltDown(evt)) ? 9384 null : img.substring(0, img.lastIndexOf('.')).replace(/_/g, ' ')); 9385 })); 9386 } 9387 else if (file != null && !editorUi.isOffline() && new XMLHttpRequest().upload && editorUi.isRemoteFileFormat(data, file.name)) 9388 { 9389 editorUi.parseFile(file, mxUtils.bind(this, function(xhr) 9390 { 9391 if (xhr.readyState == 4) 9392 { 9393 editorUi.spinner.stop(); 9394 9395 if (xhr.status >= 200 && xhr.status <= 299) 9396 { 9397 var xml = xhr.responseText; 9398 addButton(xml, mimeType, x, y, w, h, img, 'fixed', (mxEvent.isAltDown(evt)) ? 9399 null : img.substring(0, img.lastIndexOf('.')).replace(/_/g, ' ')); 9400 div.scrollTop = div.scrollHeight; 9401 } 9402 } 9403 })); 9404 } 9405 else 9406 { 9407 addButton(data, mimeType, x, y, w, h, img, 'fixed', (mxEvent.isAltDown(evt)) ? 9408 null : img.substring(0, img.lastIndexOf('.')).replace(/_/g, ' ')); 9409 div.scrollTop = div.scrollHeight; 9410 } 9411 }; 9412 }; 9413 9414 function dropHandler(evt) 9415 { 9416 evt.stopPropagation(); 9417 evt.preventDefault(); 9418 errorShowed = false; 9419 dropTargetIndex = getIndexForEvent(evt); 9420 9421 if (dragSourceIndex != null) 9422 { 9423 if (dropTargetIndex != null && dropTargetIndex < div.children.length) 9424 { 9425 images.splice((dropTargetIndex > dragSourceIndex) ? dropTargetIndex - 1 : dropTargetIndex, 9426 0, images.splice(dragSourceIndex, 1)[0]); 9427 div.insertBefore(div.children[dragSourceIndex], div.children[dropTargetIndex]); 9428 } 9429 else 9430 { 9431 images.push(images.splice(dragSourceIndex, 1)[0]); 9432 div.appendChild(div.children[dragSourceIndex]); 9433 } 9434 } 9435 else if (evt.dataTransfer.files.length > 0) 9436 { 9437 editorUi.importFiles(evt.dataTransfer.files, 0, 0, editorUi.maxImageSize, createImportHandler(evt)); 9438 } 9439 else if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0) 9440 { 9441 var uri = decodeURIComponent(evt.dataTransfer.getData('text/uri-list')); 9442 9443 if (/(\.jpg)($|\?)/i.test(uri) || /(\.png)($|\?)/i.test(uri) || 9444 /(\.gif)($|\?)/i.test(uri) || /(\.svg)($|\?)/i.test(uri)) 9445 { 9446 editorUi.loadImage(uri, function(img) 9447 { 9448 addButton(uri, null, 0, 0, img.width, img.height); 9449 div.scrollTop = div.scrollHeight; 9450 }); 9451 } 9452 } 9453 9454 evt.stopPropagation(); 9455 evt.preventDefault(); 9456 }; 9457 9458 mxEvent.addListener(div, 'dragover', dragOver); 9459 mxEvent.addListener(div, 'drop', dropHandler); 9460 mxEvent.addListener(bg, 'dragover', dragOver); 9461 mxEvent.addListener(bg, 'drop', dropHandler); 9462 9463 outer.appendChild(div); 9464 9465 var btns = document.createElement('div'); 9466 btns.style.textAlign = 'right'; 9467 btns.style.marginTop = '20px'; 9468 9469 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 9470 { 9471 editorUi.hideDialog(true); 9472 }); 9473 9474 cancelBtn.setAttribute('id', 'btnCancel'); 9475 cancelBtn.className = 'geBtn'; 9476 9477 if (editorUi.editor.cancelFirst) 9478 { 9479 btns.appendChild(cancelBtn); 9480 } 9481 9482 if (editorUi.getServiceName() == 'draw.io' && file != null && 9483 // Limits button to ibraries which are known to have public URLs 9484 (file.constructor == DriveLibrary || file.constructor == GitHubLibrary)) 9485 { 9486 var btn = mxUtils.button(mxResources.get('link'), function() 9487 { 9488 if (editorUi.spinner.spin(document.body, mxResources.get('loading'))) 9489 { 9490 file.getPublicUrl(function(url) 9491 { 9492 editorUi.spinner.stop(); 9493 9494 if (url != null) 9495 { 9496 var search = editorUi.getSearch(['create', 'title', 'mode', 'url', 'drive', 'splash', 'state', 'clibs', 'ui']); 9497 search += ((search.length == 0) ? '?' : '&') + 'splash=0&clibs=U' + encodeURIComponent(url); 9498 var dlg = new EmbedDialog(editorUi, window.location.protocol + '//' + 9499 window.location.host + '/' + search, null, null, null, null, 9500 'Check out the library I made using @drawio'); 9501 editorUi.showDialog(dlg.container, 450, 240, true); 9502 dlg.init(); 9503 } 9504 else if (file.constructor == DriveLibrary) 9505 { 9506 editorUi.showError(mxResources.get('error'), mxResources.get('diagramIsNotPublic'), 9507 mxResources.get('share'), mxUtils.bind(this, function() 9508 { 9509 editorUi.drive.showPermissions(file.getId()); 9510 }), null, mxResources.get('ok'), mxUtils.bind(this, function() 9511 { 9512 // Hides dialog 9513 }) 9514 ); 9515 } 9516 else 9517 { 9518 editorUi.handleError({message: mxResources.get('diagramIsNotPublic')}); 9519 } 9520 }); 9521 } 9522 }); 9523 9524 btn.className = 'geBtn'; 9525 btns.appendChild(btn); 9526 } 9527 9528 var btn = mxUtils.button(mxResources.get('export'), function() 9529 { 9530 var data = editorUi.createLibraryDataFromImages(images); 9531 var filename = nameInput.value; 9532 9533 if (!/(\.xml)$/i.test(filename)) 9534 { 9535 filename += '.xml'; 9536 } 9537 9538 if (editorUi.isLocalFileSave()) 9539 { 9540 editorUi.saveLocalFile(data, filename, 'text/xml', null, null, true, null, 'xml'); 9541 } 9542 else 9543 { 9544 new mxXmlRequest(SAVE_URL, 'filename=' + encodeURIComponent(filename) + 9545 '&format=xml&xml=' + encodeURIComponent(data)).simulate(document, '_blank'); 9546 } 9547 }); 9548 9549 btn.setAttribute('id', 'btnDownload'); 9550 btn.className = 'geBtn'; 9551 btns.appendChild(btn); 9552 9553 if (Graph.fileSupport) 9554 { 9555 if (editorUi.libDlgFileInputElt == null) 9556 { 9557 var fileInput = document.createElement('input'); 9558 fileInput.setAttribute('multiple', 'multiple'); 9559 fileInput.setAttribute('type', 'file'); 9560 9561 mxEvent.addListener(fileInput, 'change', function(evt) 9562 { 9563 errorShowed = false; 9564 9565 editorUi.importFiles(fileInput.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h, img, doneFn, file) 9566 { 9567 if (fileInput.files != null) 9568 { 9569 createImportHandler(evt)(data, mimeType, x, y, w, h, img, doneFn, file); 9570 9571 // Resets input to force change event for same file (type reset required for IE) 9572 fileInput.type = ''; 9573 fileInput.type = 'file'; 9574 fileInput.value = ''; 9575 } 9576 }); 9577 9578 div.scrollTop = div.scrollHeight; 9579 }); 9580 9581 fileInput.style.display = 'none'; 9582 document.body.appendChild(fileInput); 9583 editorUi.libDlgFileInputElt = fileInput; 9584 } 9585 9586 var btn = mxUtils.button(mxResources.get('import'), function() 9587 { 9588 if (stopEditing != null) 9589 { 9590 stopEditing(); 9591 stopEditing = null; 9592 } 9593 9594 editorUi.libDlgFileInputElt.click(); 9595 }); 9596 btn.setAttribute('id', 'btnAddImage'); 9597 btn.className = 'geBtn'; 9598 9599 btns.appendChild(btn); 9600 } 9601 9602 var btn = mxUtils.button(mxResources.get('addImages'), function() 9603 { 9604 if (stopEditing != null) 9605 { 9606 stopEditing(); 9607 stopEditing = null; 9608 } 9609 9610 editorUi.showImageDialog(mxResources.get('addImageUrl'), '', function(url, w, h) 9611 { 9612 errorShowed = false; 9613 9614 if (url != null) 9615 { 9616 // Image dialog returns modified data URLs which 9617 // must be converted back to real data URL 9618 if (url.substring(0, 11) == 'data:image/') 9619 { 9620 var comma = url.indexOf(','); 9621 9622 if (comma > 0) 9623 { 9624 url = url.substring(0, comma) + ';base64,' + url.substring(comma + 1); 9625 } 9626 } 9627 9628 addButton(url, null, 0, 0, w, h); 9629 div.scrollTop = div.scrollHeight; 9630 } 9631 }); 9632 }); 9633 9634 btn.setAttribute('id', 'btnAddImageUrl'); 9635 btn.className = 'geBtn'; 9636 btns.appendChild(btn); 9637 9638 // Indirection for overriding 9639 this.saveBtnClickHandler = function(name, images, file, mode) 9640 { 9641 editorUi.saveLibrary(name, images, file, mode); 9642 }; 9643 9644 var btn = mxUtils.button(mxResources.get('save'),mxUtils.bind(this, function() 9645 { 9646 if (stopEditing != null) 9647 { 9648 stopEditing(); 9649 stopEditing = null; 9650 } 9651 9652 this.saveBtnClickHandler(nameInput.value, images, file, mode); 9653 })); 9654 9655 btn.setAttribute('id', 'btnSave'); 9656 btn.className = 'geBtn gePrimaryBtn'; 9657 btns.appendChild(btn); 9658 9659 if (!editorUi.editor.cancelFirst) 9660 { 9661 btns.appendChild(cancelBtn); 9662 } 9663 9664 outer.appendChild(btns); 9665 9666 this.container = outer; 9667}; 9668 9669/** 9670 * Constructs a new textarea dialog. 9671 */ 9672var EditShapeDialog = function(editorUi, cell, title, w, h) 9673{ 9674 w = (w != null) ? w : 300; 9675 h = (h != null) ? h : 120; 9676 var row, td; 9677 9678 var table = document.createElement('table'); 9679 var tbody = document.createElement('tbody'); 9680 table.style.cellPadding = '4px'; 9681 9682 row = document.createElement('tr'); 9683 9684 td = document.createElement('td'); 9685 td.setAttribute('colspan', '2'); 9686 td.style.fontSize = '10pt'; 9687 mxUtils.write(td, title); 9688 9689 row.appendChild(td); 9690 tbody.appendChild(row); 9691 9692 row = document.createElement('tr'); 9693 td = document.createElement('td'); 9694 9695 var nameInput = document.createElement('textarea'); 9696 nameInput.style.outline = 'none'; 9697 nameInput.style.resize = 'none'; 9698 nameInput.style.width = (w - 200) + 'px'; 9699 nameInput.style.height = h + 'px'; 9700 9701 this.textarea = nameInput; 9702 9703 this.init = function() 9704 { 9705 nameInput.focus(); 9706 nameInput.scrollTop = 0; 9707 }; 9708 9709 td.appendChild(nameInput); 9710 row.appendChild(td); 9711 9712 td = document.createElement('td'); 9713 9714 var container = document.createElement('div'); 9715 container.style.position = 'relative'; 9716 container.style.border = '1px solid gray'; 9717 container.style.top = '6px'; 9718 container.style.width = '200px'; 9719 container.style.height = (h + 4) + 'px'; 9720 container.style.overflow = 'hidden'; 9721 container.style.marginBottom = '16px'; 9722 mxEvent.disableContextMenu(container); 9723 td.appendChild(container); 9724 9725 var graph = new Graph(container); 9726 graph.setEnabled(false); 9727 9728 var clone = editorUi.editor.graph.cloneCell(cell); 9729 graph.addCells([clone]); 9730 9731 var state = graph.view.getState(clone); 9732 var stencil = ''; 9733 9734 if (state.shape != null && state.shape.stencil != null) 9735 { 9736 stencil = mxUtils.getPrettyXml(state.shape.stencil.desc); 9737 } 9738 9739 mxUtils.write(nameInput, stencil || ''); 9740 9741 var b = graph.getGraphBounds(); 9742 var ns = Math.min((200 - 40) / b.width, (h - 40) / b.height); 9743 graph.view.scaleAndTranslate(ns, 20 / ns - b.x, 20 / ns - b.y); 9744 9745 row.appendChild(td); 9746 tbody.appendChild(row); 9747 9748 row = document.createElement('tr'); 9749 td = document.createElement('td'); 9750 td.setAttribute('colspan', '2'); 9751 td.style.paddingTop = '2px'; 9752 td.style.whiteSpace = 'nowrap'; 9753 td.setAttribute('align', 'right'); 9754 9755 if (!editorUi.isOffline()) 9756 { 9757 var helpBtn = mxUtils.button(mxResources.get('help'), function() 9758 { 9759 editorUi.openLink('https://www.diagrams.net/doc/faq/shape-complex-create-edit'); 9760 }); 9761 9762 helpBtn.className = 'geBtn'; 9763 td.appendChild(helpBtn); 9764 } 9765 9766 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 9767 { 9768 editorUi.hideDialog(); 9769 }); 9770 cancelBtn.className = 'geBtn'; 9771 9772 if (editorUi.editor.cancelFirst) 9773 { 9774 td.appendChild(cancelBtn); 9775 } 9776 9777 var updateShape = function(targetGraph, targetCell, hide) 9778 { 9779 var newValue = nameInput.value; 9780 9781 // Checks if XML has changed (getPrettyXml "normalizes" DOM) 9782 var doc = mxUtils.parseXml(newValue); 9783 newValue = mxUtils.getPrettyXml(doc.documentElement); 9784 9785 // Checks for validation errors 9786 // LATER: Validate against XSD 9787 var errors = doc.documentElement.getElementsByTagName('parsererror'); 9788 9789 if (errors != null && errors.length > 0) 9790 { 9791 editorUi.showError(mxResources.get('error'), mxResources.get('containsValidationErrors'), mxResources.get('ok')); 9792 } 9793 else 9794 { 9795 if (hide) 9796 { 9797 editorUi.hideDialog(); 9798 } 9799 9800 var isNew = !targetGraph.model.contains(targetCell); 9801 9802 if (!hide || isNew || newValue != stencil) 9803 { 9804 // Transform XML value to be used in cell style 9805 newValue = Graph.compress(newValue); 9806 9807 targetGraph.getModel().beginUpdate(); 9808 try 9809 { 9810 // Inserts cell if required 9811 if (isNew) 9812 { 9813 var pt = editorUi.editor.graph.getFreeInsertPoint(); 9814 targetCell.geometry.x = pt.x; 9815 targetCell.geometry.y = pt.y; 9816 targetGraph.addCell(targetCell) 9817 } 9818 9819 targetGraph.setCellStyles(mxConstants.STYLE_SHAPE, 'stencil(' + newValue + ')', [targetCell]); 9820 } 9821 catch (e) 9822 { 9823 throw e; 9824 } 9825 finally 9826 { 9827 // Updates the display 9828 targetGraph.getModel().endUpdate(); 9829 } 9830 9831 // Updates selection after stencil was created for rendering 9832 if (isNew) 9833 { 9834 targetGraph.setSelectionCell(targetCell); 9835 targetGraph.scrollCellToVisible(targetCell); 9836 } 9837 } 9838 } 9839 }; 9840 9841 var previewBtn = mxUtils.button(mxResources.get('preview'), function() 9842 { 9843 updateShape(graph, clone, false); 9844 }); 9845 9846 previewBtn.className = 'geBtn'; 9847 td.appendChild(previewBtn); 9848 9849 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 9850 { 9851 updateShape(editorUi.editor.graph, cell, true); 9852 }); 9853 9854 applyBtn.className = 'geBtn gePrimaryBtn'; 9855 td.appendChild(applyBtn); 9856 9857 if (!editorUi.editor.cancelFirst) 9858 { 9859 td.appendChild(cancelBtn); 9860 } 9861 9862 row.appendChild(td); 9863 tbody.appendChild(row); 9864 table.appendChild(tbody); 9865 this.container = table; 9866}; 9867 9868var CustomDialog = function(editorUi, content, okFn, cancelFn, okButtonText, helpLink, buttonsContent, hideCancel, cancelButtonText, hideAfterOKFn) 9869{ 9870 var div = document.createElement('div'); 9871 div.appendChild(content); 9872 9873 var btns = document.createElement('div'); 9874 btns.style.marginTop = '30px'; 9875 btns.style.textAlign = 'center'; 9876 9877 if (buttonsContent != null) 9878 { 9879 btns.appendChild(buttonsContent); 9880 } 9881 9882 if (!editorUi.isOffline() && helpLink != null) 9883 { 9884 var helpBtn = mxUtils.button(mxResources.get('help'), function() 9885 { 9886 editorUi.openLink(helpLink); 9887 }); 9888 9889 helpBtn.className = 'geBtn'; 9890 btns.appendChild(helpBtn); 9891 } 9892 9893 var cancelBtn = mxUtils.button(cancelButtonText || mxResources.get('cancel'), function() 9894 { 9895 editorUi.hideDialog(); 9896 9897 if (cancelFn != null) 9898 { 9899 cancelFn(); 9900 } 9901 }); 9902 9903 cancelBtn.className = 'geBtn'; 9904 9905 if (hideCancel) 9906 { 9907 cancelBtn.style.display = 'none'; 9908 } 9909 9910 if (editorUi.editor.cancelFirst) 9911 { 9912 btns.appendChild(cancelBtn); 9913 } 9914 9915 var okBtn = mxUtils.button(okButtonText || mxResources.get('ok'), mxUtils.bind(this, function() 9916 { 9917 if (!hideAfterOKFn) 9918 { 9919 editorUi.hideDialog(null, null, this.container); 9920 } 9921 9922 if (okFn != null) 9923 { 9924 var okRet = okFn(); 9925 9926 if (typeof okRet === 'string') 9927 { 9928 editorUi.showError(mxResources.get('error'), okRet); 9929 return; 9930 } 9931 } 9932 9933 if (hideAfterOKFn) 9934 { 9935 editorUi.hideDialog(null, null, this.container); 9936 } 9937 })); 9938 btns.appendChild(okBtn); 9939 9940 okBtn.className = 'geBtn gePrimaryBtn'; 9941 9942 if (!editorUi.editor.cancelFirst) 9943 { 9944 btns.appendChild(cancelBtn); 9945 } 9946 9947 div.appendChild(btns); 9948 9949 this.cancelBtn = cancelBtn; 9950 this.okButton = okBtn; 9951 this.container = div; 9952}; 9953 9954//TODO Many of the code is the same as NewDialog. Needs merging 9955var TemplatesDialog = function(editorUi, callback, cancelCallback, 9956 templateFile, newDiagramCatsFile, username, recentDocsCallback, searchDocsCallback, 9957 loadExtDoc, linkToDiagramCallback, customTempCallback, withOpen, withLink, withoutType, noDlgHide) 9958{ 9959 var dialogSkeleton = 9960 '<div class="geTempDlgHeader">' + 9961 '<img src="/images/draw.io-logo.svg" class="geTempDlgHeaderLogo">' + 9962 '<input type="search" class="geTempDlgSearchBox" ' + (searchDocsCallback? '' : 'style="display: none"') 9963 + ' placeholder="'+ mxResources.get('search') +'">' + 9964 '</div>' + 9965 '<div class="geTemplatesList" style="display: none">' + 9966 '<div class="geTempDlgBack">< '+ mxResources.get('back') + '</div>' + 9967 '<div class="geTempDlgHLine"></div>' + 9968 '<div class="geTemplatesLbl">'+ mxResources.get('templates') + '</div>' + 9969 '</div>' + 9970 '<div class="geTempDlgContent" style="width: 100%">' + 9971 '<div class="geTempDlgNewDiagramCat">' + 9972 '<div class="geTempDlgNewDiagramCatLbl">'+ mxResources.get('newDiagram') +'</div>' + 9973 '<div class="geTempDlgNewDiagramCatList">' + 9974 '</div>' + 9975 '<div class="geTempDlgNewDiagramCatFooter">' + 9976 '<div class="geTempDlgShowAllBtn">'+ mxResources.get('showMore') +'</div>' + 9977 '</div>' + 9978 '</div>' + 9979 '<div class="geTempDlgDiagramsList">' + 9980 '<div class="geTempDlgDiagramsListHeader">' + 9981 '<div class="geTempDlgDiagramsListTitle"></div>' + 9982 '<div class="geTempDlgDiagramsListBtns">' + 9983 '<div class="geTempDlgRadioBtn geTempDlgRadioBtnLarge" data-id="myDiagramsBtn">' + 9984 '<img src="/images/my-diagrams.svg" class="geTempDlgMyDiagramsBtnImg"> <span>'+ mxResources.get('myDiagrams') + '</span>' + 9985 '</div><div class="geTempDlgRadioBtn geTempDlgRadioBtnLarge geTempDlgRadioBtnActive" data-id="allDiagramsBtn">' + 9986 '<img src="/images/all-diagrams-sel.svg" class="geTempDlgAllDiagramsBtnImg"> <span>'+ mxResources.get('allDiagrams') + '</span>' + 9987 '</div><div class="geTempDlgSpacer"> </div><div class="geTempDlgRadioBtn geTempDlgRadioBtnSmall geTempDlgRadioBtnActive" data-id="tilesBtn">' + 9988 '<img src="/images/tiles-sel.svg" class="geTempDlgTilesBtnImg">' + 9989 '</div><div class="geTempDlgRadioBtn geTempDlgRadioBtnSmall" data-id="listBtn">' + 9990 '<img src="/images/list.svg" class="geTempDlgListBtnImg">' + 9991 '</div>' + 9992 '</div>' + 9993 '</div>' + 9994 '<div class="geTempDlgDiagramsTiles">' + 9995 '</div>'+ 9996 '</div>' + 9997 '</div>' + 9998 '<br style="clear:both;"/>' + 9999 '<div class="geTempDlgFooter">' + 10000 '<div class="geTempDlgErrMsg"></div>' + 10001 (withLink? 10002 '<span class="geTempDlgLinkToDiagram geTempDlgLinkToDiagramHint">' + mxResources.get('linkToDiagramHint') + '</span>' + 10003 '<button class="geTempDlgLinkToDiagram geTempDlgLinkToDiagramBtn">'+ mxResources.get('linkToDiagram') + '</button>' : 10004 '' 10005 ) + 10006 (withOpen? '<div class="geTempDlgOpenBtn">'+ mxResources.get('open') + '</div>' : '') + 10007 '<div class="geTempDlgCreateBtn">'+ mxResources.get('create') + '</div>' + 10008 '<div class="geTempDlgCancelBtn">'+ mxResources.get('cancel') + '</div>' + 10009 '</div>'; 10010 10011 var dlg = this; 10012 var dlgDiv = document.createElement('div'); 10013 dlgDiv.innerHTML = dialogSkeleton; 10014 dlgDiv.className = "geTemplateDlg"; 10015 this.container = dlgDiv; 10016 templateFile = (templateFile != null) ? templateFile : (TEMPLATE_PATH + '/index.xml'); 10017 newDiagramCatsFile = (newDiagramCatsFile != null) ? newDiagramCatsFile : NEW_DIAGRAM_CATS_PATH + '/index.xml'; 10018 var callInitiated = false; 10019 var cancelPendingCall = false; 10020 var currentEntry = null, lastEntry = null; 10021 var currentItem = null; 10022 var currentItemInfo = null; 10023 var showingAll = false; 10024 var isGetAll = true; 10025 var showAsList = false; 10026 var curDiagList = [], curSearchImportCats = null; 10027 var lastSearchStr, lastGetAll; 10028 var categorySelected = true; 10029 var inTempScreen = false; 10030 var showAllBtn = dlgDiv.querySelector(".geTempDlgShowAllBtn"); 10031 var diagramsTiles = dlgDiv.querySelector('.geTempDlgDiagramsTiles'); 10032 var diagramsListTitle = dlgDiv.querySelector('.geTempDlgDiagramsListTitle'); 10033 var diagramsListBtns = dlgDiv.querySelector('.geTempDlgDiagramsListBtns'); 10034 var tempDlgContent = dlgDiv.querySelector('.geTempDlgContent'); 10035 var diagramsList = dlgDiv.querySelector('.geTempDlgDiagramsList'); 10036 var newDiagramCat = dlgDiv.querySelector('.geTempDlgNewDiagramCat'); 10037 var newDiagramCatList = dlgDiv.querySelector(".geTempDlgNewDiagramCatList"); 10038 var createBtn = dlgDiv.querySelector('.geTempDlgCreateBtn'); 10039 var openBtn = dlgDiv.querySelector('.geTempDlgOpenBtn'); 10040 var searchInout = dlgDiv.querySelector('.geTempDlgSearchBox'); 10041 var errMsg = dlgDiv.querySelector('.geTempDlgErrMsg'); 10042 var spinner = new Spinner({ 10043 lines: 12, // The number of lines to draw 10044 length: 10, // The length of each line 10045 width: 5, // The line thickness 10046 radius: 10, // The radius of the inner circle 10047 rotate: 0, // The rotation offset 10048 color: '#000', // #rgb or #rrggbb 10049 speed: 1.5, // Rounds per second 10050 trail: 60, // Afterglow percentage 10051 shadow: false, // Whether to render a shadow 10052 hwaccel: false, // Whether to use hardware acceleration 10053 top: '50px', 10054 zIndex: 2e9 // The z-index (defaults to 2000000000) 10055 }); 10056 10057 function showError(msg) 10058 { 10059 errMsg.innerHTML = mxUtils.htmlEntities(msg); 10060 errMsg.style.display = 'block'; 10061 10062 setTimeout(function() 10063 { 10064 errMsg.style.display = 'none'; 10065 }, 4000); 10066 }; 10067 10068 function deselectTempCat() 10069 { 10070 if (currentEntry != null) 10071 { 10072 currentEntry.style.fontWeight = 'normal'; 10073 currentEntry.style.textDecoration = 'none'; 10074 lastEntry = currentEntry; 10075 currentEntry = null; 10076 } 10077 }; 10078 10079 mxEvent.addListener(dlgDiv.querySelector('.geTempDlgBack'), 'click', function() 10080 { 10081 deselectTempCat(); 10082 inTempScreen = false; 10083 var list = dlgDiv.querySelector(".geTemplatesList"); 10084 list.style.display = 'none'; 10085 tempDlgContent.style.width = '100%'; 10086 newDiagramCat.style.display = ''; 10087 diagramsList.style.minHeight = 'calc(100% - 280px)'; 10088 searchInout.style.display = searchDocsCallback? '' : 'none'; 10089 searchInout.value = ''; 10090 lastSearchStr = null; 10091 10092 getRecentDocs(isGetAll); 10093 }); 10094 10095 function radioClick(btn, btnImgId, btnImgFile, otherBtnId, otherBtnImgId, otherBtnImgFile, isLarge) 10096 { 10097 if (btn.className.indexOf('geTempDlgRadioBtnActive') > -1) 10098 { 10099 return false; 10100 } 10101 else 10102 { 10103 btn.className += ' geTempDlgRadioBtnActive'; 10104 dlgDiv.querySelector('.geTempDlgRadioBtn[data-id='+ otherBtnId +']').className = "geTempDlgRadioBtn " + 10105 (isLarge? "geTempDlgRadioBtnLarge" : "geTempDlgRadioBtnSmall"); 10106 dlgDiv.querySelector('.'+ btnImgId).src = "/images/"+ btnImgFile +"-sel.svg"; 10107 dlgDiv.querySelector('.'+ otherBtnImgId).src = "/images/"+ otherBtnImgFile +".svg"; 10108 return true; 10109 } 10110 }; 10111 10112 mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=allDiagramsBtn]'), 'click', function() 10113 { 10114 if (radioClick(this, 'geTempDlgAllDiagramsBtnImg', 'all-diagrams', 'myDiagramsBtn', 'geTempDlgMyDiagramsBtnImg', 'my-diagrams', true)) 10115 { 10116 isGetAll = true; 10117 lastSearchStr == null? getRecentDocs(isGetAll) : doSearch(lastSearchStr); 10118 } 10119 }); 10120 10121 mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=myDiagramsBtn]'), 'click', function() 10122 { 10123 if (radioClick(this, 'geTempDlgMyDiagramsBtnImg', 'my-diagrams', 'allDiagramsBtn', 'geTempDlgAllDiagramsBtnImg', 'all-diagrams', true)) 10124 { 10125 isGetAll = false; 10126 lastSearchStr == null? getRecentDocs(isGetAll) : doSearch(lastSearchStr); 10127 } 10128 }); 10129 10130 mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=listBtn]'), 'click', function() 10131 { 10132 if (radioClick(this, 'geTempDlgListBtnImg', 'list', 'tilesBtn', 'geTempDlgTilesBtnImg', 'tiles', false)) 10133 { 10134 showAsList = true; 10135 fillDiagramsList(curDiagList, false, showAsList, curSearchImportCats); 10136 } 10137 }); 10138 10139 mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=tilesBtn]'), 'click', function() 10140 { 10141 if (radioClick(this, 'geTempDlgTilesBtnImg', 'tiles', 'listBtn', 'geTempDlgListBtnImg', 'list', false)) 10142 { 10143 showAsList = false; 10144 fillDiagramsList(curDiagList, false, showAsList, curSearchImportCats); 10145 } 10146 }); 10147 10148 var loading = false; 10149 10150 function createPreview(diagram, elt, img, evt) 10151 { 10152 var xmlData = null; 10153 10154 function loadXmlData(url, callback) 10155 { 10156 if (xmlData == null) 10157 { 10158 var realUrl = url; 10159 10160 if (/^https?:\/\//.test(realUrl) && !editorUi.editor.isCorsEnabledForUrl(realUrl)) 10161 { 10162 realUrl = PROXY_URL + '?url=' + encodeURIComponent(realUrl); 10163 } 10164 else 10165 { 10166 realUrl = TEMPLATE_PATH + '/' + realUrl; 10167 } 10168 10169 mxUtils.get(realUrl, mxUtils.bind(this, function(req) 10170 { 10171 if (req.getStatus() >= 200 && req.getStatus() <= 299) 10172 { 10173 xmlData = req.getText(); 10174 callback(xmlData); 10175 } 10176 else 10177 { 10178 callback(xmlData); 10179 } 10180 })); 10181 } 10182 else 10183 { 10184 callback(xmlData); 10185 } 10186 } 10187 10188 // Shows a tooltip with the rendered template 10189 function showTooltip(xml, x, y) 10190 { 10191 // Checks if dialog still visible 10192 if (xml != null && mxUtils.isAncestorNode(document.body, elt)) 10193 { 10194 var doc = mxUtils.parseXml(xml); 10195 var tempNode = Editor.extractGraphModel(doc.documentElement, true); 10196 10197 if (tempNode == null) return; //Not a diagram file 10198 10199 if (tempNode.nodeName == 'mxfile') 10200 { 10201 var tempNode = Editor.parseDiagramNode(tempNode.getElementsByTagName('diagram')[0]); 10202 } 10203 10204 var codec = new mxCodec(tempNode.ownerDocument); 10205 var model = new mxGraphModel(); 10206 codec.decode(tempNode, model); 10207 var cells = model.root.getChildAt(0).children || []; 10208 10209 var ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 10210 var wh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; 10211 10212 // TODO: Use maxscreensize 10213 editorUi.sidebar.createTooltip(elt, cells, Math.min(ww - 80, 1000), Math.min(wh - 80, 800), 10214 (diagram.title != null) ? mxResources.get(diagram.title, null, diagram.title) : null, 10215 true, new mxPoint(x, y), true, null, true); 10216 10217 var mask = document.createElement('div'); 10218 mask.className = "geTempDlgDialogMask"; 10219 dlgDiv.appendChild(mask); 10220 //Remove the mask when tooltop is hidden 10221 var origHideTooltip = editorUi.sidebar.hideTooltip; 10222 10223 editorUi.sidebar.hideTooltip = function() 10224 { 10225 if (mask) 10226 { 10227 dlgDiv.removeChild(mask); 10228 mask = null; 10229 origHideTooltip.apply(this, arguments); 10230 editorUi.sidebar.hideTooltip = origHideTooltip; 10231 } 10232 }; 10233 10234 mxEvent.addListener(mask, 'click', function() 10235 { 10236 editorUi.sidebar.hideTooltip(); 10237 }); 10238 } 10239 }; 10240 10241 if (!loading && editorUi.sidebar.currentElt != elt) 10242 { 10243 editorUi.sidebar.hideTooltip(); 10244 editorUi.sidebar.currentElt = elt; 10245 loading = true; 10246 img.src = '/images/aui-wait.gif'; 10247 10248 function renderXML(xml) 10249 { 10250 if (loading && editorUi.sidebar.currentElt == elt) 10251 { 10252 showTooltip(xml, mxEvent.getClientX(evt), mxEvent.getClientY(evt)); 10253 } 10254 10255 loading = false; 10256 img.src = '/images/icon-search.svg'; 10257 }; 10258 10259 if (diagram.isExt) 10260 { 10261 loadExtDoc(diagram, renderXML, function() 10262 { 10263 showError(mxResources.get('cantLoadPrev')); 10264 loading = false; 10265 img.src = '/images/icon-search.svg'; 10266 }); 10267 } 10268 else 10269 { 10270 loadXmlData(diagram.url, renderXML); 10271 } 10272 } 10273 else 10274 { 10275 editorUi.sidebar.hideTooltip(); 10276 } 10277 }; 10278 10279 function swapActiveItem(newItem, activeCls, itemInfo) 10280 { 10281 if (currentItem != null) 10282 { 10283 var classes = currentItem.className.split(" "); 10284 10285 for (var i = 0; i < classes.length; i++) 10286 { 10287 if (classes[i].indexOf("Active") > -1) 10288 { 10289 classes.splice(i, 1); 10290 break; 10291 } 10292 } 10293 10294 currentItem.className = classes.join(" "); 10295 } 10296 10297 if (newItem != null) 10298 { 10299 currentItem = newItem; 10300 currentItem.className += " " + activeCls; 10301 currentItemInfo = itemInfo; 10302 categorySelected = itemInfo.isCategory; 10303 //activate create button 10304 createBtn.className = "geTempDlgCreateBtn"; 10305 } 10306 else 10307 { 10308 currentItem = null; 10309 currentItemInfo = null; 10310 //disable create button 10311 createBtn.className = "geTempDlgCreateBtn geTempDlgBtnDisabled"; 10312 } 10313 }; 10314 10315 function handleDialogOK(linkToDiagram, openDiagram) 10316 { 10317 if (currentItemInfo != null) 10318 { 10319 var itemInfo = currentItemInfo; 10320 //disable create button 10321 currentItemInfo = null; 10322 10323 if (typeof openDiagram !== 'boolean') 10324 { 10325 openDiagram = itemInfo.isExternal && withOpen; //Double click default to open with external docs 10326 } 10327 10328 function cancelSubmit() 10329 { 10330 currentItemInfo = itemInfo; 10331 createBtn.className = 'geTempDlgCreateBtn'; 10332 10333 if (openDiagram) 10334 { 10335 openBtn.className = 'geTempDlgOpenBtn'; 10336 } 10337 }; 10338 10339 function submitErr() 10340 { 10341 showError(mxResources.get('cannotLoad')); 10342 cancelSubmit(); 10343 }; 10344 10345 function doSubmit(xml, filename) 10346 { 10347 if (!noDlgHide) 10348 { 10349 editorUi.hideDialog(true); 10350 } 10351 10352 callback(xml, filename, itemInfo, openDiagram); 10353 }; 10354 10355 function startSubmit(filename) 10356 { 10357 if (itemInfo.isExternal) 10358 { 10359 loadExtDoc(itemInfo, function(xml) 10360 { 10361 doSubmit(xml, filename); 10362 }, submitErr); 10363 } 10364 else if (itemInfo.url) 10365 { 10366 mxUtils.get(TEMPLATE_PATH + '/' + itemInfo.url, mxUtils.bind(this, function(req) 10367 { 10368 if (req.getStatus() >= 200 && req.getStatus() <= 299) 10369 { 10370 doSubmit(req.getText(), filename); 10371 } 10372 else 10373 { 10374 submitErr(); 10375 } 10376 })); 10377 } 10378 else 10379 { 10380 doSubmit(editorUi.emptyDiagramXml, filename); 10381 } 10382 }; 10383 10384 if (linkToDiagram == true) 10385 { 10386 linkToDiagramCallback(itemInfo.url, itemInfo); 10387 } 10388 else if (openDiagram) 10389 { 10390 openBtn.className = "geTempDlgOpenBtn geTempDlgBtnDisabled geTempDlgBtnBusy"; 10391 startSubmit(); 10392 } 10393 else 10394 { 10395 createBtn.className = "geTempDlgCreateBtn geTempDlgBtnDisabled geTempDlgBtnBusy"; 10396 var nameTitle = (((editorUi.mode == null || editorUi.mode == App.MODE_GOOGLE || 10397 editorUi.mode == App.MODE_BROWSER) ? mxResources.get('diagramName') : mxResources.get('filename'))); 10398 var nameDlg = new FilenameDialog(editorUi, editorUi.defaultFilename + '.drawio', 10399 mxResources.get('ok'), startSubmit, nameTitle, function(name) 10400 { 10401 //TODO validate? 10402 var valid = name != null && name.length > 0; 10403 10404 if (valid && noDlgHide) 10405 { 10406 startSubmit(name); 10407 return false; //prevent closing 10408 } 10409 10410 return valid; 10411 }, null, null, null, cancelSubmit, withoutType? null : []); 10412 10413 editorUi.showDialog(nameDlg.container, 350, 80, true, true); 10414 nameDlg.init(); 10415 } 10416 } 10417 }; 10418 10419 function toggleButtons(isTemplate) 10420 { 10421 createBtn.innerHTML = mxUtils.htmlEntities(mxResources.get(inTempScreen || isTemplate? 'create' : 'copy')); 10422 10423 var opemDisplay = isTemplate? 'none' : ''; 10424 10425 if (withOpen) 10426 { 10427 openBtn.style.display = opemDisplay; 10428 } 10429 10430 var elems = dlgDiv.querySelectorAll(".geTempDlgLinkToDiagram"); 10431 10432 for(var i = 0; i < elems.length; i++) 10433 { 10434 elems[i].style.display = opemDisplay; 10435 } 10436 }; 10437 10438 function fillDiagramsList(diagrams, isTemplate, asList, searchImportCats, internalCall) 10439 { 10440 function setSubmitBtnLbl() 10441 { 10442 toggleButtons(isTemplate); 10443 }; 10444 10445 if (!internalCall) 10446 { 10447 diagramsTiles.innerHTML = ''; 10448 swapActiveItem(); 10449 curDiagList = diagrams; 10450 curSearchImportCats = searchImportCats; 10451 } 10452 10453 var grid = null; 10454 10455 if (asList) 10456 { 10457 grid = document.createElement('table'); 10458 grid.className = 'geTempDlgDiagramsListGrid'; 10459 //create header row 10460 var hrow = document.createElement('tr'); 10461 var th = document.createElement('th'); 10462 th.style.width = "50%"; 10463 th.innerHTML = mxUtils.htmlEntities(mxResources.get('diagram')); 10464 hrow.appendChild(th); 10465 th = document.createElement('th'); 10466 th.style.width = "25%"; 10467 th.innerHTML = mxUtils.htmlEntities(mxResources.get('changedBy')); 10468 hrow.appendChild(th); 10469 th = document.createElement('th'); 10470 th.style.width = "25%"; 10471 th.innerHTML = mxUtils.htmlEntities(mxResources.get('lastModifiedOn')); 10472 hrow.appendChild(th); 10473 grid.appendChild(hrow); 10474 diagramsTiles.appendChild(grid); 10475 } 10476 10477 //TODO support paging 10478 for (var i = 0; i < diagrams.length; i++) 10479 { 10480 diagrams[i].isExternal = !isTemplate; 10481 var url = diagrams[i].url; 10482 var title = mxUtils.htmlEntities(isTemplate? 10483 mxResources.get(diagrams[i].title, null, diagrams[i].title): 10484 diagrams[i].title); 10485 var tooltip = title || diagrams[i].url; 10486 var imgUrl = diagrams[i].imgUrl; 10487 var changedBy = mxUtils.htmlEntities(diagrams[i].changedBy || ""); 10488 var lastModifiedOn = ''; 10489 10490 if (diagrams[i].lastModifiedOn) 10491 { 10492 var str = editorUi.timeSince(new Date(diagrams[i].lastModifiedOn)); 10493 10494 if (str == null) 10495 { 10496 str = mxResources.get('lessThanAMinute'); 10497 } 10498 10499 lastModifiedOn = mxUtils.htmlEntities(mxResources.get('timeAgo', [str], '{1} ago')); 10500 } 10501 10502 if (!imgUrl) 10503 { 10504 imgUrl = TEMPLATE_PATH + '/' + url.substring(0, url.length - 4) + '.png'; 10505 } 10506 10507 var titleLimit = asList? 50 : 15; 10508 10509 if (title != null && title.length > titleLimit) 10510 { 10511 title = title.substring(0, titleLimit) + '…'; 10512 } 10513 10514 if (asList) 10515 { 10516 var row = document.createElement('tr'); 10517 var td = document.createElement('td'); 10518 var prevImg = document.createElement('img'); 10519 prevImg.src = "/images/icon-search.svg"; 10520 prevImg.className = "geTempDlgDiagramListPreviewBtn"; 10521 prevImg.setAttribute('title', mxResources.get("preview")); 10522 10523 if (!internalCall) 10524 { 10525 td.appendChild(prevImg); 10526 } 10527 10528 var titleSpan = document.createElement('span'); 10529 titleSpan.className = "geTempDlgDiagramTitle"; 10530 titleSpan.innerHTML = title; 10531 td.appendChild(titleSpan); 10532 row.appendChild(td); 10533 td = document.createElement('td'); 10534 td.innerHTML = changedBy; 10535 row.appendChild(td); 10536 td = document.createElement('td'); 10537 td.innerHTML = lastModifiedOn; 10538 row.appendChild(td); 10539 grid.appendChild(row); 10540 10541 if (currentItem == null) 10542 { 10543 setSubmitBtnLbl(); 10544 swapActiveItem(row, "geTempDlgDiagramsListGridActive", diagrams[i]); 10545 } 10546 10547 (function(diagram2, row2, prevImg2) 10548 { 10549 mxEvent.addListener(row, 'click', function() 10550 { 10551 if (currentItem != row2) 10552 { 10553 setSubmitBtnLbl(); 10554 swapActiveItem(row2, "geTempDlgDiagramsListGridActive", diagram2); 10555 } 10556 }); 10557 10558 mxEvent.addListener(row, 'dblclick', handleDialogOK); 10559 10560 mxEvent.addListener(prevImg, 'click', function(evt) 10561 { 10562 createPreview(diagram2, row2, prevImg2, evt); 10563 }); 10564 })(diagrams[i], row, prevImg); 10565 } 10566 else 10567 { 10568 var tile = document.createElement('div'); 10569 tile.className = "geTempDlgDiagramTile"; 10570 tile.setAttribute('title', tooltip); 10571 10572 if (currentItem == null) 10573 { 10574 setSubmitBtnLbl(); 10575 swapActiveItem(tile, "geTempDlgDiagramTileActive", diagrams[i]); 10576 } 10577 10578 var imgDiv = document.createElement('div'); 10579 imgDiv.className = "geTempDlgDiagramTileImg geTempDlgDiagramTileImgLoading"; 10580 var img = document.createElement('img'); 10581 img.style.display = "none"; 10582 10583 (function(img2, imgDiv2, fallbackImgUrl) 10584 { 10585 img.onload = function() 10586 { 10587 imgDiv2.className = "geTempDlgDiagramTileImg"; 10588 img2.style.display = ""; 10589 } 10590 10591 img.onerror = function() 10592 { 10593 if (this.src != fallbackImgUrl) 10594 { 10595 this.src = fallbackImgUrl; 10596 } 10597 else 10598 { 10599 imgDiv2.className = "geTempDlgDiagramTileImg geTempDlgDiagramTileImgError"; 10600 } 10601 } 10602 })(img, imgDiv, imgUrl? imgUrl.replace('.drawio.xml', '').replace('.drawio', '').replace('.xml', '') : ''); 10603 10604 img.src = imgUrl; 10605 imgDiv.appendChild(img); 10606 tile.appendChild(imgDiv); 10607 10608 var lblDiv = document.createElement('div'); 10609 lblDiv.className = "geTempDlgDiagramTileLbl"; 10610 lblDiv.innerHTML = title != null? title : ''; 10611 tile.appendChild(lblDiv); 10612 10613 var prevImg = document.createElement('img'); 10614 prevImg.src = "/images/icon-search.svg"; 10615 prevImg.className = "geTempDlgDiagramPreviewBtn"; 10616 prevImg.setAttribute('title', mxResources.get("preview")); 10617 10618 if (!internalCall) 10619 { 10620 tile.appendChild(prevImg); 10621 } 10622 10623 (function(diagram2, tile2, prevImg2) 10624 { 10625 mxEvent.addListener(tile, 'click', function() 10626 { 10627 if (currentItem != tile2) 10628 { 10629 setSubmitBtnLbl(); 10630 swapActiveItem(tile2, "geTempDlgDiagramTileActive", diagram2); 10631 } 10632 }); 10633 10634 mxEvent.addListener(tile, 'dblclick', handleDialogOK); 10635 10636 mxEvent.addListener(prevImg, 'click', function(evt) 10637 { 10638 createPreview(diagram2, tile2, prevImg2, evt); 10639 }); 10640 })(diagrams[i], tile, prevImg); 10641 10642 diagramsTiles.appendChild(tile); 10643 } 10644 } 10645 10646 for (var cat in searchImportCats) 10647 { 10648 var catList = searchImportCats[cat]; 10649 10650 if (catList.length > 0) 10651 { 10652 var header = document.createElement('div'); 10653 header.className = 'geTempDlgImportCat'; 10654 header.innerHTML = mxResources.get(cat, null, cat); 10655 diagramsTiles.appendChild(header); 10656 fillDiagramsList(catList, isTemplate, asList, null, true); 10657 } 10658 } 10659 }; 10660 10661 function fillNewDiagramCats(newDiagramCats, showAll) 10662 { 10663 newDiagramCatList.innerHTML = ""; 10664 swapActiveItem(); 10665 var oneRowCount = Math.floor(newDiagramCatList.offsetWidth / 150) - 1; 10666 var catCount = !showAll && newDiagramCats.length > oneRowCount ? oneRowCount : newDiagramCats.length; 10667 10668 for (var i = 0; i < catCount; i++) 10669 { 10670 var cat = newDiagramCats[i]; 10671 cat.isCategory = true; 10672 var entry = document.createElement('div'); 10673 var label = mxResources.get(cat.title); 10674 10675 if (label == null) 10676 { 10677 label = cat.title.substring(0, 1).toUpperCase() + cat.title.substring(1); 10678 } 10679 10680 entry.className = 'geTempDlgNewDiagramCatItem'; 10681 entry.setAttribute('title', label); 10682 10683 label = mxUtils.htmlEntities(label); 10684 10685 if (label.length > 15) 10686 { 10687 label = label.substring(0, 15) + '…'; 10688 } 10689 10690 if (currentItem == null) 10691 { 10692 toggleButtons(true); 10693 swapActiveItem(entry, "geTempDlgNewDiagramCatItemActive", cat); 10694 } 10695 10696 var imgDiv = document.createElement('div'); 10697 imgDiv.className = "geTempDlgNewDiagramCatItemImg"; 10698 var img = document.createElement('img'); 10699 img.src = NEW_DIAGRAM_CATS_PATH + '/' + cat.img; 10700 imgDiv.appendChild(img); 10701 entry.appendChild(imgDiv); 10702 10703 var lblDiv = document.createElement('div'); 10704 lblDiv.className = "geTempDlgNewDiagramCatItemLbl"; 10705 lblDiv.innerHTML = label; 10706 entry.appendChild(lblDiv); 10707 10708 newDiagramCatList.appendChild(entry); 10709 10710 (function(cat2, entry2) 10711 { 10712 mxEvent.addListener(entry, 'click', function() 10713 { 10714 if (currentItem != entry2) 10715 { 10716 toggleButtons(true); 10717 swapActiveItem(entry2, "geTempDlgNewDiagramCatItemActive", cat2); 10718 } 10719 }); 10720 10721 mxEvent.addListener(entry, 'dblclick', handleDialogOK); 10722 })(cat, entry); 10723 } 10724 10725 //Add the "Show All Templates" card 10726 var entry = document.createElement('div'); 10727 entry.className = 'geTempDlgNewDiagramCatItem'; 10728 var label = mxResources.get('showAllTemps'); 10729 entry.setAttribute('title', label); 10730 var imgDiv = document.createElement('div'); 10731 imgDiv.className = "geTempDlgNewDiagramCatItemImg"; 10732 imgDiv.innerHTML = '...'; 10733 imgDiv.style.fontSize = '32px'; 10734 entry.appendChild(imgDiv); 10735 var lblDiv = document.createElement('div'); 10736 lblDiv.className = "geTempDlgNewDiagramCatItemLbl"; 10737 lblDiv.innerHTML = label; 10738 entry.appendChild(lblDiv); 10739 newDiagramCatList.appendChild(entry); 10740 10741 mxEvent.addListener(entry, 'click', function() 10742 { 10743 //Show templates screen 10744 inTempScreen = true; 10745 var list = dlgDiv.querySelector(".geTemplatesList"); 10746 list.style.display = 'block'; 10747 tempDlgContent.style.width = ''; 10748 searchInout.style.display = ''; 10749 searchInout.value = ''; 10750 lastSearchStr = null; 10751 10752 function openFirstCat() 10753 { 10754 var firstCat = list.querySelector('.geTemplateDrawioCatLink'); 10755 10756 if (firstCat != null) 10757 { 10758 firstCat.click(); 10759 } 10760 else 10761 { 10762 setTimeout(openFirstCat, 200); 10763 } 10764 }; 10765 10766 openFirstCat(); 10767 }); 10768 10769 showAllBtn.style.display = newDiagramCats.length <= oneRowCount ? "none" : ""; 10770 }; 10771 10772 mxEvent.addListener(showAllBtn, 'click', function() 10773 { 10774 if (showingAll) 10775 { 10776 newDiagramCat.style.height = "280px"; 10777 newDiagramCatList.style.height = "190px"; 10778 showAllBtn.innerHTML = mxUtils.htmlEntities(mxResources.get('showMore')); 10779 fillNewDiagramCats(newDiagramCats); 10780 } 10781 else 10782 { 10783 newDiagramCat.style.height = "440px"; 10784 newDiagramCatList.style.height = "355px"; 10785 showAllBtn.innerHTML = mxUtils.htmlEntities(mxResources.get('showLess')); 10786 fillNewDiagramCats(newDiagramCats, true); 10787 } 10788 10789 showingAll = !showingAll; 10790 }); 10791 10792 function fillTemplatesList(categories, customCats, customCatCount) 10793 { 10794 var list = dlgDiv.querySelector(".geTemplatesList"); 10795 10796 function getEntryTitle(cat, templateList) 10797 { 10798 var label = mxResources.get(cat); 10799 10800 if (label == null) 10801 { 10802 label = cat.substring(0, 1).toUpperCase() + cat.substring(1); 10803 } 10804 10805 var fullLbl = label + ' (' + templateList.length + ')'; 10806 label = mxUtils.htmlEntities(label); 10807 var lblOnly = label; 10808 10809 if (label.length > 15) 10810 { 10811 label = label.substring(0, 15) + '…'; 10812 } 10813 10814 return {lbl: label + ' (' + templateList.length + ')', fullLbl: fullLbl, lblOnly: lblOnly}; 10815 }; 10816 10817 function addEntryHandler(cat, label, entry, subCat, isCustom) 10818 { 10819 mxEvent.addListener(entry, 'click', function() 10820 { 10821 if (currentEntry != entry) 10822 { 10823 if (currentEntry != null) 10824 { 10825 currentEntry.style.fontWeight = 'normal'; 10826 currentEntry.style.textDecoration = 'none'; 10827 } 10828 else 10829 { 10830 newDiagramCat.style.display = 'none'; 10831 diagramsList.style.minHeight = '100%'; 10832 } 10833 10834 currentEntry = entry; 10835 currentEntry.style.fontWeight = 'bold'; 10836 currentEntry.style.textDecoration = 'underline'; 10837 10838 tempDlgContent.scrollTop = 0; 10839 10840 if (callInitiated) 10841 { 10842 cancelPendingCall = true; 10843 } 10844 10845 diagramsListTitle.innerHTML = label; 10846 diagramsListBtns.style.display = 'none'; 10847 fillDiagramsList(isCustom ? customCats[cat] : 10848 (subCat? subCategories[cat][subCat] : categories[cat]), isCustom ? false : true); 10849 } 10850 }); 10851 }; 10852 10853 if (customCatCount > 0) 10854 { 10855 var titleCss = 'font-weight: bold;background: #f9f9f9;padding: 5px 0 5px 0;text-align: center;margin-top: 10px;'; 10856 var title = document.createElement('div'); 10857 title.style.cssText = titleCss; 10858 mxUtils.write(title, mxResources.get('custom')); 10859 list.appendChild(title); 10860 10861 for (var cat in customCats) 10862 { 10863 var entry = document.createElement('div'); 10864 var templateList = customCats[cat]; 10865 var lbls = getEntryTitle(cat, templateList); 10866 entry.className = 'geTemplateCatLink'; 10867 entry.setAttribute('title', lbls.fullLbl); 10868 entry.innerHTML = lbls.lbl; 10869 list.appendChild(entry); 10870 addEntryHandler(cat, lbls.lblOnly, entry, null, true); 10871 } 10872 10873 title = document.createElement('div'); 10874 title.style.cssText = titleCss; 10875 mxUtils.write(title, 'draw.io'); 10876 list.appendChild(title); 10877 } 10878 10879 for (var cat in categories) 10880 { 10881 var subCats = subCategories[cat]; 10882 var entry = document.createElement(subCats? 'ul' : 'div'); 10883 var clickElem = entry; 10884 var templateList = categories[cat]; 10885 var lbls = getEntryTitle(cat, templateList); 10886 10887 if (subCats != null) 10888 { 10889 var entryLi = document.createElement('li'); 10890 var entryDiv = document.createElement('div'); 10891 entryDiv.className = 'geTempTreeCaret geTemplateCatLink geTemplateDrawioCatLink'; 10892 entryDiv.style.padding = '0'; 10893 entryDiv.setAttribute('title', lbls.fullLbl); 10894 entryDiv.innerHTML = lbls.lbl; 10895 clickElem = entryDiv; 10896 entryLi.appendChild(entryDiv); 10897 //We support one level deep only 10898 var subUl = document.createElement('ul'); 10899 subUl.className = 'geTempTreeNested'; 10900 subUl.style.visibility = 'hidden'; 10901 10902 for (var subCat in subCats) 10903 { 10904 var subLi = document.createElement('li'); 10905 var subLbls = getEntryTitle(subCat, subCats[subCat]); 10906 subLi.setAttribute('title', subLbls.fullLbl); 10907 subLi.innerHTML = subLbls.lbl; 10908 subLi.className = 'geTemplateCatLink'; 10909 subLi.style.padding = '0'; 10910 subLi.style.margin = '0'; 10911 addEntryHandler(cat, subLbls.lblOnly, subLi, subCat); 10912 subUl.appendChild(subLi); 10913 } 10914 10915 entryLi.appendChild(subUl); 10916 entry.className = 'geTempTree'; 10917 entry.appendChild(entryLi); 10918 10919 (function(subUl2, entryDiv2) 10920 { 10921 mxEvent.addListener(entryDiv2, 'click', function() 10922 { 10923 var lis = subUl2.querySelectorAll('li'); 10924 10925 for (var i = 0; i < lis.length; i++) 10926 { 10927 lis[i].style.margin = ''; 10928 } 10929 10930 subUl2.style.visibility = 'visible'; 10931 subUl2.classList.toggle('geTempTreeActive'); 10932 10933 if (subUl2.classList.toggle('geTempTreeNested')) 10934 { 10935 //Must hide sub elements to allow click on elements above it 10936 setTimeout(function() 10937 { 10938 for (var i = 0; i < lis.length; i++) 10939 { 10940 lis[i].style.margin = '0'; 10941 } 10942 10943 subUl2.style.visibility = 'hidden'; 10944 }, 250); 10945 } 10946 10947 entryDiv2.classList.toggle('geTempTreeCaret-down'); 10948 }); 10949 })(subUl, entryDiv); 10950 } 10951 else 10952 { 10953 entry.className = 'geTemplateCatLink geTemplateDrawioCatLink'; 10954 entry.setAttribute('title', lbls.fullLbl); 10955 entry.innerHTML = lbls.lbl; 10956 } 10957 10958 list.appendChild(entry); 10959 addEntryHandler(cat, lbls.lblOnly, clickElem); 10960 } 10961 }; 10962 10963 var indexLoaded = false, indexLoaded2 = false; 10964 var categories = {}, subCategories = {}, customCats = {}; 10965 var newDiagramCats = []; 10966 var categoryCount = 1, customCatCount = 0; 10967 10968 function loadDrawioTemplates() 10969 { 10970 mxUtils.get(templateFile, function(req) 10971 { 10972 // Workaround for index loaded 3 times in iOS offline mode 10973 if (!indexLoaded) 10974 { 10975 indexLoaded = true; 10976 var tmpDoc = req.getXml(); 10977 var node = tmpDoc.documentElement.firstChild; 10978 var clibs = {}; 10979 10980 while (node != null) 10981 { 10982 if (typeof(node.getAttribute) !== 'undefined') 10983 { 10984 if (node.nodeName == 'clibs') 10985 { 10986 var name = node.getAttribute('name'); 10987 var adds = node.getElementsByTagName('add'); 10988 var temp = []; 10989 10990 for (var i = 0; i < adds.length; i++) 10991 { 10992 temp.push(encodeURIComponent(mxUtils.getTextContent(adds[i]))); 10993 } 10994 10995 if (name != null && temp.length > 0) 10996 { 10997 clibs[name] = temp.join(';'); 10998 } 10999 } 11000 else 11001 { 11002 var url = node.getAttribute('url'); 11003 11004 if (url != null) 11005 { 11006 var category = node.getAttribute('section'); 11007 var subCategory = node.getAttribute('subsection'); 11008 11009 if (category == null) 11010 { 11011 var slash = url.indexOf('/'); 11012 category = url.substring(0, slash); 11013 11014 if (subCategory == null) 11015 { 11016 var nextSlash = url.indexOf('/', slash + 1); 11017 11018 if (nextSlash > -1) 11019 { 11020 subCategory = url.substring(slash + 1, nextSlash); 11021 } 11022 } 11023 } 11024 11025 var list = categories[category]; 11026 11027 if (list == null) 11028 { 11029 categoryCount++; 11030 list = []; 11031 categories[category] = list; 11032 } 11033 11034 var tempLibs = node.getAttribute('clibs'); 11035 11036 if (clibs[tempLibs] != null) 11037 { 11038 tempLibs = clibs[tempLibs]; 11039 } 11040 11041 var tempObj = {url: node.getAttribute('url'), libs: node.getAttribute('libs'), 11042 title: node.getAttribute('title') || node.getAttribute('name'), 11043 preview: node.getAttribute('preview'), clibs: tempLibs, tags: node.getAttribute('tags')}; 11044 list.push(tempObj); 11045 11046 if (subCategory != null) 11047 { 11048 var subCats = subCategories[category]; 11049 11050 if (subCats == null) 11051 { 11052 subCats = {}; 11053 subCategories[category] = subCats; 11054 } 11055 11056 var subCatList = subCats[subCategory]; 11057 11058 if (subCatList == null) 11059 { 11060 subCatList = []; 11061 subCats[subCategory] = subCatList; 11062 } 11063 11064 subCatList.push(tempObj); 11065 } 11066 } 11067 } 11068 } 11069 11070 node = node.nextSibling; 11071 } 11072 11073 fillTemplatesList(categories, customCats, customCatCount); 11074 } 11075 }); 11076 }; 11077 11078 if (customTempCallback != null) 11079 { 11080 customTempCallback(function(cats, count) 11081 { 11082 customCats = cats; 11083 customCatCount = count; 11084 loadDrawioTemplates(); 11085 }, loadDrawioTemplates); //In case of an error, just load draw.io templates only 11086 } 11087 else 11088 { 11089 loadDrawioTemplates(); 11090 } 11091 11092 mxUtils.get(newDiagramCatsFile, function(req) 11093 { 11094 // Workaround for index loaded 3 times in iOS offline mode 11095 if (!indexLoaded2) 11096 { 11097 indexLoaded2 = true; 11098 var tmpDoc = req.getXml(); 11099 var node = tmpDoc.documentElement.firstChild; 11100 11101 while (node != null) 11102 { 11103 if (typeof(node.getAttribute) !== 'undefined') 11104 { 11105 var title = node.getAttribute('title'); 11106 11107 if (title != null) 11108 { 11109 newDiagramCats.push({img: node.getAttribute('img'), libs: node.getAttribute('libs'), 11110 clibs: node.getAttribute('clibs'), title: node.getAttribute('title')}); 11111 } 11112 } 11113 11114 node = node.nextSibling; 11115 } 11116 11117 fillNewDiagramCats(newDiagramCats); 11118 } 11119 }); 11120 11121 var extDiagramsCallback = function(list, errorMsg, searchImportCats) 11122 { 11123 diagramsListBtns.style.display = ''; 11124 spinner.stop(); 11125 11126 callInitiated = false; 11127 11128 if (cancelPendingCall) 11129 { 11130 cancelPendingCall = false; 11131 return; 11132 } 11133 11134 if (errorMsg) 11135 { 11136 diagramsTiles.innerHTML = errorMsg; 11137 } 11138 else 11139 { 11140 searchImportCats = searchImportCats || {}; 11141 var importListsCount = 0; 11142 11143 for (var cat in searchImportCats) 11144 { 11145 importListsCount += searchImportCats[cat].length; 11146 } 11147 11148 if (list.length == 0 && importListsCount == 0) 11149 { 11150 diagramsTiles.innerHTML = mxUtils.htmlEntities(mxResources.get('noDiagrams')); 11151 } 11152 else 11153 { 11154 fillDiagramsList(list, false, showAsList, importListsCount == 0? null : searchImportCats); 11155 } 11156 } 11157 }; 11158 11159 function getRecentDocs(getAll) 11160 { 11161 if (recentDocsCallback) 11162 { 11163 tempDlgContent.scrollTop = 0; 11164 diagramsTiles.innerHTML = ''; 11165 spinner.spin(diagramsTiles); 11166 cancelPendingCall = false; 11167 callInitiated = true; 11168 diagramsListTitle.innerHTML = mxUtils.htmlEntities(mxResources.get('recentDiag')); 11169 lastSearchStr = null; 11170 recentDocsCallback(extDiagramsCallback, function() 11171 { 11172 showError(mxResources.get('cannotLoad')); 11173 extDiagramsCallback([]); 11174 }, getAll? null : username); 11175 } 11176 }; 11177 11178 getRecentDocs(isGetAll); 11179 11180 var delayTimer = null; 11181 11182 function resetTemplates() 11183 { 11184 if (lastEntry != null) 11185 { 11186 lastEntry.click(); 11187 lastEntry = null; 11188 } 11189 }; 11190 11191 function filterTemplates(searchTerms) 11192 { 11193 if (searchTerms == '') 11194 { 11195 resetTemplates(); 11196 return; 11197 } 11198 11199 if (TemplatesDialog.tagsList[templateFile] == null) 11200 { 11201 var tagsList = {}; 11202 11203 for (var cat in categories) 11204 { 11205 var templateList = categories[cat]; 11206 11207 for (var i = 0; i < templateList.length; i++) 11208 { 11209 var temp = templateList[i]; 11210 11211 if (temp.tags != null) 11212 { 11213 var tags = temp.tags.toLowerCase().split(';'); 11214 11215 for (var j = 0; j < tags.length; j++) 11216 { 11217 if (tagsList[tags[j]] == null) 11218 { 11219 tagsList[tags[j]] = []; 11220 } 11221 11222 tagsList[tags[j]].push(temp); 11223 } 11224 } 11225 } 11226 } 11227 11228 TemplatesDialog.tagsList[templateFile] = tagsList; 11229 } 11230 11231 var tmp = searchTerms.toLowerCase().split(' '); 11232 tagsList = TemplatesDialog.tagsList[templateFile]; 11233 11234 if (customCatCount > 0 && tagsList.__tagsList__ == null) 11235 { 11236 for (var cat in customCats) 11237 { 11238 var templateList = customCats[cat]; 11239 11240 for (var i = 0; i < templateList.length; i++) 11241 { 11242 var temp = templateList[i]; 11243 var tags = temp.title.split(' '); 11244 tags.push(cat); 11245 11246 for (var j = 0; j < tags.length; j++) 11247 { 11248 var tag = tags[j].toLowerCase(); 11249 11250 if (tagsList[tag] == null) 11251 { 11252 tagsList[tag] = []; 11253 } 11254 11255 tagsList[tag].push(temp); 11256 } 11257 } 11258 } 11259 11260 tagsList.__tagsList__ = true; 11261 } 11262 11263 var results = [], resMap = {}, index = 0; 11264 11265 for (var i = 0; i < tmp.length; i++) 11266 { 11267 if (tmp[i].length > 0) 11268 { 11269 var list = tagsList[tmp[i]]; 11270 var tmpResMap = {}; 11271 results = []; 11272 11273 if (list != null) 11274 { 11275 for (var j = 0; j < list.length; j++) 11276 { 11277 var temp = list[j]; 11278 11279 //ANDing terms 11280 if ((index == 0) == (resMap[temp.url] == null)) 11281 { 11282 tmpResMap[temp.url] = true; 11283 results.push(temp); 11284 } 11285 } 11286 } 11287 11288 resMap = tmpResMap; 11289 index++; 11290 } 11291 } 11292 11293 if (results.length == 0) 11294 { 11295 diagramsListTitle.innerHTML = mxResources.get('noResultsFor', [searchTerms]); 11296 } 11297 else 11298 { 11299 fillDiagramsList(results, true); 11300 } 11301 }; 11302 11303 function doSearch(searchStr) 11304 { 11305 if (lastSearchStr == searchStr && isGetAll == lastGetAll) return; 11306 11307 deselectTempCat(); 11308 tempDlgContent.scrollTop = 0; 11309 diagramsTiles.innerHTML = ''; 11310 diagramsListTitle.innerHTML = mxUtils.htmlEntities(mxResources.get('searchResults')) + 11311 ' "' + mxUtils.htmlEntities(searchStr) + '"'; 11312 delayTimer = null; 11313 11314 if (inTempScreen) 11315 { 11316 //Do search in templates 11317 filterTemplates(searchStr); 11318 } 11319 else if (searchDocsCallback) 11320 { 11321 if (searchStr) 11322 { 11323 spinner.spin(diagramsTiles); 11324 cancelPendingCall = false; 11325 callInitiated = true; 11326 //TODO use request id to allow only last request to show results 11327 searchDocsCallback(searchStr, extDiagramsCallback, function() 11328 { 11329 showError(mxResources.get('searchFailed')); 11330 extDiagramsCallback([]); 11331 }, isGetAll? null : username); 11332 } 11333 else 11334 { 11335 getRecentDocs(isGetAll); //Load recent doc again 11336 } 11337 } 11338 11339 lastSearchStr = searchStr; 11340 lastGetAll = isGetAll; 11341 }; 11342 11343 function searchEvent(evt) 11344 { 11345 if (delayTimer != null) 11346 { 11347 clearTimeout(delayTimer); 11348 } 11349 11350 if (evt.keyCode == 13) 11351 { 11352 doSearch(searchInout.value); 11353 } 11354 else 11355 { 11356 delayTimer = setTimeout(function() 11357 { 11358 doSearch(searchInout.value); 11359 }, 1000); 11360 } 11361 }; 11362 11363 //Use keyup to detect delete and backspace 11364 mxEvent.addListener(searchInout, 'keyup', searchEvent); 11365 //To detect copy/paste and clear 11366 mxEvent.addListener(searchInout, 'search', searchEvent); 11367 mxEvent.addListener(searchInout, 'input', searchEvent); 11368 11369 mxEvent.addListener(createBtn, 'click', function(evt) 11370 { 11371 handleDialogOK(false, false); 11372 }); 11373 11374 if (withOpen) 11375 { 11376 mxEvent.addListener(openBtn, 'click', function(evt) 11377 { 11378 handleDialogOK(false, true); 11379 }); 11380 } 11381 11382 if (withLink) 11383 { 11384 mxEvent.addListener(dlgDiv.querySelector(".geTempDlgLinkToDiagramBtn"), 'click', function(evt) 11385 { 11386 handleDialogOK(true); 11387 }); 11388 } 11389 11390 mxEvent.addListener(dlgDiv.querySelector('.geTempDlgCancelBtn'), 'click', function() 11391 { 11392 if (cancelCallback != null) 11393 { 11394 cancelCallback(); 11395 } 11396 11397 if (!noDlgHide) 11398 { 11399 editorUi.hideDialog(true); 11400 } 11401 }); 11402}; 11403 11404TemplatesDialog.tagsList = {}; 11405/** 11406 * Constructs a new popup opener button dialog. 11407 */ 11408var BtnDialog = function(editorUi, peer, btnLbl, fn) 11409{ 11410 var div = document.createElement('div'); 11411 div.style.textAlign = 'center'; 11412 11413 var hd = document.createElement('p'); 11414 hd.style.fontSize = '16pt'; 11415 hd.style.padding = '0px'; 11416 hd.style.margin = '0px'; 11417 hd.style.color = 'gray'; 11418 11419 mxUtils.write(hd, mxResources.get('done')); 11420 11421 var service = 'Unknown'; 11422 11423 var img = document.createElement('img'); 11424 img.setAttribute('border', '0'); 11425 img.setAttribute('align', 'absmiddle'); 11426 img.style.marginRight = '10px'; 11427 11428 if (peer == editorUi.drive) 11429 { 11430 service = mxResources.get('googleDrive'); 11431 img.src = IMAGE_PATH + '/google-drive-logo-white.svg'; 11432 } 11433 else if (peer == editorUi.dropbox) 11434 { 11435 service = mxResources.get('dropbox'); 11436 img.src = IMAGE_PATH + '/dropbox-logo-white.svg'; 11437 } 11438 else if (peer == editorUi.oneDrive) 11439 { 11440 service = mxResources.get('oneDrive'); 11441 img.src = IMAGE_PATH + '/onedrive-logo-white.svg'; 11442 } 11443 else if (peer == editorUi.gitHub) 11444 { 11445 service = mxResources.get('github'); 11446 img.src = IMAGE_PATH + '/github-logo-white.svg'; 11447 } 11448 else if (peer == editorUi.gitLab) 11449 { 11450 service = mxResources.get('gitlab'); 11451 img.src = IMAGE_PATH + '/gitlab-logo.svg'; 11452 } 11453 else if (peer == editorUi.notion) 11454 { 11455 service = mxResources.get('notion'); 11456 img.src = IMAGE_PATH + '/notion-logo.svg'; 11457 } 11458 else if (peer == editorUi.trello) 11459 { 11460 service = mxResources.get('trello'); 11461 img.src = IMAGE_PATH + '/trello-logo-white.svg'; 11462 } 11463 11464 var p = document.createElement('p'); 11465 mxUtils.write(p, mxResources.get('authorizedIn', [service], 'You are now authorized in {1}')); 11466 11467 var button = mxUtils.button(btnLbl, fn); 11468 11469 button.insertBefore(img, button.firstChild); 11470 button.style.marginTop = '6px'; 11471 button.className = 'geBigButton'; 11472 button.style.fontSize = '18px'; 11473 button.style.padding = '14px'; 11474 11475 div.appendChild(hd); 11476 div.appendChild(p); 11477 div.appendChild(button); 11478 11479 this.container = div; 11480}; 11481 11482/** 11483 * Constructs a new font dialog. 11484 */ 11485var FontDialog = function(editorUi, curFontname, curUrl, curType, fn) 11486{ 11487 var row, td, label; 11488 11489 var table = document.createElement('table'); 11490 var tbody = document.createElement('tbody'); 11491 table.style.marginTop = '8px'; 11492 11493 //System fonts section 11494 row = document.createElement('tr'); 11495 11496 td = document.createElement('td'); 11497 td.colSpan = 2; 11498 td.style.whiteSpace = 'nowrap'; 11499 td.style.fontSize = '10pt'; 11500 td.style.fontWeight = 'bold'; 11501 11502 var sysFontRadio = document.createElement('input'); 11503 sysFontRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 11504 sysFontRadio.setAttribute('value', 'sysfonts'); 11505 sysFontRadio.setAttribute('type', 'radio'); 11506 sysFontRadio.setAttribute('name', 'current-fontdialog'); 11507 sysFontRadio.setAttribute('id', 'fontdialog-sysfonts'); 11508 td.appendChild(sysFontRadio); 11509 11510 label = document.createElement('label'); 11511 label.setAttribute('for', 'fontdialog-sysfonts'); 11512 mxUtils.write(label, (mxResources.get('sysFonts', null, 'System Fonts'))); 11513 td.appendChild(label); 11514 11515 row.appendChild(td); 11516 tbody.appendChild(row); 11517 11518 row = document.createElement('tr'); 11519 11520 td = document.createElement('td'); 11521 td.style.whiteSpace = 'nowrap'; 11522 td.style.fontSize = '10pt'; 11523 td.style.width = '120px'; 11524 td.style.paddingLeft = '15px'; 11525 mxUtils.write(td, (mxResources.get('fontname', null, 'Font Name')) + ':'); 11526 11527 row.appendChild(td); 11528 11529 var sysFontInput = document.createElement('input'); 11530 11531 if (curType == 's') 11532 { 11533 sysFontInput.setAttribute('value', curFontname); 11534 } 11535 11536 sysFontInput.style.marginLeft = '4px'; 11537 sysFontInput.style.width = '250px'; 11538 sysFontInput.className = 'dlg_fontName_s'; 11539 11540 td = document.createElement('td'); 11541 td.appendChild(sysFontInput); 11542 row.appendChild(td); 11543 11544 tbody.appendChild(row); 11545 11546 //Google fonts section 11547 row = document.createElement('tr'); 11548 11549 td = document.createElement('td'); 11550 td.colSpan = 2; 11551 td.style.whiteSpace = 'nowrap'; 11552 td.style.fontSize = '10pt'; 11553 td.style.fontWeight = 'bold'; 11554 11555 var googleFontRadio = document.createElement('input'); 11556 googleFontRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 11557 googleFontRadio.setAttribute('value', 'googlefonts'); 11558 googleFontRadio.setAttribute('type', 'radio'); 11559 googleFontRadio.setAttribute('name', 'current-fontdialog'); 11560 googleFontRadio.setAttribute('id', 'fontdialog-googlefonts'); 11561 td.appendChild(googleFontRadio); 11562 11563 label = document.createElement('label'); 11564 label.setAttribute('for', 'fontdialog-googlefonts'); 11565 mxUtils.write(label, (mxResources.get('googleFonts', null, 'Google Fonts'))); 11566 td.appendChild(label); 11567 11568 // Link to Google Fonts 11569 if (!mxClient.IS_CHROMEAPP && (!editorUi.isOffline() || EditorUi.isElectronApp)) 11570 { 11571 var link = editorUi.menus.createHelpLink('https://fonts.google.com/'); 11572 link.getElementsByTagName('img')[0].setAttribute('valign', 'middle'); 11573 td.appendChild(link); 11574 } 11575 11576 row.appendChild(td); 11577 tbody.appendChild(row); 11578 11579 row = document.createElement('tr'); 11580 11581 td = document.createElement('td'); 11582 td.style.whiteSpace = 'nowrap'; 11583 td.style.fontSize = '10pt'; 11584 td.style.width = '120px'; 11585 td.style.paddingLeft = '15px'; 11586 mxUtils.write(td, (mxResources.get('fontname', null, 'Font Name')) + ':'); 11587 11588 row.appendChild(td); 11589 11590 var googleFontInput = document.createElement('input'); 11591 11592 if (curType == 'g') 11593 { 11594 googleFontInput.setAttribute('value', curFontname); 11595 } 11596 11597 googleFontInput.style.marginLeft = '4px'; 11598 googleFontInput.style.width = '250px'; 11599 googleFontInput.className = 'dlg_fontName_g'; 11600 11601 td = document.createElement('td'); 11602 td.appendChild(googleFontInput); 11603 row.appendChild(td); 11604 tbody.appendChild(row); 11605 11606 //Generic remote fonts section 11607 row = document.createElement('tr'); 11608 11609 td = document.createElement('td'); 11610 td.colSpan = 2; 11611 td.style.whiteSpace = 'nowrap'; 11612 td.style.fontSize = '10pt'; 11613 td.style.fontWeight = 'bold'; 11614 11615 var webFontRadio = document.createElement('input'); 11616 webFontRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; 11617 webFontRadio.setAttribute('value', 'webfonts'); 11618 webFontRadio.setAttribute('type', 'radio'); 11619 webFontRadio.setAttribute('name', 'current-fontdialog'); 11620 webFontRadio.setAttribute('id', 'fontdialog-webfonts'); 11621 td.appendChild(webFontRadio); 11622 11623 label = document.createElement('label'); 11624 label.setAttribute('for', 'fontdialog-webfonts'); 11625 mxUtils.write(label, (mxResources.get('webfonts', null, 'Web Fonts'))); 11626 td.appendChild(label); 11627 11628 row.appendChild(td); 11629 11630 if (Editor.enableWebFonts) 11631 { 11632 tbody.appendChild(row); 11633 } 11634 11635 row = document.createElement('tr'); 11636 11637 td = document.createElement('td'); 11638 td.style.whiteSpace = 'nowrap'; 11639 td.style.fontSize = '10pt'; 11640 td.style.width = '120px'; 11641 td.style.paddingLeft = '15px'; 11642 mxUtils.write(td, (mxResources.get('fontname', null, 'Font Name')) + ':'); 11643 11644 row.appendChild(td); 11645 11646 var webFontInput = document.createElement('input'); 11647 11648 if (curType == 'w') 11649 { 11650 if (Editor.enableWebFonts) 11651 { 11652 webFontInput.setAttribute('value', curFontname); 11653 } 11654 else 11655 { 11656 sysFontInput.setAttribute('value', curFontname); 11657 } 11658 } 11659 11660 webFontInput.style.marginLeft = '4px'; 11661 webFontInput.style.width = '250px'; 11662 webFontInput.className = 'dlg_fontName_w'; 11663 11664 td = document.createElement('td'); 11665 td.appendChild(webFontInput); 11666 row.appendChild(td); 11667 11668 if (Editor.enableWebFonts) 11669 { 11670 tbody.appendChild(row); 11671 } 11672 11673 row = document.createElement('tr'); 11674 11675 td = document.createElement('td'); 11676 td.style.whiteSpace = 'nowrap'; 11677 td.style.fontSize = '10pt'; 11678 td.style.width = '120px'; 11679 td.style.paddingLeft = '15px'; 11680 mxUtils.write(td, (mxResources.get('fontUrl', null, 'Font URL')) + ':'); 11681 11682 row.appendChild(td); 11683 11684 var webFontUrlInput = document.createElement('input'); 11685 webFontUrlInput.setAttribute('value', curUrl || ''); 11686 webFontUrlInput.style.marginLeft = '4px'; 11687 webFontUrlInput.style.width = '250px'; 11688 webFontUrlInput.className = 'dlg_fontUrl'; 11689 11690 td = document.createElement('td'); 11691 td.appendChild(webFontUrlInput); 11692 row.appendChild(td); 11693 11694 if (Editor.enableWebFonts) 11695 { 11696 tbody.appendChild(row); 11697 } 11698 11699 this.init = function() 11700 { 11701 var input = sysFontInput; 11702 11703 if (curType == 'g') 11704 { 11705 input = googleFontInput; 11706 } 11707 else if (curType == 'w' && Editor.enableWebFonts) 11708 { 11709 input = webFontInput; 11710 } 11711 11712 input.focus(); 11713 11714 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 11715 { 11716 input.select(); 11717 } 11718 else 11719 { 11720 document.execCommand('selectAll', false, null); 11721 } 11722 }; 11723 11724 row = document.createElement('tr'); 11725 td = document.createElement('td'); 11726 td.colSpan = 2; 11727 td.style.paddingTop = '20px'; 11728 td.style.whiteSpace = 'nowrap'; 11729 td.setAttribute('align', 'right'); 11730 11731 if (!editorUi.isOffline()) 11732 { 11733 var helpBtn = mxUtils.button(mxResources.get('help'), function() 11734 { 11735 editorUi.openLink('https://www.diagrams.net/blog/external-fonts'); 11736 }); 11737 11738 helpBtn.className = 'geBtn'; 11739 td.appendChild(helpBtn); 11740 } 11741 11742 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 11743 { 11744 editorUi.hideDialog(); 11745 fn(); 11746 }); 11747 cancelBtn.className = 'geBtn'; 11748 11749 if (editorUi.editor.cancelFirst) 11750 { 11751 td.appendChild(cancelBtn); 11752 } 11753 11754 function validateFn(fontName, fontUrl, type) 11755 { 11756 var urlPattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; 11757 11758 if (fontName == null || fontName.length == 0) 11759 { 11760 table.querySelector('.dlg_fontName_' + type).style.border = '1px solid red'; 11761 return false; 11762 } 11763 11764 if (type == 'w' && !urlPattern.test(fontUrl)) 11765 { 11766 table.querySelector('.dlg_fontUrl').style.border = '1px solid red'; 11767 return false; 11768 } 11769 11770 return true; 11771 }; 11772 11773 var okBtn = mxUtils.button(mxResources.get('apply'), function() 11774 { 11775 var fontName, fontUrl, type; 11776 11777 if (sysFontRadio.checked) 11778 { 11779 fontName = sysFontInput.value; 11780 type = 's'; 11781 } 11782 else if (googleFontRadio.checked) 11783 { 11784 fontName = googleFontInput.value; 11785 fontUrl = Editor.GOOGLE_FONTS + encodeURIComponent(fontName).replace(/%20/g, '+'); 11786 type = 'g'; 11787 } 11788 else if (webFontRadio.checked) 11789 { 11790 fontName = webFontInput.value; 11791 fontUrl = webFontUrlInput.value; 11792 type = 'w'; 11793 } 11794 11795 if (validateFn(fontName, fontUrl, type)) 11796 { 11797 fn(fontName, fontUrl, type); 11798 editorUi.hideDialog(); 11799 } 11800 }); 11801 okBtn.className = 'geBtn gePrimaryBtn'; 11802 11803 function enterSubmit(e) 11804 { 11805 this.style.border = ''; 11806 11807 if (e.keyCode == 13) 11808 { 11809 okBtn.click(); 11810 } 11811 }; 11812 11813 mxEvent.addListener(sysFontInput, 'keypress', enterSubmit); 11814 mxEvent.addListener(googleFontInput, 'keypress', enterSubmit); 11815 mxEvent.addListener(webFontInput, 'keypress', enterSubmit); 11816 mxEvent.addListener(webFontUrlInput, 'keypress', enterSubmit); 11817 11818 mxEvent.addListener(sysFontInput, 'focus', function() 11819 { 11820 sysFontRadio.setAttribute('checked', 'checked'); 11821 sysFontRadio.checked = true; 11822 }); 11823 11824 mxEvent.addListener(googleFontInput, 'focus', function() 11825 { 11826 googleFontRadio.setAttribute('checked', 'checked'); 11827 googleFontRadio.checked = true; 11828 }); 11829 11830 mxEvent.addListener(webFontInput, 'focus', function() 11831 { 11832 webFontRadio.setAttribute('checked', 'checked'); 11833 webFontRadio.checked = true; 11834 }); 11835 11836 mxEvent.addListener(webFontUrlInput, 'focus', function() 11837 { 11838 webFontRadio.setAttribute('checked', 'checked'); 11839 webFontRadio.checked = true; 11840 }); 11841 11842 td.appendChild(okBtn); 11843 11844 if (!editorUi.editor.cancelFirst) 11845 { 11846 td.appendChild(cancelBtn); 11847 } 11848 11849 row.appendChild(td); 11850 tbody.appendChild(row); 11851 table.appendChild(tbody); 11852 11853 this.container = table; 11854}; 11855 11856/* Aspect Dialog 11857 * @module drawio/aspect-dialog 11858 */ 11859function AspectDialog(editorUi, pageId, layerIds, okFn, cancelFn) 11860{ 11861 this.aspect = {pageId : pageId || (editorUi.pages? editorUi.pages[0].getId() : null), layerIds : layerIds || []}; 11862 var div = document.createElement('div'); 11863 11864 var title = document.createElement('h5'); 11865 title.style.margin = '0 0 10px'; 11866 mxUtils.write(title, mxResources.get('pages')); 11867 div.appendChild(title); 11868 11869 var pagesContainer = document.createElement('div'); 11870 pagesContainer.className = 'geAspectDlgList'; 11871 div.appendChild(pagesContainer); 11872 11873 title = document.createElement('h5'); 11874 title.style.margin = '0 0 10px'; 11875 mxUtils.write(title, mxResources.get('layers')); 11876 div.appendChild(title); 11877 11878 var layersContainer = document.createElement('div'); 11879 layersContainer.className = 'geAspectDlgList'; 11880 div.appendChild(layersContainer); 11881 11882 this.pagesContainer = pagesContainer; 11883 this.layersContainer = layersContainer; 11884 this.ui = editorUi; 11885 11886 var btns = document.createElement('div'); 11887 btns.style.marginTop = '16px'; 11888 btns.style.textAlign = 'center'; 11889 11890 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 11891 { 11892 editorUi.hideDialog(); 11893 11894 if (cancelFn != null) 11895 { 11896 cancelFn(); 11897 } 11898 }); 11899 11900 cancelBtn.className = 'geBtn'; 11901 11902 if (editorUi.editor.cancelFirst) 11903 { 11904 btns.appendChild(cancelBtn); 11905 } 11906 11907 var okBtn = mxUtils.button(mxResources.get('ok'), mxUtils.bind(this, function() 11908 { 11909 editorUi.hideDialog(); 11910 okFn({pageId: this.selectedPage, layerIds: Object.keys(this.selectedLayers)}); 11911 })); 11912 11913 btns.appendChild(okBtn); 11914 okBtn.className = 'geBtn gePrimaryBtn'; 11915 11916 if (!editorUi.editor.cancelFirst) 11917 { 11918 btns.appendChild(cancelBtn); 11919 } 11920 11921 okBtn.setAttribute('disabled', 'disabled'); 11922 this.okBtn = okBtn; 11923 div.appendChild(btns); 11924 this.container = div; 11925}; 11926 11927//Drawing the graph with dialog not visible doesn't get dimensions right. It has to be visible! 11928AspectDialog.prototype.init = function() 11929{ 11930 var xml = this.ui.getFileData(true); //Force pages to update their nodes 11931 11932 if (this.ui.pages) 11933 { 11934 for (var i = 0; i < this.ui.pages.length; i++) 11935 { 11936 var page = this.ui.updatePageRoot(this.ui.pages[i]); 11937 11938 this.createPageItem(page.getId(), page.getName(), page.node); 11939 } 11940 } 11941 else 11942 { 11943 this.createPageItem('1', 'Page-1', mxUtils.parseXml(xml).documentElement); 11944 } 11945}; 11946 11947AspectDialog.prototype.createViewer = function(container, pageNode, layerId, defaultBackground) 11948{ 11949 mxEvent.disableContextMenu(container); 11950 container.style.userSelect = 'none'; 11951 11952 var graph = new Graph(container); 11953 graph.setTooltips(false); 11954 graph.setEnabled(false); 11955 graph.setPanning(false); 11956 graph.minFitScale = null; 11957 graph.maxFitScale = null; 11958 graph.centerZoom = true; 11959 11960 var node = pageNode.nodeName == 'mxGraphModel'? pageNode : Editor.parseDiagramNode(pageNode); //Handles compressed and non-compressed page node 11961 11962 if (node != null) 11963 { 11964 var bg = node.getAttribute('background'); 11965 11966 if (bg == null || bg == '' || bg == mxConstants.NONE) 11967 { 11968 bg = (defaultBackground != null) ? defaultBackground : '#ffffff'; 11969 } 11970 11971 container.style.backgroundColor = bg; 11972 11973 var codec = new mxCodec(node.ownerDocument); 11974 var model = graph.getModel(); 11975 codec.decode(node, model); 11976 11977 var childCount = model.getChildCount(model.root); 11978 11979 var showAll = layerId == null; 11980 11981 // handle layers visibility 11982 for (var i = 0; i < childCount; i++) 11983 { 11984 var child = model.getChildAt(model.root, i); 11985 model.setVisible(child, showAll || layerId == child.id); 11986 } 11987 11988 graph.maxFitScale = 1; 11989 graph.fit(0); 11990 graph.center(); 11991 } 11992 11993 return graph; 11994}; 11995 11996AspectDialog.prototype.createPageItem = function(pageId, pageName, pageNode) 11997{ 11998 var $listItem = document.createElement('div'); 11999 $listItem.className = 'geAspectDlgListItem'; 12000 $listItem.setAttribute('data-page-id', pageId) 12001 $listItem.innerHTML = '<div style="max-width: 100%; max-height: 100%;"></div><div class="geAspectDlgListItemText">' + mxUtils.htmlEntities(pageName) + '</div>'; 12002 12003 this.pagesContainer.appendChild($listItem); 12004 12005 var graph = this.createViewer($listItem.childNodes[0], pageNode); 12006 12007 var onClick = mxUtils.bind(this, function() 12008 { 12009 if (this.selectedItem != null) 12010 { 12011 this.selectedItem.className = 'geAspectDlgListItem'; 12012 } 12013 12014 this.selectedItem = $listItem; 12015 this.selectedPage = pageId; 12016 $listItem.className += ' geAspectDlgListItemSelected'; 12017 this.layersContainer.innerHTML = ''; 12018 this.selectedLayers = {}; 12019 this.okBtn.setAttribute('disabled', 'disabled'); 12020 12021 var graphModel = graph.model; 12022 var layers = graphModel.getChildCells(graphModel.getRoot()); 12023 12024 for (var i = 0; i < layers.length; i++) 12025 { 12026 this.createLayerItem(layers[i], pageId, graph, pageNode); 12027 } 12028 }); 12029 12030 mxEvent.addListener($listItem, 'click', onClick); 12031 12032 if(this.aspect.pageId == pageId) 12033 { 12034 onClick(); 12035 } 12036}; 12037 12038AspectDialog.prototype.createLayerItem = function(layer, pageId, graph, pageNode) 12039{ 12040 var layerName = graph.convertValueToString(layer) || (mxResources.get('background') || 'Background'); 12041 var $listItem = document.createElement('div'); 12042 $listItem.setAttribute('data-layer-id', layer.id); 12043 $listItem.className = 'geAspectDlgListItem'; 12044 $listItem.innerHTML = '<div style="max-width: 100%; max-height: 100%;"></div><div class="geAspectDlgListItemText">' + mxUtils.htmlEntities(layerName) + '</div>'; 12045 this.layersContainer.appendChild($listItem); 12046 12047 this.createViewer($listItem.childNodes[0], pageNode, layer.id); 12048 12049 var onClick = mxUtils.bind(this, function() 12050 { 12051 if ($listItem.className.indexOf('geAspectDlgListItemSelected') >= 0) //Selected 12052 { 12053 $listItem.className = 'geAspectDlgListItem'; 12054 delete this.selectedLayers[layer.id]; 12055 12056 if (Object.keys(this.selectedLayers).length == 0) 12057 { 12058 this.okBtn.setAttribute('disabled', 'disabled'); 12059 } 12060 } 12061 else 12062 { 12063 $listItem.className += ' geAspectDlgListItemSelected'; 12064 this.selectedLayers[layer.id] = true; 12065 this.okBtn.removeAttribute('disabled'); 12066 } 12067 }); 12068 12069 mxEvent.addListener($listItem, 'click', onClick); 12070 12071 if(this.aspect.layerIds.indexOf(layer.id) != -1) 12072 { 12073 onClick(); 12074 } 12075}; 12076 12077/** 12078 * Constructs a new page setup dialog. 12079 */ 12080var FilePropertiesDialog = function(editorUi) 12081{ 12082 var row, td; 12083 var table = document.createElement('table'); 12084 var tbody = document.createElement('tbody'); 12085 table.style.width = '100%'; 12086 table.style.marginTop = '8px'; 12087 12088 var file = editorUi.getCurrentFile(); 12089 var filename = (file != null && file.getTitle() != null) ? 12090 file.getTitle() : editorUi.defaultFilename; 12091 var isPng = /(\.png)$/i.test(filename); 12092 var apply = null; 12093 12094 if (isPng) 12095 { 12096 var scale = 1; 12097 var border = 0; 12098 var node = editorUi.fileNode; 12099 12100 if (node != null) 12101 { 12102 if (node.hasAttribute('scale')) 12103 { 12104 scale = parseFloat(node.getAttribute('scale')); 12105 } 12106 12107 if (node.hasAttribute('border')) 12108 { 12109 border = parseInt(node.getAttribute('border')); 12110 } 12111 } 12112 12113 row = document.createElement('tr'); 12114 td = document.createElement('td'); 12115 td.style.whiteSpace = 'nowrap'; 12116 td.style.fontSize = '10pt'; 12117 td.style.width = '120px'; 12118 mxUtils.write(td, mxResources.get('zoom') + ':'); 12119 12120 row.appendChild(td); 12121 12122 var zoomInput = document.createElement('input'); 12123 zoomInput.setAttribute('value', (scale * 100) + '%'); 12124 zoomInput.style.marginLeft = '4px'; 12125 zoomInput.style.width ='180px'; 12126 12127 td = document.createElement('td'); 12128 td.style.whiteSpace = 'nowrap'; 12129 td.appendChild(zoomInput); 12130 row.appendChild(td); 12131 tbody.appendChild(row); 12132 12133 row = document.createElement('tr'); 12134 td = document.createElement('td'); 12135 td.style.whiteSpace = 'nowrap'; 12136 td.style.fontSize = '10pt'; 12137 td.style.width = '120px'; 12138 mxUtils.write(td, mxResources.get('borderWidth') + ':'); 12139 12140 row.appendChild(td); 12141 12142 var borderInput = document.createElement('input'); 12143 borderInput.setAttribute('value', border); 12144 borderInput.style.marginLeft = '4px'; 12145 borderInput.style.width ='180px'; 12146 12147 td = document.createElement('td'); 12148 td.style.whiteSpace = 'nowrap'; 12149 td.appendChild(borderInput); 12150 row.appendChild(td); 12151 tbody.appendChild(row); 12152 12153 this.init = function() 12154 { 12155 zoomInput.focus(); 12156 12157 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 12158 { 12159 zoomInput.select(); 12160 } 12161 else 12162 { 12163 document.execCommand('selectAll', false, null); 12164 } 12165 }; 12166 12167 apply = function() 12168 { 12169 if (editorUi.fileNode != null) 12170 { 12171 editorUi.fileNode.setAttribute('scale', Math.max(0, parseInt(zoomInput.value) / 100)); 12172 editorUi.fileNode.setAttribute('border', Math.max(0, parseInt(borderInput.value))); 12173 12174 if (file != null) 12175 { 12176 file.fileChanged(); 12177 } 12178 } 12179 12180 editorUi.hideDialog(); 12181 }; 12182 } 12183 else 12184 { 12185 var compressed = (file != null) ? file.isCompressed() : Editor.compressXml; 12186 12187 row = document.createElement('tr'); 12188 td = document.createElement('td'); 12189 td.style.whiteSpace = 'nowrap'; 12190 td.style.fontSize = '10pt'; 12191 td.style.width = '120px'; 12192 mxUtils.write(td, mxResources.get('compressed') + ':'); 12193 12194 row.appendChild(td); 12195 12196 var compressedInput = document.createElement('input'); 12197 compressedInput.setAttribute('type', 'checkbox'); 12198 12199 if (compressed) 12200 { 12201 compressedInput.setAttribute('checked', 'checked'); 12202 compressedInput.defaultChecked = true; 12203 } 12204 12205 td = document.createElement('td'); 12206 td.style.whiteSpace = 'nowrap'; 12207 td.appendChild(compressedInput); 12208 row.appendChild(td); 12209 tbody.appendChild(row); 12210 12211 this.init = function() 12212 { 12213 compressedInput.focus(); 12214 }; 12215 12216 apply = function() 12217 { 12218 if (editorUi.fileNode != null) 12219 { 12220 editorUi.fileNode.setAttribute('compressed', (compressedInput.checked) ? 'true' : 'false'); 12221 12222 if (file != null) 12223 { 12224 file.fileChanged(); 12225 } 12226 } 12227 12228 editorUi.hideDialog(); 12229 }; 12230 } 12231 12232 var genericBtn = mxUtils.button(mxResources.get('apply'), apply); 12233 genericBtn.className = 'geBtn gePrimaryBtn'; 12234 12235 row = document.createElement('tr'); 12236 td = document.createElement('td'); 12237 td.colSpan = 2; 12238 td.style.paddingTop = '20px'; 12239 td.style.whiteSpace = 'nowrap'; 12240 td.setAttribute('align', 'right'); 12241 12242 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 12243 { 12244 editorUi.hideDialog(); 12245 }); 12246 cancelBtn.className = 'geBtn'; 12247 12248 if (editorUi.editor.cancelFirst) 12249 { 12250 td.appendChild(cancelBtn); 12251 } 12252 12253 td.appendChild(genericBtn); 12254 12255 if (!editorUi.editor.cancelFirst) 12256 { 12257 td.appendChild(cancelBtn); 12258 } 12259 12260 row.appendChild(td); 12261 tbody.appendChild(row); 12262 table.appendChild(tbody); 12263 12264 this.container = table; 12265}; 12266