diff --git a/ckeditor.api.php b/ckeditor.api.php
new file mode 100644
index 0000000..f434b54
--- /dev/null
+++ b/ckeditor.api.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ * Documentation for CKEditor module APIs.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Provides a list of CKEditor plugins.
+ *
+ * Each plugin for CKEditor must provide an array of properties containing
+ * information about the plugin. At minimum, plugins must provide a path and
+ * file location so that CKEditor may add the plugin. Available properties for
+ * each plugin include:
+ *
+ * - location: Required for all external plugins. String path to the plugin
+ *   directory relative to the Drupal installation root. Do not include a
+ *   trailing slash.
+ * - file: Required for all external plugins. String file name of the plugin in
+ *   the "location" directory.
+ * - internal: Boolean value indicating if the plugin is part of the compressed
+ *   CKEditor library package and already loaded on all instances. If TRUE,
+ *   the "location" and "file" properties are not needed.
+ * - css: An array of CSS files that should be added by CKEditor. These files
+ *   are used only when CKEditor is using an iframe wrapper around its content.
+ *   If a plugin needs to include CSS for inline and iframe versions, it should
+ *   add its CSS via CKEditor's JavaScript CKEDITOR.addCss() method.
+ * - enabled callback: String containing a function name that can determine if
+ *   this plugin should be enabled based on the current editor configuration.
+ *   See the hook_ckeditor_PLUGIN_plugin_check() function for an example.
+ * - buttons: An array of buttons that are provided by this plugin. Each button
+ *   should by keyed by its CKEditor button name, and should contain an array
+ *   of button properties, including:
+ *   - label: A human-readable, translated button name.
+ *   - image: An image for the button to be used in the toolbar.
+ *   - image_rtl: If the image needs to have a right-to-left version, specify
+ *     an alternative file that will be used in RTL editors.
+ *   - image_alternative: If this button does not render as an image, specify
+ *     an HTML string representing the contents of this button. This alternative
+ *     will only be used in the administrative section for assembling the
+ *     toolbar.
+ *   - attributes: An array of HTML attributes which should be added to this
+ *     button when rendering the button in the administrative section for
+ *     assembling the toolbar.
+ *   - multiple: Boolean value indicating if this button may be added multiple
+ *     times to the toolbar. This typically is only applicable for dividers and
+ *     group indicators.
+ *   - required_tags: If this button requires certain HTML tags to be allowed,
+ *     specify an array of tags.
+ * @return array
+ *   An array of plugin definitions, keyed by the plugin name.
+ *
+ * @see ckeditor_ckeditor_plugins()
+ * @see hook_ckeditor_PLUGIN_plugin_check()
+ * @see \Drupal\editor\Plugin\EditorBase
+ */
+function hook_ckeditor_plugins() {
+  // The drupalcaption plugin provides consistent behaviors for image captions.
+  $plugins['myplugin'] = array(
+    'path' => drupal_get_path('module', 'mymodule') . '/js/myplugin',
+    'file' => 'plugin.js',
+    'css' => array(drupal_get_path('module', 'mymodule') . '/css/myplugin.css'),
+    'enabled callback' => 'mymodule_myplugin_plugin_check',
+  );
+
+  return $plugins;
+}
+
+/**
+ * Modify the list of available CKEditor plugins.
+ *
+ * This hook may be used to modify plugin properties after they have been
+ * specified by other modules.
+ *
+ * @param $plugins
+ *   An array of all the existing plugin definitions, passed by reference.
+ *
+ * @see hook_ckeditor_plugins()
+ */
+function hook_ckeditor_plugins_alter(array &$plugins) {
+  $plugins['someplugin']['enabled callback'] = 'mymodule_someplugin_enabled_callback';
+}
+
+/**
+ * Modify the list of CSS files that will be added to a CKEditor instance.
+ *
+ * Modules may use this hook to provide their own custom CSS file without
+ * providing a CKEditor plugin. This list of CSS files is only used in the
+ * iframe versions of CKEditor.
+ *
+ * Note that because this hook is only called for modules and the active theme,
+ * front-end themes will not be able to use this hook to add their own CSS files
+ * if a different admin theme is active. Instead, front-end themes and base
+ * themes may specify CSS files to be used in iframe instances of CKEditor
+ * through an entry in their .info file:
+ *
+ * @code
+ * ckeditor_stylesheets[] = css/ckeditor-iframe.css
+ * @endcode
+ *
+ * @param $css
+ *   An array of CSS files, passed by reference. This is a flat list of file
+ *   paths relative to the Drupal root.
+ * @param $editor
+ *   The editor object as returned by editor_load(), for which these files are
+ *   being loaded.
+ * @param $format
+ *   The corresponding text format object as returned by filter_format_load()
+ *   for which the current text editor is being displayed.
+ *
+ * @see _ckeditor_theme_css()
+ */
+function hook_ckeditor_css_alter(array &$css, $editor, $format) {
+  $css[] = drupal_get_path('module', 'mymodule') . '/css/mymodule-ckeditor.css';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
+
+/**
+ * Enabled callback for hook_ckeditor_plugins().
+ *
+ * Note: This is not really a hook. The function name is manually specified via
+ * 'enabled callback' in hook_ckeditor_plugins(), with this recommended callback
+ * name pattern. It is called from
+ * \Drupal\ckeditor\Plugin\editor\editor\CKEditor:getJSSettings().
+ *
+ * This callback should determine if a plugin should be enabled for a CKEditor
+ * instance. Plugins may be enabled based off an explicit setting, or enable
+ * themselves based on the configuration of another setting, such as enabling
+ * based on a particular button being present in the toolbar.
+ *
+ * @param object $editor
+ *   An editor instance as returned by editor_load(). The editor's settings may
+ *   be found in $editor->settings.
+ * @param string $plugin_name
+ *   String name of the plugin that is being checked.
+ *
+ * @return boolean
+ *   Boolean TRUE if the plugin should be enabled, FALSE otherwise.
+ *
+ * @see hook_ckeditor_plugins()
+ * @see \Drupal\ckeditor\Plugin\editor\editor\CKEditor:getJSSettings()
+ */
+function hook_ckeditor_PLUGIN_plugin_check($editor, $plugin_name) {
+  // Automatically enable this plugin if the Underline button is enabled.
+  foreach ($editor->settings['toolbar']['buttons'] as $row) {
+    if (in_array('Underline', $row)) {
+      return TRUE;
+    }
+  }
+}
diff --git a/ckeditor.module b/ckeditor.module
index 80d7dc9..911c7d0 100644
--- a/ckeditor.module
+++ b/ckeditor.module
@@ -250,10 +250,10 @@ function ckeditor_ckeditor_plugins() {
     ),
   );
 
