8
0

snippet.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /* globals window, document, setTimeout */
  6. // Show clipboard input notification when user tries to paste a content from MS Word or Google Docs.
  7. setTimeout( () => {
  8. // Don't show the warning notification in "Paste from Office" and "Paste from Google Docs" demos.
  9. if ( window.preventPasteFromOfficeNotification ) {
  10. return;
  11. }
  12. const editables = document.querySelectorAll( '.ck-content' );
  13. const googleDocsMatch = /id=("|')docs-internal-guid-[-0-9a-f]+("|')/i;
  14. const msWordMatch1 = /<meta\s*name="?generator"?\s*content="?microsoft\s*word\s*\d+"?\/?>/i;
  15. const msWordMatch2 = /xmlns:o="urn:schemas-microsoft-com/i;
  16. // A global variable indication if clipboard notification is visible.
  17. // We use the variable for displaying only one instance of the clipboard notification.
  18. window.isClipboardInputNotificationVisible = false;
  19. editables.forEach( editable => {
  20. const editor = editable.ckeditorInstance;
  21. if ( !editor ) {
  22. return;
  23. }
  24. editor.plugins.get( 'Clipboard' ).listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {
  25. const htmlString = data.dataTransfer.getData( 'text/html' );
  26. const match = msWordMatch1.test( htmlString ) ||
  27. msWordMatch2.test( htmlString ) ||
  28. googleDocsMatch.test( htmlString );
  29. if ( match && !window.isClipboardInputNotificationVisible ) {
  30. createClipboardInputNotification();
  31. }
  32. } );
  33. } );
  34. }, 3000 );
  35. // The notification should contain the links to the demos where user can test rich formatting from.
  36. function createClipboardInputNotification() {
  37. const title = 'Hello!';
  38. const message = `
  39. <p>We detected that you tried to paste content from <strong>Microsoft Word</strong> or <strong>Google Docs</strong>.</p>
  40. <p>Please bear in mind that the editor demo to which you try to paste does not have all the features enabled.
  41. Due to that, unsupported formatting is being stripped.</p>
  42. <p>Check out the <a href="/docs/ckeditor5/latest/features/pasting/paste-from-word.html">Paste from Word</a> or
  43. <a href="/docs/ckeditor5/latest/pasting/paste-from-google-docs.html">Paste from Google Docs</a>
  44. demos for the best experience.</p>`;
  45. window.createNotification( title, message, () => {
  46. window.isClipboardInputNotificationVisible = false;
  47. } );
  48. window.isClipboardInputNotificationVisible = true;
  49. }
  50. /**
  51. * Creates a notification and appends it to the `.main__content` element.
  52. *
  53. * @param {String} title A title of the notification.
  54. * @param {String} message A message to display in the notification.
  55. * @param {Function} [onClose] A callback function that executes on closing the notification.
  56. *
  57. * @returns {Object} A notification element.
  58. */
  59. window.createNotification = function( title, message, onClose ) {
  60. const notificationTemplate = `
  61. <h3 class="main__notification-title">${ title }</h3>
  62. <div class="main__notification-body">
  63. ${ message }
  64. </div>
  65. `;
  66. const notification = document.createElement( 'div' );
  67. const close = document.createElement( 'button' );
  68. close.classList.add( 'main__notification-close' );
  69. close.innerText = '✕';
  70. close.setAttribute( 'aria-label', 'Close the notification' );
  71. notification.classList.add( 'main__notification', 'notice' );
  72. notification.innerHTML = notificationTemplate;
  73. // ATM we support only top-right position.
  74. notification.style.top = window.getViewportTopOffsetConfig() + 10 + 'px';
  75. notification.style.right = '10px';
  76. notification.appendChild( close );
  77. const activeNotifications = document.querySelectorAll( '.main__notification' );
  78. // Translate the position of multiple notifications (just in case).
  79. if ( activeNotifications.length > 0 ) {
  80. const moveOffset = activeNotifications.length * 10;
  81. notification.style.top = parseInt( notification.style.top ) + moveOffset + 'px';
  82. notification.style.right = parseInt( notification.style.right ) + moveOffset + 'px';
  83. }
  84. // Append notification to the `.main__content` element.
  85. const main = document.querySelector( '.main__content' );
  86. main.appendChild( notification );
  87. close.addEventListener( 'click', () => {
  88. main.removeChild( notification );
  89. if ( onClose && typeof onClose == 'function' ) {
  90. onClose();
  91. }
  92. } );
  93. return notification;
  94. };
  95. /**
  96. * Returns the `config.toolbar.viewportTopOffset` config value for editors using floating toolbars that
  97. * stick to the top of the viewport to remain visible to the user.
  98. *
  99. * The value is determined in styles by the `--ck-snippet-viewport-top-offset` custom property
  100. * and may differ e.g. according to the used media queries.
  101. *
  102. * @returns {Number} The value of the offset.
  103. */
  104. window.getViewportTopOffsetConfig = function() {
  105. const documentElement = document.documentElement;
  106. return parseInt( window.getComputedStyle( documentElement ).getPropertyValue( '--ck-snippet-viewport-top-offset' ) );
  107. };