paste.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or http://ckeditor.com/license
  4. */
  5. CKEDITOR.dialog.add( 'paste', function( editor ) {
  6. var lang = editor.lang.clipboard;
  7. function onPasteFrameLoad( win ) {
  8. var doc = new CKEDITOR.dom.document( win.document ),
  9. body = doc.getBody(),
  10. script = doc.getById( 'cke_actscrpt' );
  11. script && script.remove();
  12. body.setAttribute( 'contenteditable', true );
  13. // IE before version 8 will leave cursor blinking inside the document after
  14. // editor blurred unless we clean up the selection. (#4716)
  15. if ( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) {
  16. doc.getWindow().on( 'blur', function() {
  17. doc.$.selection.empty();
  18. } );
  19. }
  20. doc.on( 'keydown', function( e ) {
  21. var domEvent = e.data,
  22. key = domEvent.getKeystroke(),
  23. processed;
  24. switch ( key ) {
  25. case 27:
  26. this.hide();
  27. processed = 1;
  28. break;
  29. case 9:
  30. case CKEDITOR.SHIFT + 9:
  31. this.changeFocus( 1 );
  32. processed = 1;
  33. }
  34. processed && domEvent.preventDefault();
  35. }, this );
  36. editor.fire( 'ariaWidget', new CKEDITOR.dom.element( win.frameElement ) );
  37. // Handle pending focus.
  38. if ( doc.getWindow().getFrame().removeCustomData( 'pendingFocus' ) )
  39. body.focus();
  40. }
  41. // If pasteDialogCommit wasn't canceled by e.g. editor.getClipboardData
  42. // then fire paste event.
  43. // Do not use editor#paste, because it would start from beforePaste event.
  44. editor.on( 'pasteDialogCommit', function( evt ) {
  45. if ( evt.data )
  46. editor.fire( 'paste', {
  47. type: 'auto',
  48. dataValue: evt.data,
  49. method: 'paste',
  50. dataTransfer: CKEDITOR.plugins.clipboard.initPasteDataTransfer()
  51. } );
  52. }, null, null, 1000 );
  53. return {
  54. title: lang.title,
  55. minWidth: CKEDITOR.env.ie && CKEDITOR.env.quirks ? 370 : 350,
  56. minHeight: CKEDITOR.env.quirks ? 250 : 245,
  57. onShow: function() {
  58. // FIREFOX BUG: Force the browser to render the dialog to make the to-be-
  59. // inserted iframe editable. (#3366)
  60. this.parts.dialog.$.offsetHeight;
  61. this.setupContent();
  62. // Set dialog title to the custom value (set e.g. in editor.openDialog callback) and reset this value.
  63. // If custom title not set, use default one.
  64. this.parts.title.setHtml( this.customTitle || lang.title );
  65. this.customTitle = null;
  66. },
  67. onLoad: function() {
  68. if ( ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) && editor.lang.dir == 'rtl' )
  69. this.parts.contents.setStyle( 'overflow', 'hidden' );
  70. },
  71. onOk: function() {
  72. this.commitContent();
  73. },
  74. contents: [ {
  75. id: 'general',
  76. label: editor.lang.common.generalTab,
  77. elements: [
  78. {
  79. type: 'html',
  80. id: 'securityMsg',
  81. html: '<div style="white-space:normal;width:340px">' + lang.securityMsg + '</div>'
  82. },
  83. {
  84. type: 'html',
  85. id: 'pasteMsg',
  86. html: '<div style="white-space:normal;width:340px">' + lang.pasteMsg + '</div>'
  87. },
  88. {
  89. type: 'html',
  90. id: 'editing_area',
  91. style: 'width:100%;height:100%',
  92. html: '',
  93. focus: function() {
  94. var iframe = this.getInputElement(),
  95. doc = iframe.getFrameDocument(),
  96. body = doc.getBody();
  97. // Frame content may not loaded at the moment.
  98. if ( !body || body.isReadOnly() )
  99. iframe.setCustomData( 'pendingFocus', 1 );
  100. else
  101. body.focus();
  102. },
  103. setup: function() {
  104. var dialog = this.getDialog();
  105. var htmlToLoad = '<html dir="' + editor.config.contentsLangDirection + '"' +
  106. ' lang="' + ( editor.config.contentsLanguage || editor.langCode ) + '">' +
  107. '<head><style>body{margin:3px;height:95%;word-break:break-all;}</style></head><body>' +
  108. '<script id="cke_actscrpt" type="text/javascript">' +
  109. 'window.parent.CKEDITOR.tools.callFunction(' + CKEDITOR.tools.addFunction( onPasteFrameLoad, dialog ) + ',this);' +
  110. '</script></body>' +
  111. '</html>';
  112. var src =
  113. CKEDITOR.env.air ?
  114. 'javascript:void(0)' : // jshint ignore:line
  115. ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ?
  116. 'javascript:void((function(){' + encodeURIComponent( // jshint ignore:line
  117. 'document.open();' +
  118. '(' + CKEDITOR.tools.fixDomain + ')();' +
  119. 'document.close();'
  120. ) + '})())"'
  121. : '';
  122. var iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' +
  123. ' class="cke_pasteframe"' +
  124. ' frameborder="0" ' +
  125. ' allowTransparency="true"' +
  126. ' src="' + src + '"' +
  127. ' aria-label="' + lang.pasteArea + '"' +
  128. ' aria-describedby="' + dialog.getContentElement( 'general', 'pasteMsg' ).domId + '"' +
  129. '></iframe>' );
  130. iframe.on( 'load', function( e ) {
  131. e.removeListener();
  132. var doc = iframe.getFrameDocument();
  133. doc.write( htmlToLoad );
  134. editor.focusManager.add( doc.getBody() );
  135. if ( CKEDITOR.env.air )
  136. onPasteFrameLoad.call( this, doc.getWindow().$ );
  137. }, dialog );
  138. iframe.setCustomData( 'dialog', dialog );
  139. var container = this.getElement();
  140. container.setHtml( '' );
  141. container.append( iframe );
  142. // IE need a redirect on focus to make
  143. // the cursor blinking inside iframe. (#5461)
  144. if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
  145. var focusGrabber = CKEDITOR.dom.element.createFromHtml( '<span tabindex="-1" style="position:absolute" role="presentation"></span>' );
  146. focusGrabber.on( 'focus', function() {
  147. // Since fixDomain is called in src attribute,
  148. // IE needs some slight delay to correctly move focus.
  149. setTimeout( function() {
  150. iframe.$.contentWindow.focus();
  151. } );
  152. } );
  153. container.append( focusGrabber );
  154. // Override focus handler on field.
  155. this.focus = function() {
  156. focusGrabber.focus();
  157. this.fire( 'focus' );
  158. };
  159. }
  160. this.getInputElement = function() {
  161. return iframe;
  162. };
  163. // Force container to scale in IE.
  164. if ( CKEDITOR.env.ie ) {
  165. container.setStyle( 'display', 'block' );
  166. container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
  167. }
  168. },
  169. commit: function() {
  170. var editor = this.getDialog().getParentEditor(),
  171. body = this.getInputElement().getFrameDocument().getBody(),
  172. bogus = body.getBogus(),
  173. html;
  174. bogus && bogus.remove();
  175. // Saving the contents so changes until paste is complete will not take place (#7500)
  176. html = body.getHtml();
  177. // Opera needs some time to think about what has happened and what it should do now.
  178. setTimeout( function() {
  179. editor.fire( 'pasteDialogCommit', html );
  180. }, 0 );
  181. }
  182. }
  183. ]
  184. } ]
  185. };
  186. } );
  187. /**
  188. * Internal event to pass paste dialog's data to the listeners.
  189. *
  190. * @private
  191. * @event pasteDialogCommit
  192. * @member CKEDITOR.editor
  193. * @param {CKEDITOR.editor} editor This editor instance.
  194. */