 core/modules/ckeditor/js/ckeditor.js               |   57 +++++++++++++++++++-
 .../ckeditor/Plugin/editor/editor/CKEditor.php     |    3 +-
 2 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js
index b8318be..856c53e 100644
--- a/core/modules/ckeditor/js/ckeditor.js
+++ b/core/modules/ckeditor/js/ckeditor.js
@@ -1,4 +1,4 @@
-(function (Drupal, CKEDITOR) {
+(function (Drupal, CKEDITOR, $) {
 
 "use strict";
 
@@ -15,6 +15,7 @@ Drupal.editors.ckeditor = {
       }
       delete format.editorSettings.drupalExternalPlugins;
     }
+    this._loadExternalPlugins(format);
     return !!CKEDITOR.replace(element, format.editorSettings);
   },
 
@@ -29,8 +30,60 @@ Drupal.editors.ckeditor = {
       }
     }
     return !!editor;
+  },
+
+  onChange: function (element, callback) {
+    var editor = CKEDITOR.dom.element.get(element).getEditor();
+    if (editor) {
+      var changed = function () {
+        callback(editor.getData());
+      };
+      // @todo Make this more elegant once http://dev.ckeditor.com/ticket/9794
+      // is fixed.
+      editor.on('key', changed);
+      editor.on('paste', changed);
+      editor.on('afterCommandExec', changed);
+    }
+    return !!editor;
+  },
+
+  attachInlineEditor: function (element, format, mainToolbarId, floatedToolbarId) {
+    this._loadExternalPlugins(format);
+
+    var settings = $.extend(true, {}, format.editorSettings);
+
+    // If a toolbar is already provided for "true WYSIWYG" (in-place editing),
+    // then use that toolbar instead: override the default settings to render
+    // CKEditor UI's top toolbar into mainToolbar, and don't render the bottom
+    // toolbar at all. (CKEditor doesn't need a floated toolbar.)
+    if (mainToolbarId) {
+      var settingsOverride = {
+        extraPlugins: 'sharedspace',
+        removePlugins: 'floatingspace,elementspath',
+        sharedSpaces: {
+          top: mainToolbarId
+        }
+      };
+      settings.extraPlugins += ',' + settingsOverride.extraPlugins;
+      settings.removePlugins += ',' + settingsOverride.removePlugins;
+      settings.sharedSpaces = settingsOverride.sharedSpaces;
+    }
+
+    return !!CKEDITOR.inline(element, settings);
+  },
+
+  _loadExternalPlugins: function(format) {
+    // Register additional Drupal plugins as necessary.
+    if (format.editorSettings.externalPlugins) {
+      for (var pluginName in format.editorSettings.externalPlugins) {
+        if (format.editorSettings.externalPlugins.hasOwnProperty(pluginName)) {
+          CKEDITOR.plugins.addExternal(pluginName, drupalSettings.basePath + format.editorSettings.externalPlugins[pluginName]['path'] + '/', format.editorSettings.externalPlugins[pluginName]['file']);
+        }
+      }
+      delete format.editorSettings.externalPlugins;
+    }
   }
 
 };
 
-})(Drupal, CKEDITOR);
+})(Drupal, CKEDITOR, jQuery);
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php
index df34b05..de51f8c 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php
@@ -18,7 +18,8 @@
  * @Plugin(
  *   id = "ckeditor",
  *   label = @Translation("CKEditor"),
- *   module = "ckeditor"
+ *   module = "ckeditor",
+ *   supports_inline_editing = TRUE
  * )
  */
 class CKEditor extends EditorBase {