-  // Populate image locations, which all match button names.
+  // Populate image locations that match button names.
   foreach ($buttons as $button_name => &$button) {
     if (!isset($button['image_alternative']) && !isset($button['image'])) {
-      // Because we know the list of strings, drupal_strtolower() is not needed.
+      // Because button names are ASCII text, drupal_strtolower() is not needed.
       $button['image'] = $image_prefix . strtolower($button_name) . '.png';
     }
   }
@@ -327,7 +327,7 @@ function ckeditor_image_plugin_check($editor) {
 /**
  * Retrieves the default theme's CKEditor stylesheets defined in the .info file.
  *
- * Themes may specify iFrame-specific CSS files for use with CKEditor by
+ * Themes may specify iframe-specific CSS files for use with CKEditor by
  * including a "ckeditor_stylesheets" key in the theme .info file.
  *
  * @code
diff --git a/css/ckeditor-iframe.css b/css/ckeditor-iframe.css
index e3d1fd0..44929d6 100644
--- a/css/ckeditor-iframe.css
+++ b/css/ckeditor-iframe.css
@@ -1,5 +1,5 @@
 /**
- * CSS added to iFrame-based instances only.
+ * CSS added to iframe-based instances only.
  */
 body {
   font-family: Arial, Verdana, sans-serif;
@@ -9,7 +9,7 @@ body {
   margin: 8px;
 }
 
-ol,ul,dl {
+ol, ul, dl {
   /* IE7: reset rtl list margin. (CKEditor issue #7334) */
   *margin-right: 0px;
   /* Preserved spaces for list items with text direction other than the list.
@@ -17,7 +17,7 @@ ol,ul,dl {
   padding: 0 40px;
 }
 
-/* The Drupal <!--break--> tag is only shown in iFrame based editing. */
+/* The Drupal <!--break--> tag is only shown in iframe based editing. */
 .cke_editable img.cke_drupal_break {
   background-image: url(../images/break-handle.png);
   background-position: center center;
diff --git a/css/ckeditor-rtl.css b/css/ckeditor-rtl.css
index 1e2d05b..59f97b8 100644
--- a/css/ckeditor-rtl.css
+++ b/css/ckeditor-rtl.css
@@ -1,5 +1,5 @@
 /**
- * RTL styles used by CKEditor. Added to front-end theme and iFrame editors.
+ * RTL styles used by CKEditor. Added to front-end theme and iframe editors.
  */
 .align-left {
   text-align: right;
diff --git a/css/ckeditor.admin.css b/css/ckeditor.admin.css
index 2e4027c..15fad3b 100644
--- a/css/ckeditor.admin.css
+++ b/css/ckeditor.admin.css
@@ -1,19 +1,22 @@
 /**
  * @file
  * Styles for configuration of CKEditor module.
+ *
+ * Many of these styles are adapted directly from the default CKEditor theme
+ * "moono".
  */
 
 .ckeditor-toolbar-active {
-  border: 1px solid #B6B6B6;
+  border: 1px solid #b6b6b6;
   padding: 6px 8px 2px;
   box-shadow: 0 1px 0 white inset;
-  background: #CFD1CF;
-  background-image: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#CFD1CF));
-  background-image: -moz-linear-gradient(top, whiteSmoke, #CFD1CF);
-  background-image: -o-linear-gradient(top, whiteSmoke, #CFD1CF);
-  background-image: -ms-linear-gradient(top, whiteSmoke, #CFD1CF);
-  background-image: linear-gradient(top, whiteSmoke, #CFD1CF);
-  filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#fff5f5f5',endColorstr='#ffcfd1cf');
+  background: #cfd1cf;
+  background-image: -webkit-gradient(linear, left top, left bottom, from(whiteSmoke), to(#cfd1cf));
+  background-image: -moz-linear-gradient(top, whiteSmoke, #cfd1cf);
+  background-image: -o-linear-gradient(top, whiteSmoke, #cfd1cf);
+  background-image: -ms-linear-gradient(top, whiteSmoke, #cfd1cf);
+  background-image: linear-gradient(top, whiteSmoke, #cfd1cf);
+  filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#fff5f5f5', endColorstr='#ffcfd1cf');
   margin: 5px 0;
   overflow: nowrap;
 }
@@ -30,14 +33,10 @@ ul.ckeditor-buttons {
   clear: left;
   padding: 0;
   margin: 0 6px 5px 0;
-  border: 1px solid #A6A6A6;
+  border: 1px solid #a6a6a6;
   border-bottom-color: #979797;
-  -moz-border-radius: 3px;
-  -webkit-border-radius: 3px;
   border-radius: 3px;
-  -moz-box-shadow: 0 1px 0 rgba(255,255,255,.5),0 0 2px rgba(255,255,255,.15) inset,0 1px 0 rgba(255,255,255,.15) inset;
-  -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5),0 0 2px rgba(255, 255, 255, .15) inset,0 1px 0 rgba(255, 255, 255, .15) inset;
-  box-shadow: 0 1px 0 rgba(255, 255, 255, .5),0 0 2px rgba(255, 255, 255, .15) inset,0 1px 0 rgba(255, 255, 255, .15) inset;
+  box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 0 2px rgba(255, 255, 255, .15) inset, 0 1px 0 rgba(255, 255, 255, .15) inset;
 }
 ul.ckeditor-buttons li {
   display: inline-block;
@@ -49,28 +48,20 @@ ul.ckeditor-buttons li {
   border: 0;
   white-space: nowrap;
 
-  background: #E4E4E4;
-  background-image: -webkit-gradient(linear,left top,left bottom,from(white),to(#E4E4E4));
-  background-image: -moz-linear-gradient(top,white,#E4E4E4);
-  background-image: -webkit-linear-gradient(top,white,#E4E4E4);
-  background-image: -o-linear-gradient(top,white,#E4E4E4);
-  background-image: -ms-linear-gradient(top,white,#E4E4E4);
-  background-image: linear-gradient(top,white,#E4E4E4);
+  background: #e4e4e4;
+  background-image: -webkit-gradient(linear,left top,left bottom,from(white),to(#e4e4e4));
+  background-image: -moz-linear-gradient(top,white,#e4e4e4);
+  background-image: -webkit-linear-gradient(top,white,#e4e4e4);
+  background-image: -o-linear-gradient(top,white,#e4e4e4);
+  background-image: -ms-linear-gradient(top,white,#e4e4e4);
+  background-image: linear-gradient(top,white,#e4e4e4);
   filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#ffffffff',endColorstr='#ffe4e4e4');
 }
 ul.ckeditor-buttons li:first-child {
-  -moz-border-top-left-radius: 2px;
-  -moz-border-bottom-left-radius: 2px;
-  -webkit-border-top-left-radius: 2px;
-  -webkit-border-bottom-left-radius: 2px;
   border-top-left-radius: 2px;
   border-bottom-left-radius: 2px;
 }
 ul.ckeditor-buttons li:last-child {
-  -moz-border-top-right-radius: 2px;
-  -moz-border-bottom-right-radius: 2px;
-  -webkit-border-top-right-radius: 2px;
-  -webkit-border-bottom-right-radius: 2px;
   border-top-right-radius: 2px;
   border-bottom-right-radius: 2px;
 }
@@ -114,14 +105,14 @@ ul.ckeditor-buttons li.ckeditor-button-separator {
   position: relative;
   z-index: 10;
 
-  background: #E4E4E4;
-  background-image: -webkit-gradient(linear,left top,left bottom,from(white),to(#E4E4E4));
-  background-image: -moz-linear-gradient(top,white,#E4E4E4);
-  background-image: -webkit-linear-gradient(top,white,#E4E4E4);
-  background-image: -o-linear-gradient(top,white,#E4E4E4);
-  background-image: -ms-linear-gradient(top,white,#E4E4E4);
-  background-image: linear-gradient(top,white,#E4E4E4);
-  filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#ffffffff',endColorstr='#ffe4e4e4');
+  background: #e4e4e4;
+  background-image: -webkit-gradient(linear, left top, left bottom, from(white), to(#e4e4e4));
+  background-image: -moz-linear-gradient(top, white, #e4e4e4);
+  background-image: -webkit-linear-gradient(top, white, #e4e4e4);
+  background-image: -o-linear-gradient(top, white, #e4e4e4);
+  background-image: -ms-linear-gradient(top, white, #e4e4e4);
+  background-image: linear-gradient(top, white, #e4e4e4);
+  filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#ffffffff', endColorstr='#ffe4e4e4');
 }
 ul.ckeditor-multiple-buttons li.ckeditor-button-separator {
   width: 2px;
diff --git a/css/ckeditor.css b/css/ckeditor.css
index 94bdcf3..d5c6efe 100644
--- a/css/ckeditor.css
+++ b/css/ckeditor.css
@@ -1,5 +1,5 @@
 /**
- * Common styles used by CKEditor. Added to front-end theme and iFrame editors.
+ * Common styles used by CKEditor. Added to front-end theme and iframe editors.
  */
 .align-left {
   text-align: left; /* RTL */
diff --git a/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php b/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php
index 7955914..6dbae6f 100644
--- a/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php
+++ b/lib/Drupal/ckeditor/Plugin/editor/editor/CKEditor.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Definition of \Drupal\ckeditor\Plugin\editor\editor\CKEditor.
+ * Contains \Drupal\ckeditor\Plugin\editor\editor\CKEditor.
  */
 
 namespace Drupal\ckeditor\Plugin\editor\editor;
@@ -125,7 +125,7 @@ class CKEditor extends EditorBase {
     foreach ($plugin_info as $plugin_name => $plugin) {
       // Check if this plugin should be enabled.
       if (isset($plugin['enabled callback'])) {
-        if ($plugin['enabled callback'] === TRUE || $plugin['enabled callback']($editor) && !empty($plugin['path'])) {
+        if ($plugin['enabled callback'] === TRUE || $plugin['enabled callback']($editor, $plugin_name) && !empty($plugin['path'])) {
           $external_plugins[$plugin_name]['file'] = $plugin['file'];
           $external_plugins[$plugin_name]['path'] = $plugin['path'];
           if (isset($plugin['css'])) {
