diff --git a/customize.dist/ckeditor-config.js b/customize.dist/ckeditor-config.js
index a39616e6e..ac7989294 100644
--- a/customize.dist/ckeditor-config.js
+++ b/customize.dist/ckeditor-config.js
@@ -61,7 +61,6 @@ CKEDITOR.editorConfig = function( config ) {
// every part of ckeditor will get in the browser cache.
var fix = function (x) {
if (x.map) { return x.map(fix); }
- console.log('> ' + x);
return (/\/bower_components\/.*\.css$/.test(x)) ? (x + '?ver=' + CKEDITOR.timestamp) : x;
};
CKEDITOR.tools._buildStyleHtml = CKEDITOR.tools.buildStyleHtml;
diff --git a/www/common/sframe-chainpad-netflux-inner.js b/www/common/sframe-chainpad-netflux-inner.js
index 04659fe17..a1359f522 100644
--- a/www/common/sframe-chainpad-netflux-inner.js
+++ b/www/common/sframe-chainpad-netflux-inner.js
@@ -67,7 +67,9 @@ define([
logLevel: logLevel
});
chainpad.onMessage(function(message, cb) {
- sframeChan.query('Q_RT_MESSAGE', message, cb);
+ sframeChan.query('Q_RT_MESSAGE', message, function (ret) {
+ if (ret === 'OK') { cb(); }
+ });
});
chainpad.onPatch(function () {
onRemote({ realtime: chainpad });
diff --git a/www/common/sframe-chainpad-netflux-outer.js b/www/common/sframe-chainpad-netflux-outer.js
index f1186d79d..ff6e522c8 100644
--- a/www/common/sframe-chainpad-netflux-outer.js
+++ b/www/common/sframe-chainpad-netflux-outer.js
@@ -153,12 +153,16 @@ define([], function () {
if (message) {
// Do not remove wcObject, it allows us to use a new 'wc' without changing the handler if we
// want to keep the same chainpad (realtime) object
- wcObject.wc.bcast(message).then(function() {
- cb('OK');
- }, function(err) {
- // The message has not been sent, display the error.
- console.error(err);
- });
+ try {
+ wcObject.wc.bcast(message).then(function() {
+ cb('OK');
+ }, function(err) {
+ // The message has not been sent, display the error.
+ console.error(err);
+ });
+ } catch (e) {
+ cb('ERROR');
+ }
}
};
queue.forEach(function (arr) { messageFromInner(arr[0], arr[1]); });
diff --git a/www/pad2/ckeditor-inner.html b/www/pad2/ckeditor-inner.html
new file mode 100644
index 000000000..511bd5f40
--- /dev/null
+++ b/www/pad2/ckeditor-inner.html
@@ -0,0 +1,3 @@
+
+
Rich Text Editor, editor1
diff --git a/www/pad2/main.js b/www/pad2/main.js
index 3027bab63..497082f1f 100644
--- a/www/pad2/main.js
+++ b/www/pad2/main.js
@@ -117,13 +117,6 @@ define([
'AUDIO'
];
- var openLink = function (e) {
- var el = e.currentTarget;
- if (!el || el.nodeName !== 'A') { return; }
- var href = el.getAttribute('href');
- if (href) { window.open(href, '_blank'); }
- };
-
var getHTML = function (inner) {
return ('\n' + '\n' + inner.innerHTML);
};
@@ -303,12 +296,21 @@ define([
el.setAttribute('class', 'non-realtime');
});
- var documentBody = $html.find('iframe')[0].contentWindow.document.body;
+ var ifrWindow = $html.find('iframe')[0].contentWindow;
+
+ var documentBody = ifrWindow.document.body;
var inner = window.inner = documentBody;
var cursor = module.cursor = Cursor(inner);
+ var openLink = function (e) {
+ var el = e.currentTarget;
+ if (!el || el.nodeName !== 'A') { return; }
+ var href = el.getAttribute('href');
+ if (href) { ifrWindow.open(href, '_blank'); }
+ };
+
var setEditable = module.setEditable = function (bool) {
if (bool) {
$(inner).css({
@@ -733,7 +735,10 @@ define([
var common;
nThen(function (waitFor) {
- ckEditorAvailable(waitFor(function (ck) { Ckeditor = ck; }));
+ ckEditorAvailable(waitFor(function (ck) {
+ Ckeditor = ck;
+ require(['/pad2/wysiwygarea-plugin.js'], waitFor());
+ }));
$(waitFor(function () {
Cryptpad.addLoadingScreen();
}));
diff --git a/www/pad2/wysiwygarea-plugin.js b/www/pad2/wysiwygarea-plugin.js
new file mode 100644
index 000000000..c7f827000
--- /dev/null
+++ b/www/pad2/wysiwygarea-plugin.js
@@ -0,0 +1,735 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+/**
+ * @fileOverview The WYSIWYG Area plugin. It registers the "wysiwyg" editing
+ * mode, which handles the main editing area space.
+ */
+
+define(['/api/config'], function (ApiConfig) {
+ var framedWysiwyg;
+ var iframe;
+
+ CKEDITOR.plugins.registered.wysiwygarea.init = function( editor ) {
+ if ( editor.config.fullPage ) {
+ editor.addFeature( {
+ allowedContent: 'html head title; style [media,type]; body (*)[id]; meta link [*]',
+ requiredContent: 'body'
+ } );
+ }
+
+ editor.addMode( 'wysiwyg', function( callback ) {
+ var src = 'document.open();' +
+ // In IE, the document domain must be set any time we call document.open().
+ ( CKEDITOR.env.ie ? '(' + CKEDITOR.tools.fixDomain + ')();' : '' ) +
+ 'document.close();';
+
+ // With IE, the custom domain has to be taken care at first,
+ // for other browers, the 'src' attribute should be left empty to
+ // trigger iframe's 'load' event.
+ // Microsoft Edge throws "Permission Denied" if treated like an IE (http://dev.ckeditor.com/ticket/13441).
+ if ( CKEDITOR.env.air ) {
+ src = 'javascript:void(0)'; // jshint ignore:line
+ } else if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
+ src = 'javascript:void(function(){' + encodeURIComponent( src ) + '}())'; // jshint ignore:line
+ } else {
+ src = '';
+ }
+
+ // CryptPad
+ src = '/pad/ckeditor-inner.html?' + ApiConfig.requireConf.urlArgs;
+
+ iframe = CKEDITOR.dom.element.createFromHtml( '' );
+ iframe.setStyles( { width: '100%', height: '100%' } );
+ iframe.addClass( 'cke_wysiwyg_frame' ).addClass( 'cke_reset' );
+
+ // CryptPad
+ // this is impossible because ckeditor uses some (non-inline) script inside of the iframe...
+ //iframe.setAttribute('sandbox', 'allow-same-origin');
+
+ var contentSpace = editor.ui.space( 'contents' );
+ contentSpace.append( iframe );
+
+
+ // Asynchronous iframe loading is only required in IE>8 and Gecko (other reasons probably).
+ // Do not use it on WebKit as it'll break the browser-back navigation.
+ var useOnloadEvent = ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) || CKEDITOR.env.gecko;
+ if ( useOnloadEvent )
+ iframe.on( 'load', onLoad );
+
+ var frameLabel = editor.title,
+ helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label;
+
+ if ( frameLabel ) {
+ if ( CKEDITOR.env.ie && helpLabel )
+ frameLabel += ', ' + helpLabel;
+
+ iframe.setAttribute( 'title', frameLabel );
+ }
+
+ if ( helpLabel ) {
+ var labelId = CKEDITOR.tools.getNextId(),
+ desc = CKEDITOR.dom.element.createFromHtml( '' + helpLabel + '' );
+
+ contentSpace.append( desc, 1 );
+ iframe.setAttribute( 'aria-describedby', labelId );
+ }
+
+ // Remove the ARIA description.
+ editor.on( 'beforeModeUnload', function( evt ) {
+ evt.removeListener();
+ if ( desc )
+ desc.remove();
+ } );
+
+ iframe.setAttributes( {
+ tabIndex: editor.tabIndex,
+ allowTransparency: 'true'
+ } );
+
+ // Execute onLoad manually for all non IE||Gecko browsers.
+ !useOnloadEvent && onLoad();
+
+ editor.fire( 'ariaWidget', iframe );
+
+ function onLoad( evt ) {
+ evt && evt.removeListener();
+ var fw = new framedWysiwyg( editor, iframe.$.contentWindow.document.body );
+ editor.editable( fw );
+ editor.setData( editor.getData( 1 ), callback );
+ }
+ } );
+ };
+
+ /**
+ * Adds the path to a stylesheet file to the exisiting {@link CKEDITOR.config#contentsCss} value.
+ *
+ * **Note:** This method is available only with the `wysiwygarea` plugin and only affects
+ * classic editors based on it (so it does not affect inline editors).
+ *
+ * editor.addContentsCss( 'assets/contents.css' );
+ *
+ * @since 4.4
+ * @param {String} cssPath The path to the stylesheet file which should be added.
+ * @member CKEDITOR.editor
+ */
+ CKEDITOR.editor.prototype.addContentsCss = function( cssPath ) {
+ var cfg = this.config,
+ curContentsCss = cfg.contentsCss;
+
+ // Convert current value into array.
+ if ( !CKEDITOR.tools.isArray( curContentsCss ) )
+ cfg.contentsCss = curContentsCss ? [ curContentsCss ] : [];
+
+ cfg.contentsCss.push( cssPath );
+ };
+
+ function onDomReady( win ) {
+ var editor = this.editor,
+ doc = win.document,
+ body = doc.body;
+
+ // Remove helper scripts from the DOM.
+ var script = doc.getElementById( 'cke_actscrpt' );
+ script && script.parentNode.removeChild( script );
+ script = doc.getElementById( 'cke_shimscrpt' );
+ script && script.parentNode.removeChild( script );
+ script = doc.getElementById( 'cke_basetagscrpt' );
+ script && script.parentNode.removeChild( script );
+
+ body.contentEditable = true;
+
+ if ( CKEDITOR.env.ie ) {
+ // Don't display the focus border.
+ body.hideFocus = true;
+
+ // Disable and re-enable the body to avoid IE from
+ // taking the editing focus at startup. (http://dev.ckeditor.com/ticket/141 / http://dev.ckeditor.com/ticket/523)
+ body.disabled = true;
+ body.removeAttribute( 'disabled' );
+ }
+
+ delete this._.isLoadingData;
+
+ // Play the magic to alter element reference to the reloaded one.
+ this.$ = body;
+
+ doc = new CKEDITOR.dom.document( doc );
+
+ this.setup();
+ this.fixInitialSelection();
+
+ var editable = this;
+
+ // Without it IE8 has problem with removing selection in nested editable. (http://dev.ckeditor.com/ticket/13785)
+ if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {
+ doc.getDocumentElement().addClass( doc.$.compatMode );
+ }
+
+ // Prevent IE/Edge from leaving a new paragraph/div after deleting all contents in body. (http://dev.ckeditor.com/ticket/6966, http://dev.ckeditor.com/ticket/13142)
+ if ( CKEDITOR.env.ie && !CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_P ) {
+ removeSuperfluousElement( 'p' );
+ } else if ( CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_DIV ) {
+ removeSuperfluousElement( 'div' );
+ }
+
+ // Fix problem with cursor not appearing in Webkit and IE11+ when clicking below the body (http://dev.ckeditor.com/ticket/10945, http://dev.ckeditor.com/ticket/10906).
+ // Fix for older IEs (8-10 and QM) is placed inside selection.js.
+ if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version > 10 ) ) {
+ doc.getDocumentElement().on( 'mousedown', function( evt ) {
+ if ( evt.data.getTarget().is( 'html' ) ) {
+ // IE needs this timeout. Webkit does not, but it does not cause problems too.
+ setTimeout( function() {
+ editor.editable().focus();
+ } );
+ }
+ } );
+ }
+
+ // Config props: disableObjectResizing and disableNativeTableHandles handler.
+ objectResizeDisabler( editor );
+
+ // Enable dragging of position:absolute elements in IE.
+ try {
+ editor.document.$.execCommand( '2D-position', false, true );
+ } catch ( e ) {}
+
+ if ( CKEDITOR.env.gecko || CKEDITOR.env.ie && editor.document.$.compatMode == 'CSS1Compat' ) {
+ this.attachListener( this, 'keydown', function( evt ) {
+ var keyCode = evt.data.getKeystroke();
+
+ // PageUp OR PageDown
+ if ( keyCode == 33 || keyCode == 34 ) {
+ // PageUp/PageDown scrolling is broken in document
+ // with standard doctype, manually fix it. (http://dev.ckeditor.com/ticket/4736)
+ if ( CKEDITOR.env.ie ) {
+ setTimeout( function() {
+ editor.getSelection().scrollIntoView();
+ }, 0 );
+ }
+ // Page up/down cause editor selection to leak
+ // outside of editable thus we try to intercept
+ // the behavior, while it affects only happen
+ // when editor contents are not overflowed. (http://dev.ckeditor.com/ticket/7955)
+ else if ( editor.window.$.innerHeight > this.$.offsetHeight ) {
+ var range = editor.createRange();
+ range[ keyCode == 33 ? 'moveToElementEditStart' : 'moveToElementEditEnd' ]( this );
+ range.select();
+ evt.data.preventDefault();
+ }
+ }
+ } );
+ }
+
+ if ( CKEDITOR.env.ie ) {
+ // [IE] Iframe will still keep the selection when blurred, if
+ // focus is moved onto a non-editing host, e.g. link or button, but
+ // it becomes a problem for the object type selection, since the resizer
+ // handler attached on it will mark other part of the UI, especially
+ // for the dialog. (http://dev.ckeditor.com/ticket/8157)
+ // [IE<8 & Opera] Even worse For old IEs, the cursor will not vanish even if
+ // the selection has been moved to another text input in some cases. (http://dev.ckeditor.com/ticket/4716)
+ //
+ // Now the range restore is disabled, so we simply force IE to clean
+ // up the selection before blur.
+ this.attachListener( doc, 'blur', function() {
+ // Error proof when the editor is not visible. (http://dev.ckeditor.com/ticket/6375)
+ try {
+ doc.$.selection.empty();
+ } catch ( er ) {}
+ } );
+ }
+
+ if ( CKEDITOR.env.iOS ) {
+ // [iOS] If touch is bound to any parent of the iframe blur happens on any touch
+ // event and body becomes the focused element (http://dev.ckeditor.com/ticket/10714).
+ this.attachListener( doc, 'touchend', function() {
+ win.focus();
+ } );
+ }
+
+ var title = editor.document.getElementsByTag( 'title' ).getItem( 0 );
+ // document.title is malfunctioning on Chrome, so get value from the element (http://dev.ckeditor.com/ticket/12402).
+ title.data( 'cke-title', title.getText() );
+
+ // [IE] JAWS will not recognize the aria label we used on the iframe
+ // unless the frame window title string is used as the voice label,
+ // backup the original one and restore it on output.
+ if ( CKEDITOR.env.ie )
+ editor.document.$.title = this._.docTitle;
+
+ CKEDITOR.tools.setTimeout( function() {
+ // Editable is ready after first setData.
+ if ( this.status == 'unloaded' )
+ this.status = 'ready';
+
+ editor.fire( 'contentDom' );
+
+ if ( this._.isPendingFocus ) {
+ editor.focus();
+ this._.isPendingFocus = false;
+ }
+
+ setTimeout( function() {
+ editor.fire( 'dataReady' );
+ }, 0 );
+ }, 0, this );
+
+ function removeSuperfluousElement( tagName ) {
+ var lockRetain = false;
+
+ // Superfluous elements appear after keydown
+ // and before keyup, so the procedure is as follows:
+ // 1. On first keydown mark all elements with
+ // a specified tag name as non-superfluous.
+ editable.attachListener( editable, 'keydown', function() {
+ var body = doc.getBody(),
+ retained = body.getElementsByTag( tagName );
+
+ if ( !lockRetain ) {
+ for ( var i = 0; i < retained.count(); i++ ) {
+ retained.getItem( i ).setCustomData( 'retain', true );
+ }
+ lockRetain = true;
+ }
+ }, null, null, 1 );
+
+ // 2. On keyup remove all elements that were not marked
+ // as non-superfluous (which means they must have had appeared in the meantime).
+ // Also we should preserve all temporary elements inserted by editor – otherwise we'd likely
+ // leak fake selection's content into editable due to removing hidden selection container (http://dev.ckeditor.com/ticket/14831).
+ editable.attachListener( editable, 'keyup', function() {
+ var elements = doc.getElementsByTag( tagName );
+ if ( lockRetain ) {
+ if ( elements.count() == 1 && !elements.getItem( 0 ).getCustomData( 'retain' ) &&
+ !elements.getItem( 0 ).hasAttribute( 'data-cke-temp' ) ) {
+ elements.getItem( 0 ).remove( 1 );
+ }
+ lockRetain = false;
+ }
+ } );
+ }
+ }
+
+ framedWysiwyg = CKEDITOR.tools.createClass( {
+ $: function() {
+ this.base.apply( this, arguments );
+
+ this._.frameLoadedHandler = CKEDITOR.tools.addFunction( function( win ) {
+ // Avoid opening design mode in a frame window thread,
+ // which will cause host page scrolling.(http://dev.ckeditor.com/ticket/4397)
+ CKEDITOR.tools.setTimeout( onDomReady, 0, this, win );
+ }, this );
+
+ this._.docTitle = this.getWindow().getFrame().getAttribute( 'title' );
+ },
+
+ base: CKEDITOR.editable,
+
+ proto: {
+ setData: function( data, isSnapshot ) {
+ var editor = this.editor;
+
+ if ( isSnapshot ) {
+ this.setHtml( data );
+ this.fixInitialSelection();
+
+ // Fire dataReady for the consistency with inline editors
+ // and because it makes sense. (http://dev.ckeditor.com/ticket/10370)
+ editor.fire( 'dataReady' );
+ }
+ else {
+ this._.isLoadingData = true;
+ editor._.dataStore = { id: 1 };
+
+ var config = editor.config,
+ fullPage = config.fullPage,
+ docType = config.docType;
+
+ // Build the additional stuff to be included into .
+ var headExtra = CKEDITOR.tools.buildStyleHtml( iframeCssFixes() ).replace( /