diff --git a/core/misc/active-link.js b/core/misc/active-link.js
index 3a2f818b009e4b4c80b2994f90e3812d5871c74f..97c9966bc26fed9f20e3a3619450c4739197e7cd 100644
--- a/core/misc/active-link.js
+++ b/core/misc/active-link.js
@@ -18,6 +18,8 @@
    *
    * Does not discriminate based on element type, so allows you to set the
    * is-active class on any element: a, li…
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.activeLinks = {
     attach: function (context) {
@@ -28,7 +30,8 @@
       var originalSelectors = ['[data-drupal-link-system-path="' + path.currentPath + '"]'];
       var selectors;
 
-      // If this is the front page, we have to check for the <front> path as well.
+      // If this is the front page, we have to check for the <front> path as
+      // well.
       if (path.isFront) {
         originalSelectors.push('[data-drupal-link-system-path="<front>"]');
       }
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index db8dd26fa632c1c05ae1cc720f812a67b342bbfc..3cb1c8d2aed4c98c04bd2425b8e9a01c741a943d 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -1,9 +1,24 @@
+/**
+ * @file
+ * Provides Ajax page updating via jQuery $.ajax.
+ *
+ * Ajax is a method of making a request via JavaScript while viewing an HTML
+ * page. The request returns an array of commands encoded in JSON, which is
+ * then executed to make any changes that are necessary to the page.
+ *
+ * Drupal uses this file to enhance form elements with `#ajax['url']` and
+ * `#ajax['wrapper']` properties. If set, this file will automatically be
+ * included to provide Ajax capabilities.
+ */
+
 (function ($, window, Drupal, drupalSettings) {
 
   "use strict";
 
   /**
    * Attaches the Ajax behavior to each Ajax form element.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.AJAX = {
     attach: function (context, settings) {
@@ -58,7 +73,8 @@
         element_settings.setClick = true;
         // Form buttons use the 'click' event rather than mousedown.
         element_settings.event = 'click';
-        // Clicked form buttons look better with the throbber than the progress bar.
+        // Clicked form buttons look better with the throbber than the progress
+        // bar.
         element_settings.progress = {'type': 'throbber'};
         element_settings.base = $(this).attr('id');
         element_settings.element = this;
@@ -70,6 +86,15 @@
 
   /**
    * Extends Error to provide handling for Errors in Ajax.
+   *
+   * @constructor
+   *
+   * @augments Error
+   *
+   * @param {XMLHttpRequest} xmlhttp
+   *   XMLHttpRequest object used for the failed request.
+   * @param {string} uri
+   *   The URI where the error occurred.
    */
   Drupal.AjaxError = function (xmlhttp, uri) {
 
@@ -87,14 +112,15 @@
     statusCode += "\n" + Drupal.t("Debugging information follows.");
     pathText = "\n" + Drupal.t("Path: !uri", {'!uri': uri});
     statusText = '';
-    // In some cases, when statusCode === 0, xmlhttp.statusText may not be defined.
-    // Unfortunately, testing for it with typeof, etc, doesn't seem to catch that
-    // and the test causes an exception. So we need to catch the exception here.
+    // In some cases, when statusCode === 0, xmlhttp.statusText may not be
+    // defined. Unfortunately, testing for it with typeof, etc, doesn't seem to
+    // catch that and the test causes an exception. So we need to catch the
+    // exception here.
     try {
       statusText = "\n" + Drupal.t("StatusText: !statusText", {'!statusText': $.trim(xmlhttp.statusText)});
     }
     catch (e) {
-      // empty
+      // Empty.
     }
 
     responseText = '';
@@ -114,7 +140,18 @@
     // We don't need readyState except for status == 0.
     readyStateText = xmlhttp.status === 0 ? ("\n" + Drupal.t("ReadyState: !readyState", {'!readyState': xmlhttp.readyState})) : "";
 
+    /**
+     * Formatted and translated error message.
+     *
+     * @type {string}
+     */
     this.message = statusCode + pathText + statusText + responseText + readyStateText;
+
+    /**
+     * Used by some browsers to display a more accurate stack trace.
+     *
+     * @type {string}
+     */
     this.name = 'AjaxError';
   };
 
@@ -125,8 +162,8 @@
    * Provides Ajax page updating via jQuery $.ajax.
    *
    * This function is designed to improve developer experience by wrapping the
-   * initialization of Drupal.Ajax objects and storing all created object in the
-   * Drupal.ajax.instances array.
+   * initialization of {@link Drupal.Ajax} objects and storing all created
+   * objects in the {@link Drupal.ajax.instances} array.
    *
    * @example
    * Drupal.behaviors.myCustomAJAXStuff = {
@@ -158,17 +195,18 @@
    *   }
    * };
    *
-   * @see Drupal.AjaxCommands
-   *
    * @param {object} settings
-   *   The settings object passed to Drupal.Ajax constructor.
+   *   The settings object passed to {@link Drupal.Ajax} constructor.
    * @param {string} [settings.base]
-   *   Base is passed to Drupal.Ajax constructor as the 'base' parameter.
+   *   Base is passed to {@link Drupal.Ajax} constructor as the 'base'
+   *   parameter.
    * @param {HTMLElement} [settings.element]
-   *   Element parameter of Drupal.Ajax constructor, element on which
+   *   Element parameter of {@link Drupal.Ajax} constructor, element on which
    *   event listeners will be bound.
    *
    * @return {Drupal.Ajax}
+   *
+   * @see Drupal.AjaxCommands
    */
   Drupal.ajax = function (settings) {
     if (arguments.length !== 1) {
@@ -195,7 +233,7 @@
   /**
    * Contains all created Ajax objects.
    *
-   * @type {Array}
+   * @type {Array.<Drupal.Ajax>}
    */
   Drupal.ajax.instances = [];
 
@@ -205,16 +243,16 @@
    * The Ajax request returns an array of commands encoded in JSON, which is
    * then executed to make any changes that are necessary to the page.
    *
-   * Drupal uses this file to enhance form elements with #ajax['url'] and
-   * #ajax['wrapper'] properties. If set, this file will automatically be
+   * Drupal uses this file to enhance form elements with `#ajax['url']` and
+   * `#ajax['wrapper']` properties. If set, this file will automatically be
    * included to provide Ajax capabilities.
    *
    * @constructor
    *
    * @param {string} [base]
-   *   Base parameter of Drupal.Ajax constructor
+   *   Base parameter of {@link Drupal.Ajax} constructor
    * @param {HTMLElement} [element]
-   *   Element parameter of Drupal.Ajax constructor, element on which
+   *   Element parameter of {@link Drupal.Ajax} constructor, element on which
    *   event listeners will be bound.
    * @param {object} element_settings
    * @param {string} element_settings.url
@@ -244,6 +282,9 @@
 
     $.extend(this, defaults, element_settings);
 
+    /**
+     * @type {Drupal.AjaxCommands}
+     */
     this.commands = new Drupal.AjaxCommands();
     this.instanceIndex = false;
 
@@ -252,15 +293,30 @@
     //   - Include the '#' for ID-based selectors.
     //   - Support non-ID-based selectors.
     if (this.wrapper) {
+
+      /**
+       * @type {string}
+       */
       this.wrapper = '#' + this.wrapper;
     }
 
+    /**
+     * @type {HTMLElement}
+     */
     this.element = element;
+
+    /**
+     * @type {object}
+     */
     this.element_settings = element_settings;
 
     // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
     // bind Ajax to links as well.
     if (this.element && this.element.form) {
+
+      /**
+       * @type {jQuery}
+       */
       this.$form = $(this.element.form);
     }
 
@@ -273,15 +329,16 @@
       else if (this.element && element.form) {
         this.url = this.$form.attr('action');
 
-        // @todo If there's a file input on this form, then jQuery will submit the
-        //   Ajax response with a hidden Iframe rather than the XHR object. If the
-        //   response to the submission is an HTTP redirect, then the Iframe will
-        //   follow it, but the server won't content negotiate it correctly,
-        //   because there won't be an ajax_iframe_upload POST variable. Until we
-        //   figure out a work around to this problem, we prevent Ajax-enabling
-        //   elements that submit to the same URL as the form when there's a file
-        //   input. For example, this means the Delete button on the edit form of
-        //   an Article node doesn't open its confirmation form in a dialog.
+        // @todo If there's a file input on this form, then jQuery will submit
+        //   the AJAX response with a hidden Iframe rather than the XHR object.
+        //   If the response to the submission is an HTTP redirect, then the
+        //   Iframe will follow it, but the server won't content negotiate it
+        //   correctly, because there won't be an ajax_iframe_upload POST
+        //   variable. Until we figure out a work around to this problem, we
+        //   prevent AJAX-enabling elements that submit to the same URL as the
+        //   form when there's a file input. For example, this means the Delete
+        //   button on the edit form of an Article node doesn't open its
+        //   confirmation form in a dialog.
         if (this.$form.find(':file').length) {
           return;
         }
@@ -300,6 +357,26 @@
     // Set the options for the ajaxSubmit function.
     // The 'this' variable will not persist inside of the options object.
     var ajax = this;
+
+    /**
+     * Options for the ajaxSubmit function.
+     *
+     * @name Drupal.Ajax#options
+     *
+     * @type {object}
+     *
+     * @prop {string} url
+     * @prop {object} data
+     * @prop {function} beforeSerialize
+     * @prop {function} beforeSubmit
+     * @prop {function} beforeSend
+     * @prop {function} success
+     * @prop {function} complete
+     * @prop {string} dataType
+     * @prop {object} accepts
+     * @prop {string} accepts.json
+     * @prop {string} type
+     */
     ajax.options = {
       url: ajax.url,
       data: ajax.submit,
@@ -373,6 +450,8 @@
    *
    * The wrapper format determines how the HTML is wrapped, for example in a
    * modal dialog.
+   *
+   * @const {string}
    */
   Drupal.ajax.WRAPPER_FORMAT = '_wrapper_format';
 
@@ -409,6 +488,9 @@
    * In this case we're handling RETURN and SPACEBAR keypresses (event codes 13
    * and 32. RETURN is often used to submit a form when in a textfield, and
    * SPACE is often used to activate an element without submitting.
+   *
+   * @param {HTMLElement} element
+   * @param {jQuery.Event} event
    */
   Drupal.Ajax.prototype.keypressResponse = function (element, event) {
     // Create a synonym for this to reduce code confusion.
@@ -417,8 +499,8 @@
     // Detect enter key and space bar and allow the standard response for them,
     // except for form elements of type 'text', 'tel', 'number' and 'textarea',
     // where the spacebar activation causes inappropriate activation if
-    // #ajax['keypress'] is TRUE. On a text-type widget a space should always be a
-    // space.
+    // #ajax['keypress'] is TRUE. On a text-type widget a space should always
+    // be a space.
     if (event.which === 13 || (event.which === 32 && element.type !== 'text' &&
       element.type !== 'textarea' && element.type !== 'tel' && element.type !== 'number')) {
       event.preventDefault();
@@ -434,6 +516,9 @@
    * perform the actual Ajax call. It is bound to the event using
    * bind() in the constructor, and it uses the options specified on the
    * Ajax object.
+   *
+   * @param {HTMLElement} element
+   * @param {jQuery.Event} event
    */
   Drupal.Ajax.prototype.eventResponse = function (element, event) {
     event.preventDefault();
@@ -479,6 +564,10 @@
    *
    * Runs before the beforeSend() handler (see below), and unlike that one, runs
    * before field data is collected.
+   *
+   * @param {HTMLElement} element
+   * @param {object} options
+   * @param {object} options.data
    */
   Drupal.Ajax.prototype.beforeSerialize = function (element, options) {
     // Allow detaching behaviors to update field values before collecting them.
@@ -515,6 +604,10 @@
 
   /**
    * Modify form values prior to form submission.
+   *
+   * @param {object} form_values
+   * @param {HTMLElement} element
+   * @param {object} options
    */
   Drupal.Ajax.prototype.beforeSubmit = function (form_values, element, options) {
     // This function is left empty to make it simple to override for modules
@@ -523,30 +616,35 @@
 
   /**
    * Prepare the Ajax request before it is sent.
+   *
+   * @param {XMLHttpRequest} xmlhttprequest
+   * @param {object} options
+   * @param {object} options.extraData
    */
   Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
-    // For forms without file inputs, the jQuery Form plugin serializes the form
-    // values, and then calls jQuery's $.ajax() function, which invokes this
-    // handler. In this circumstance, options.extraData is never used. For forms
-    // with file inputs, the jQuery Form plugin uses the browser's normal form
-    // submission mechanism, but captures the response in a hidden IFRAME. In this
-    // circumstance, it calls this handler first, and then appends hidden fields
-    // to the form to submit the values in options.extraData. There is no simple
-    // way to know which submission mechanism will be used, so we add to extraData
-    // regardless, and allow it to be ignored in the former case.
+    // For forms without file inputs, the jQuery Form plugin serializes the
+    // form values, and then calls jQuery's $.ajax() function, which invokes
+    // this handler. In this circumstance, options.extraData is never used. For
+    // forms with file inputs, the jQuery Form plugin uses the browser's normal
+    // form submission mechanism, but captures the response in a hidden IFRAME.
+    // In this circumstance, it calls this handler first, and then appends
+    // hidden fields to the form to submit the values in options.extraData.
+    // There is no simple way to know which submission mechanism will be used,
+    // so we add to extraData regardless, and allow it to be ignored in the
+    // former case.
     if (this.$form) {
       options.extraData = options.extraData || {};
 
       // Let the server know when the IFRAME submission mechanism is used. The
-      // server can use this information to wrap the JSON response in a TEXTAREA,
-      // as per http://jquery.malsup.com/form/#file-upload.
+      // server can use this information to wrap the JSON response in a
+      // TEXTAREA, as per http://jquery.malsup.com/form/#file-upload.
       options.extraData.ajax_iframe_upload = '1';
 
       // The triggering element is about to be disabled (see below), but if it
-      // contains a value (e.g., a checkbox, textfield, select, etc.), ensure that
-      // value is included in the submission. As per above, submissions that use
-      // $.ajax() are already serialized prior to the element being disabled, so
-      // this is only needed for IFRAME submissions.
+      // contains a value (e.g., a checkbox, textfield, select, etc.), ensure
+      // that value is included in the submission. As per above, submissions
+      // that use $.ajax() are already serialized prior to the element being
+      // disabled, so this is only needed for IFRAME submissions.
       var v = $.fieldValue(this.element);
       if (v !== null) {
         options.extraData[this.element.name] = v;
@@ -563,7 +661,7 @@
       return;
     }
 
-    // Insert progress indicator
+    // Insert progress indicator.
     var progressIndicatorMethod = 'setProgressIndicator' + this.progress.type.slice(0, 1).toUpperCase() + this.progress.type.slice(1).toLowerCase();
     if (progressIndicatorMethod in this && typeof this[progressIndicatorMethod] === 'function') {
       this[progressIndicatorMethod].call(this);
@@ -607,6 +705,9 @@
 
   /**
    * Handler for the form redirection completion.
+   *
+   * @param {Array.<Drupal.AjaxCommands~commandDefinition>} response
+   * @param {number} status
    */
   Drupal.Ajax.prototype.success = function (response, status) {
     // Remove the progress element.
@@ -639,7 +740,13 @@
   };
 
   /**
-   * Build an effect object which tells us how to apply the effect when adding new HTML.
+   * Build an effect object to apply an effect when adding new HTML.
+   *
+   * @param {object} response
+   * @param {string} [response.effect]
+   * @param {string|number} [response.speed]
+   *
+   * @return {object}
    */
   Drupal.Ajax.prototype.getEffect = function (response) {
     var type = response.effect || this.effect;
@@ -667,6 +774,9 @@
 
   /**
    * Handler for the form redirection error.
+   *
+   * @param {object} response
+   * @param {string} uri
    */
   Drupal.Ajax.prototype.error = function (response, uri) {
     // Remove the progress element.
@@ -689,12 +799,46 @@
   };
 
   /**
-   * Provide a series of commands that the server can request the client perform.
+   * @typedef {object} Drupal.AjaxCommands~commandDefinition
+   *
+   * @prop {string} command
+   * @prop {string} [method]
+   * @prop {string} [selector]
+   * @prop {string} [data]
+   * @prop {object} [settings]
+   * @prop {bool} [asterisk]
+   * @prop {string} [text]
+   * @prop {string} [title]
+   * @prop {string} [url]
+   * @prop {object} [argument]
+   * @prop {string} [name]
+   * @prop {string} [value]
+   * @prop {string} [old]
+   * @prop {string} [new]
+   * @prop {bool} [merge]
+   * @prop {Array} [args]
+   *
+   * @see Drupal.AjaxCommands
+   */
+
+  /**
+   * Provide a series of commands that the client will perform.
+   *
+   * @constructor
    */
   Drupal.AjaxCommands = function () {};
   Drupal.AjaxCommands.prototype = {
+
     /**
      * Command to insert new content into the DOM.
+     *
+     * @param {Drupal.Ajax} ajax
+     * @param {object} response
+     * @param {string} response.data
+     * @param {string} [response.method]
+     * @param {string} [response.selector]
+     * @param {object} [response.settings]
+     * @param {number} [status]
      */
     insert: function (ajax, response, status) {
       // Get information from the response. If it is not there, default to
@@ -712,16 +856,17 @@
       var new_content_wrapped = $('<div></div>').html(response.data);
       var new_content = new_content_wrapped.contents();
 
-      // For legacy reasons, the effects processing code assumes that new_content
-      // consists of a single top-level element. Also, it has not been
-      // sufficiently tested whether attachBehaviors() can be successfully called
-      // with a context object that includes top-level text nodes. However, to
-      // give developers full control of the HTML appearing in the page, and to
-      // enable Ajax content to be inserted in places where DIV elements are not
-      // allowed (e.g., within TABLE, TR, and SPAN parents), we check if the new
-      // content satisfies the requirement of a single top-level element, and
-      // only use the container DIV created above when it doesn't. For more
-      // information, please see https://www.drupal.org/node/736066.
+      // For legacy reasons, the effects processing code assumes that
+      // new_content consists of a single top-level element. Also, it has not
+      // been sufficiently tested whether attachBehaviors() can be successfully
+      // called with a context object that includes top-level text nodes.
+      // However, to give developers full control of the HTML appearing in the
+      // page, and to enable Ajax content to be inserted in places where DIV
+      // elements are not allowed (e.g., within TABLE, TR, and SPAN parents),
+      // we check if the new content satisfies the requirement of a single
+      // top-level element, and only use the container DIV created above when
+      // it doesn't. For more information, please see
+      // https://www.drupal.org/node/736066.
       if (new_content.length !== 1 || new_content.get(0).nodeType !== 1) {
         new_content = new_content_wrapped;
       }
@@ -756,9 +901,9 @@
         new_content[effect.showEffect](effect.showSpeed);
       }
 
-      // Attach all JavaScript behaviors to the new content, if it was successfully
-      // added to the page, this if statement allows #ajax['wrapper'] to be
-      // optional.
+      // Attach all JavaScript behaviors to the new content, if it was
+      // successfully added to the page, this if statement allows
+      // `#ajax['wrapper']` to be optional.
       if (new_content.parents('html').length > 0) {
         // Apply any settings from the returned JSON if available.
         settings = response.settings || ajax.settings || drupalSettings;
@@ -768,6 +913,12 @@
 
     /**
      * Command to remove a chunk from the page.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.selector
+     * @param {object} [response.settings]
+     * @param {number} [status]
      */
     remove: function (ajax, response, status) {
       var settings = response.settings || ajax.settings || drupalSettings;
@@ -779,6 +930,12 @@
 
     /**
      * Command to mark a chunk changed.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.selector
+     * @param {bool} [response.asterisk]
+     * @param {number} [status]
      */
     changed: function (ajax, response, status) {
       if (!$(response.selector).hasClass('ajax-changed')) {
@@ -791,6 +948,12 @@
 
     /**
      * Command to provide an alert.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.text
+     * @param {string} response.title
+     * @param {number} [status]
      */
     alert: function (ajax, response, status) {
       window.alert(response.text, response.title);
@@ -798,6 +961,11 @@
 
     /**
      * Command to set the window.location, redirecting the browser.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.url
+     * @param {number} [status]
      */
     redirect: function (ajax, response, status) {
       window.location = response.url;
@@ -805,13 +973,24 @@
 
     /**
      * Command to provide the jQuery css() function.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {object} response.argument
+     * @param {number} [status]
      */
     css: function (ajax, response, status) {
       $(response.selector).css(response.argument);
     },
 
     /**
-     * Command to set the settings that will be used for other commands in this response.
+     * Command to set the settings used for other commands in this response.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {bool} response.merge
+     * @param {object} response.settings
+     * @param {number} [status]
      */
     settings: function (ajax, response, status) {
       if (response.merge) {
@@ -824,6 +1003,13 @@
 
     /**
      * Command to attach data using jQuery's data API.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.name
+     * @param {string} response.selector
+     * @param {string|object} response.value
+     * @param {number} [status]
      */
     data: function (ajax, response, status) {
       $(response.selector).data(response.name, response.value);
@@ -831,6 +1017,13 @@
 
     /**
      * Command to apply a jQuery method.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {Array} response.args
+     * @param {string} response.method
+     * @param {string} response.selector
+     * @param {number} [status]
      */
     invoke: function (ajax, response, status) {
       var $element = $(response.selector);
@@ -839,6 +1032,11 @@
 
     /**
      * Command to restripe a table.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.selector
+     * @param {number} [status]
      */
     restripe: function (ajax, response, status) {
       // :even and :odd are reversed because jQuery counts from 0 and
@@ -852,6 +1050,12 @@
 
     /**
      * Command to update a form's build ID.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.old
+     * @param {string} response.new
+     * @param {number} [status]
      */
     update_build_id: function (ajax, response, status) {
       $('input[name="form_build_id"][value="' + response.old + '"]').val(response.new);
@@ -863,6 +1067,11 @@
      * Uses the proprietary addImport method if available as browsers which
      * support that method ignore @import statements in dynamically added
      * stylesheets.
+     *
+     * @param {Drupal.Ajax} [ajax]
+     * @param {object} response
+     * @param {string} response.data
+     * @param {number} [status]
      */
     add_css: function (ajax, response, status) {
       // Add the styles in the normal way.
diff --git a/core/misc/announce.js b/core/misc/announce.js
index 9aafbbcbce4a7ed55e2cbc68d78e103bb7cf60a0..0a0abebbdfde58fdebcb459ec4de12ceef3dcc29 100644
--- a/core/misc/announce.js
+++ b/core/misc/announce.js
@@ -1,9 +1,12 @@
 /**
+ * @file
  * Adds an HTML element and method to trigger audio UAs to read system messages.
  *
- * Use Drupal.announce() to indicate to screen reader users that an element on
- * the page has changed state. For instance, if clicking a link loads 10 more
- * items into a list, one might announce the change like this.
+ * Use {@link Drupal.announce} to indicate to screen reader users that an
+ * element on the page has changed state. For instance, if clicking a link
+ * loads 10 more items into a list, one might announce the change like this.
+ *
+ * @example
  * $('#search-list')
  *   .on('itemInsert', function (event, data) {
  *     // Insert the new items.
@@ -14,6 +17,7 @@
  *     ));
  *   });
  */
+
 (function (Drupal, debounce) {
 
   "use strict";
@@ -22,8 +26,9 @@
   var announcements = [];
 
   /**
-   * Builds a div element with the aria-live attribute and attaches it
-   * to the DOM.
+   * Builds a div element with the aria-live attribute and add it to the DOM.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.drupalAnnounce = {
     attach: function (context) {
@@ -80,17 +85,19 @@
    *
    * The aria-live region will only read the text that currently populates its
    * text node. Replacing text quickly in rapid calls to announce results in
-   * only the text from the most recent call to Drupal.announce() being read.
-   * By wrapping the call to announce in a debounce function, we allow for
-   * time for multiple calls to Drupal.announce() to queue up their messages.
-   * These messages are then joined and append to the aria-live region as one
-   * text node.
+   * only the text from the most recent call to {@link Drupal.announce} being
+   * read. By wrapping the call to announce in a debounce function, we allow for
+   * time for multiple calls to {@link Drupal.announce} to queue up their
+   * messages. These messages are then joined and append to the aria-live region
+   * as one text node.
    *
-   * @param String text
+   * @param {string} text
    *   A string to be read by the UA.
-   * @param String priority
+   * @param {string} [priority='polite']
    *   A string to indicate the priority of the message. Can be either
-   *   'polite' or 'assertive'. Polite is the default.
+   *   'polite' or 'assertive'.
+   *
+   * @return {function}
    *
    * @see http://www.w3.org/WAI/PF/aria-practices/#liveprops
    */
diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js
index 92bb86785af0fb591f83834cb63f330c8e560414..f826281b4818e8c6399418197b39810d620e8f21 100644
--- a/core/misc/autocomplete.js
+++ b/core/misc/autocomplete.js
@@ -1,3 +1,8 @@
+/**
+ * @file
+ * Autocomplete based on jQuery UI.
+ */
+
 (function ($, Drupal) {
 
   "use strict";
@@ -7,7 +12,9 @@
   /**
    * Helper splitting terms from the autocomplete value.
    *
-   * @param {String} value
+   * @function Drupal.autocomplete.splitValues
+   *
+   * @param {string} value
    *
    * @return {Array}
    */
@@ -43,9 +50,11 @@
   /**
    * Returns the last value of an multi-value textfield.
    *
-   * @param {String} terms
+   * @function Drupal.autocomplete.extractLastTerm
+   *
+   * @param {string} terms
    *
-   * @return {String}
+   * @return {string}
    */
   function extractLastTerm(terms) {
     return autocomplete.splitValues(terms).pop();
@@ -54,9 +63,11 @@
   /**
    * The search handler is called before a search is performed.
    *
-   * @param {Object} event
+   * @function Drupal.autocomplete.options.search
    *
-   * @return {Boolean}
+   * @param {object} event
+   *
+   * @return {bool}
    */
   function searchHandler(event) {
     var options = autocomplete.options;
@@ -70,10 +81,10 @@
   }
 
   /**
-   * jQuery UI autocomplete source callback.
+   * JQuery UI autocomplete source callback.
    *
-   * @param {Object} request
-   * @param {Function} response
+   * @param {object} request
+   * @param {function} response
    */
   function sourceData(request, response) {
     var elementId = this.element.attr('id');
@@ -86,7 +97,7 @@
      * Filter through the suggestions removing all terms already tagged and
      * display the available terms to the user.
      *
-     * @param {Object} suggestions
+     * @param {object} suggestions
      */
     function showSuggestions(suggestions) {
       var tagged = autocomplete.splitValues(request.term);
@@ -103,7 +114,7 @@
     /**
      * Transforms the data object into an array and update autocomplete results.
      *
-     * @param {Object} data
+     * @param {object} data
      */
     function sourceCallbackHandler(data) {
       autocomplete.cache[elementId][term] = data;
@@ -128,7 +139,7 @@
   /**
    * Handles an autocompletefocus event.
    *
-   * @return {Boolean}
+   * @return {bool}
    */
   function focusHandler() {
     return false;
@@ -137,10 +148,10 @@
   /**
    * Handles an autocompleteselect event.
    *
-   * @param {Object} event
-   * @param {Object} ui
+   * @param {jQuery.Event} event
+   * @param {object} ui
    *
-   * @return {Boolean}
+   * @return {bool}
    */
   function selectHandler(event, ui) {
     var terms = autocomplete.splitValues(event.target.value);
@@ -161,10 +172,10 @@
   /**
    * Override jQuery UI _renderItem function to output HTML by default.
    *
-   * @param {Object} ul
-   * @param {Object} item
+   * @param {object} ul
+   * @param {object} item
    *
-   * @return {Object}
+   * @return {object}
    */
   function renderItem(ul, item) {
     return $("<li>")
@@ -174,6 +185,8 @@
 
   /**
    * Attaches the autocomplete behavior to all required fields.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.autocomplete = {
     attach: function (context) {
@@ -202,6 +215,8 @@
 
   /**
    * Autocomplete object implementation.
+   *
+   * @namespace Drupal.autocomplete
    */
   autocomplete = {
     cache: {},
@@ -209,6 +224,12 @@
     splitValues: autocompleteSplitValues,
     extractLastTerm: extractLastTerm,
     // jQuery UI autocomplete options.
+
+    /**
+     * JQuery UI option object.
+     *
+     * @name Drupal.autocomplete.options
+     */
     options: {
       source: sourceData,
       focus: focusHandler,
diff --git a/core/misc/batch.js b/core/misc/batch.js
index ee6cf68705df9f68ce542ddd1f067b2d9c2ba015..43242eab9427edc2fba47d9423f12723ebbf0c0d 100644
--- a/core/misc/batch.js
+++ b/core/misc/batch.js
@@ -1,12 +1,16 @@
 /**
+ * @file
  * Drupal's batch API.
  */
+
 (function ($, Drupal) {
 
   "use strict";
 
   /**
    * Attaches the batch behavior to progress bars.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.batch = {
     attach: function (context, settings) {
diff --git a/core/misc/collapse.js b/core/misc/collapse.js
index 2d44e3f403b3c6b0d8ee1a75aeb9c5e2b947501f..1ad89f7e80fe6f8ccabaf5b0c498ef77a4dcc21e 100644
--- a/core/misc/collapse.js
+++ b/core/misc/collapse.js
@@ -1,9 +1,18 @@
+/**
+ * @file
+ * Polyfill for HTML5 details elements.
+ */
+
 (function ($, Modernizr, Drupal) {
 
   "use strict";
 
   /**
-   * The collapsible details object represents a single collapsible details element.
+   * The collapsible details object represents a single details element.
+   *
+   * @constructor Drupal.CollapsibleDetails
+   *
+   * @param {HTMLElement} node
    */
   function CollapsibleDetails(node) {
     this.$node = $(node);
@@ -20,22 +29,24 @@
     this.setupLegend();
   }
 
-  /**
-   * Extend CollapsibleDetails function.
-   */
-  $.extend(CollapsibleDetails, {
+  $.extend(CollapsibleDetails, /** @lends Drupal.CollapsibleDetails */{
+
     /**
      * Holds references to instantiated CollapsibleDetails objects.
+     *
+     * @type {Array.<Drupal.CollapsibleDetails>}
      */
     instances: []
   });
 
-  /**
-   * Extend CollapsibleDetails prototype.
-   */
-  $.extend(CollapsibleDetails.prototype, {
+  $.extend(CollapsibleDetails.prototype, /** @lends Drupal.CollapsibleDetails# */{
+
     /**
      * Initialize and setup summary events and markup.
+     *
+     * @fires event:summaryUpdated
+     *
+     * @listens event:summaryUpdated
      */
     setupSummary: function () {
       this.$summary = $('<span class="summary"></span>');
@@ -43,6 +54,7 @@
         .on('summaryUpdated', $.proxy(this.onSummaryUpdated, this))
         .trigger('summaryUpdated');
     },
+
     /**
      * Initialize and setup legend markup.
      */
@@ -65,20 +77,25 @@
         .append(this.$summary)
         .on('click', $.proxy(this.onLegendClick, this));
     },
+
     /**
-     * Handle legend clicks
+     * Handle legend clicks.
+     *
+     * @param {jQuery.Event} e
      */
     onLegendClick: function (e) {
       this.toggle();
       e.preventDefault();
     },
+
     /**
-     * Update summary
+     * Update summary.
      */
     onSummaryUpdated: function () {
       var text = $.trim(this.$node.drupalGetSummary());
       this.$summary.html(text ? ' (' + text + ')' : '');
     },
+
     /**
      * Toggle the visibility of a details element using smooth animations.
      */
@@ -99,6 +116,11 @@
     }
   });
 
+  /**
+   * Polyfill HTML5 details element.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.collapse = {
     attach: function (context) {
       if (Modernizr.details) {
diff --git a/core/misc/debounce.js b/core/misc/debounce.js
index 45a5b87358a42cf167af0ec52e5ec0fd99a5c8f6..0239ce6af8e4e9a7244f7e1c49a0f9062318afda 100644
--- a/core/misc/debounce.js
+++ b/core/misc/debounce.js
@@ -1,7 +1,10 @@
 /**
- * Limits the invocations of a function in a given time frame.
- *
+ * @file
  * Adapted from underscore.js with the addition Drupal namespace.
+ */
+
+/**
+ * Limits the invocations of a function in a given time frame.
  *
  * The debounce function wrapper should be used sparingly. One clear use case
  * is limiting the invocation of a callback attached to the window resize event.
@@ -11,13 +14,17 @@
  * function can be written in such a way that it is only invoked under specific
  * conditions.
  *
- * @param {Function} callback
+ * @param {function} func
  *   The function to be invoked.
- *
- * @param {Number} wait
+ * @param {number} wait
  *   The time period within which the callback function should only be
  *   invoked once. For example if the wait period is 250ms, then the callback
  *   will only be called at most 4 times per second.
+ * @param {bool} immediate
+ *   Whether we wait at the beginning or end to execute the function.
+ *
+ * @return {function}
+ *   The debounced function.
  */
 Drupal.debounce = function (func, wait, immediate) {
 
diff --git a/core/misc/details-aria.js b/core/misc/details-aria.js
index b400b4fc7a1c188e0cf85bdbaf86d306e8f8fc96..4de6bdf4f55e2f3a9c01ea6dc08b2a941d583bfd 100644
--- a/core/misc/details-aria.js
+++ b/core/misc/details-aria.js
@@ -7,6 +7,11 @@
 
   "use strict";
 
+  /**
+   * Handles `aria-expanded` and `aria-pressed` attributes on details elements.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.detailsAria = {
     attach: function () {
       $('body').once('detailsAria').on('click.detailsAria', 'summary', function (event) {
diff --git a/core/misc/dialog/dialog.ajax.js b/core/misc/dialog/dialog.ajax.js
index e786d5a16bccf9f7a7b60583d0293241a4bf8172..d70ca70f2633f526a9187e4a264a250a61ec6591 100644
--- a/core/misc/dialog/dialog.ajax.js
+++ b/core/misc/dialog/dialog.ajax.js
@@ -7,6 +7,11 @@
 
   "use strict";
 
+  /**
+   * Initialize dialogs for Ajax purposes.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.dialog = {
     attach: function (context, settings) {
       var $context = $(context);
@@ -46,9 +51,10 @@
     /**
      * Scan a dialog for any primary buttons and move them to the button area.
      *
-     * @param $dialog
+     * @param {jQuery} $dialog
      *   An jQuery object containing the element that is the dialog target.
-     * @return
+     *
+     * @return {Array}
      *   An array of buttons that need to be added to the button area.
      */
     prepareDialogButtons: function ($dialog) {
@@ -81,6 +87,12 @@
 
   /**
    * Command to open a dialog.
+   *
+   * @param {Drupal.Ajax} ajax
+   * @param {object} response
+   * @param {number} [status]
+   *
+   * @return {bool|undefined}
    */
   Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
     if (!response.selector) {
@@ -107,7 +119,7 @@
       response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
     }
 
-    // Bind dialogButtonsChange
+    // Bind dialogButtonsChange.
     $dialog.on('dialogButtonsChange', function () {
       var buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
       $dialog.dialog('option', 'buttons', buttons);
@@ -131,6 +143,12 @@
    * Command to close a dialog.
    *
    * If no selector is given, it defaults to trying to close the modal.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   * @param {object} response
+   * @param {string} response.selector
+   * @param {bool} response.persist
+   * @param {number} [status]
    */
   Drupal.AjaxCommands.prototype.closeDialog = function (ajax, response, status) {
     var $dialog = $(response.selector);
@@ -141,14 +159,21 @@
       }
     }
 
-    // Unbind dialogButtonsChange
+    // Unbind dialogButtonsChange.
     $dialog.off('dialogButtonsChange');
   };
 
   /**
    * Command to set a dialog property.
    *
-   * jQuery UI specific way of setting dialog options.
+   * JQuery UI specific way of setting dialog options.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   * @param {object} response
+   * @param {string} response.selector
+   * @param {string} response.optionsName
+   * @param {string} response.optionValue
+   * @param {number} [status]
    */
   Drupal.AjaxCommands.prototype.setDialogOption = function (ajax, response, status) {
     var $dialog = $(response.selector);
@@ -159,6 +184,11 @@
 
   /**
    * Binds a listener on dialog creation to handle the cancel link.
+   *
+   * @param {jQuery.Event} e
+   * @param {Drupal.dialog~dialogDefinition} dialog
+   * @param {jQuery} $element
+   * @param {object} settings
    */
   $(window).on('dialog:aftercreate', function (e, dialog, $element, settings) {
     $element.on('click.dialog', '.dialog-cancel', function (e) {
@@ -170,6 +200,10 @@
 
   /**
    * Removes all 'dialog' listeners.
+   *
+   * @param {jQuery.Event} e
+   * @param {Drupal.dialog~dialogDefinition} dialog
+   * @param {jQuery} $element
    */
   $(window).on('dialog:beforeclose', function (e, dialog, $element) {
     $element.off('.dialog');
diff --git a/core/misc/dialog/dialog.jquery-ui.js b/core/misc/dialog/dialog.jquery-ui.js
index cd6e863fec588023557f93856b00f3b9298774a4..27fff752ad46f5179f58de8fdf15bed511c6986e 100644
--- a/core/misc/dialog/dialog.jquery-ui.js
+++ b/core/misc/dialog/dialog.jquery-ui.js
@@ -2,6 +2,7 @@
  * @file
  * Adds default classes to buttons for styling purposes.
  */
+
 (function ($) {
 
   "use strict";
diff --git a/core/misc/dialog/dialog.js b/core/misc/dialog/dialog.js
index f63b405bdcabae21b509357db9fe157fd49f1d47..cb7fb9275060821817704fc18149d9f077a8ce8d 100644
--- a/core/misc/dialog/dialog.js
+++ b/core/misc/dialog/dialog.js
@@ -1,30 +1,64 @@
 /**
  * @file
+ * Dialog API inspired by HTML5 dialog element.
  *
- * Dialog API inspired by HTML5 dialog element:
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#the-dialog-element
  */
+
 (function ($, Drupal, drupalSettings) {
 
   "use strict";
 
+  /**
+   * Default dialog options.
+   *
+   * @type {object}
+   *
+   * @prop {bool} [autoOpen=true]
+   * @prop {string} [dialogClass='']
+   * @prop {string} [buttonClass='button']
+   * @prop {string} [buttonPrimaryClass='button--primary']
+   * @prop {function} close
+   */
   drupalSettings.dialog = {
     autoOpen: true,
     dialogClass: '',
     // Drupal-specific extensions: see dialog.jquery-ui.js.
     buttonClass: 'button',
     buttonPrimaryClass: 'button--primary',
-    // When using this API directly (when generating dialogs on the client side),
-    // you may want to override this method and do
-    // @code
-    // jQuery(event.target).remove()
-    // @endcode
-    // as well, to remove the dialog on closing.
+    // When using this API directly (when generating dialogs on the client
+    // side), you may want to override this method and do
+    // `jQuery(event.target).remove()` as well, to remove the dialog on
+    // closing.
     close: function (event) {
       Drupal.detachBehaviors(event.target, null, 'unload');
     }
   };
 
+  /**
+   * @typedef {object} Drupal.dialog~dialogDefinition
+   *
+   * @prop {boolean} open
+   *   Is the dialog open or not.
+   * @prop {*} returnValue
+   *   Return value of the dialog.
+   * @prop {function} show
+   *   Method to display the dialog on the page.
+   * @prop {function} showModal
+   *   Method to display the dialog as a modal on the page.
+   * @prop {function} close
+   *   Method to hide the dialog from the page.
+   */
+
+  /**
+   * Polyfill HTML5 dialog element with jQueryUI.
+   *
+   * @param {HTMLElement} element
+   * @param {object} options
+   *   jQuery UI options to be passed to the dialog.
+   *
+   * @return {Drupal.dialog~dialogDefinition}
+   */
   Drupal.dialog = function (element, options) {
 
     function openDialog(settings) {
diff --git a/core/misc/dialog/dialog.position.js b/core/misc/dialog/dialog.position.js
index 3e08574a6947c0e9e588906861fa449c4dd64f45..a3564778b1c9b619797bfc204586ff6f0bde9439 100644
--- a/core/misc/dialog/dialog.position.js
+++ b/core/misc/dialog/dialog.position.js
@@ -1,3 +1,14 @@
+/**
+ * @file
+ * Positioning extensions for dialogs.
+ */
+
+/**
+ * Triggers when content inside a dialog changes.
+ *
+ * @event dialogContentResize
+ */
+
 (function ($, Drupal, drupalSettings, debounce, displace) {
 
   "use strict";
@@ -11,7 +22,13 @@
    * This is used as a window resize and scroll callback to reposition the
    * jQuery UI dialog. Although not a built-in jQuery UI option, this can
    * be disabled by setting autoResize: false in the options array when creating
-   * a new Drupal.dialog().
+   * a new {@link Drupal.dialog}.
+   *
+   * @function Drupal.dialog~resetSize
+   *
+   * @param {jQuery.Event} event
+   *
+   * @fires event:dialogContentResize
    */
   function resetSize(event) {
     var positionOptions = ['width', 'height', 'minWidth', 'minHeight', 'maxHeight', 'maxWidth', 'position'];
@@ -46,6 +63,12 @@
 
   /**
    * Position the dialog's center at the center of displace.offsets boundaries.
+   *
+   * @function Drupal.dialog~resetPosition
+   *
+   * @param {object} options
+   *
+   * @return {object}
    */
   function resetPosition(options) {
     var offsets = displace.offsets;
diff --git a/core/misc/displace.js b/core/misc/displace.js
index a52a82650ed389abdfbf146dd033badad64673a0..5e21ca12afbd983750b0caf540ed85c68103d86b 100644
--- a/core/misc/displace.js
+++ b/core/misc/displace.js
@@ -1,13 +1,38 @@
 /**
+ * @file
  * Manages elements that can offset the size of the viewport.
  *
  * Measures and reports viewport offset dimensions from elements like the
  * toolbar that can potentially displace the positioning of other elements.
  */
+
+/**
+ * @typedef {object} Drupal~displaceOffset
+ *
+ * @prop {number} top
+ * @prop {number} left
+ * @prop {number} right
+ * @prop {number} bottom
+ */
+
+/**
+ * Triggers when layout of the page changes.
+ *
+ * This is used to position fixed element on the page during page resize and
+ * Toolbar toggling.
+ *
+ * @event drupalViewportOffsetChange
+ */
+
 (function ($, Drupal, debounce) {
 
   "use strict";
 
+  /**
+   * @name Drupal.displace.offsets
+   *
+   * @type {Drupal~displaceOffset}
+   */
   var offsets = {
     top: 0,
     right: 0,
@@ -17,6 +42,8 @@
 
   /**
    * Registers a resize handler on the window.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.drupalDisplace = {
     attach: function () {
@@ -33,14 +60,20 @@
   /**
    * Informs listeners of the current offset dimensions.
    *
-   * @param {boolean} broadcast
-   *   (optional) When true or undefined, causes the recalculated offsets values to be
+   * @function Drupal.displace
+   *
+   * @prop {Drupal~displaceOffset} offsets
+   *
+   * @param {bool} [broadcast]
+   *   When true or undefined, causes the recalculated offsets values to be
    *   broadcast to listeners.
    *
-   * @return {object}
+   * @return {Drupal~displaceOffset}
    *   An object whose keys are the for sides an element -- top, right, bottom
    *   and left. The value of each key is the viewport displacement distance for
    *   that edge.
+   *
+   * @fires event:drupalViewportOffsetChange
    */
   function displace(broadcast) {
     offsets = Drupal.displace.offsets = calculateOffsets();
@@ -53,7 +86,7 @@
   /**
    * Determines the viewport offsets.
    *
-   * @return {object}
+   * @return {Drupal~displaceOffset}
    *   An object whose keys are the for sides an element -- top, right, bottom
    *   and left. The value of each key is the viewport displacement distance for
    *   that edge.
@@ -75,6 +108,8 @@
    * numeric value, that value will be used. If no value is provided, one will
    * be calculated using the element's dimensions and placement.
    *
+   * @function Drupal.displace.calculateOffset
+   *
    * @param {string} edge
    *   The name of the edge to calculate. Can be 'top', 'right',
    *   'bottom' or 'left'.
@@ -111,7 +146,7 @@
   /**
    * Calculates displacement for element based on its dimensions and placement.
    *
-   * @param {jQuery} $el
+   * @param {HTMLElement} el
    *   The jQuery element whose dimensions and placement will be measured.
    *
    * @param {string} edge
@@ -163,15 +198,23 @@
 
   /**
    * Assign the displace function to a property of the Drupal global object.
+   *
+   * @ignore
    */
   Drupal.displace = displace;
   $.extend(Drupal.displace, {
+
     /**
-     * Expose offsets to other scripts to avoid having to recalculate offsets
+     * Expose offsets to other scripts to avoid having to recalculate offsets.
+     *
+     * @ignore
      */
     offsets: offsets,
+
     /**
      * Expose method to compute a single edge offsets.
+     *
+     * @ignore
      */
     calculateOffset: calculateOffset
   });
diff --git a/core/misc/dropbutton/dropbutton.js b/core/misc/dropbutton/dropbutton.js
index eebf354ef9df7944055f472937786247af02b0dc..787cc560e336935612f9416304c85d97b937f3af 100644
--- a/core/misc/dropbutton/dropbutton.js
+++ b/core/misc/dropbutton/dropbutton.js
@@ -1,9 +1,16 @@
+/**
+ * @file
+ * Dropbutton feature.
+ */
+
 (function ($, Drupal) {
 
   "use strict";
 
   /**
    * Process elements with the .dropbutton class on page load.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.dropButton = {
     attach: function (context, settings) {
@@ -25,6 +32,10 @@
 
   /**
    * Delegated callback for opening and closing dropbutton secondary actions.
+   *
+   * @function Drupal.DropButton~dropbuttonClickHandler
+   *
+   * @param {jQuery.Event} e
    */
   function dropbuttonClickHandler(e) {
     e.preventDefault();
@@ -37,21 +48,36 @@
    * All secondary actions beyond the first in the list are presented in a
    * dropdown list accessible through a toggle arrow associated with the button.
    *
-   * @param {jQuery} $dropbutton
-   *   A jQuery element.
+   * @constructor Drupal.DropButton
    *
-   * @param {Object} settings
+   * @param {HTMLElement} dropbutton
+   *   A DOM element.
+   * @param {object} settings
    *   A list of options including:
-   *    - {String} title: The text inside the toggle link element. This text is
-   *      hidden from visual UAs.
+   * @param {string} settings.title
+   *   The text inside the toggle link element. This text is hidden
+   *   from visual UAs.
    */
   function DropButton(dropbutton, settings) {
     // Merge defaults with settings.
     var options = $.extend({'title': Drupal.t('List additional actions')}, settings);
     var $dropbutton = $(dropbutton);
+
+    /**
+     * @type {jQuery}
+     */
     this.$dropbutton = $dropbutton;
+
+    /**
+     * @type {jQuery}
+     */
     this.$list = $dropbutton.find('.dropbutton');
-    // Find actions and mark them.
+
+    /**
+     * Find actions and mark them.
+     *
+     * @type {jQuery}
+     */
     this.$actions = this.$list.find('li').addClass('dropbutton-action');
 
     // Add the special dropdown only if there are hidden actions.
@@ -67,18 +93,31 @@
       this.$dropbutton
         .addClass('dropbutton-multiple')
         .on({
+
           /**
            * Adds a timeout to close the dropdown on mouseleave.
+           *
+           * @ignore
            */
           'mouseleave.dropbutton': $.proxy(this.hoverOut, this),
+
           /**
            * Clears timeout when mouseout of the dropdown.
+           *
+           * @ignore
            */
           'mouseenter.dropbutton': $.proxy(this.hoverIn, this),
+
           /**
            * Similar to mouseleave/mouseenter, but for keyboard navigation.
+           *
+           * @ignore
            */
           'focusout.dropbutton': $.proxy(this.focusOut, this),
+
+          /**
+           * @ignore
+           */
           'focusin.dropbutton': $.proxy(this.focusIn, this)
         });
     }
@@ -90,11 +129,11 @@
   /**
    * Extend the DropButton constructor.
    */
-  $.extend(DropButton, {
+  $.extend(DropButton, /** @lends Drupal.DropButton */{
     /**
      * Store all processed DropButtons.
      *
-     * @type {Array}
+     * @type {Array.<Drupal.DropButton>}
      */
     dropbuttons: []
   });
@@ -102,12 +141,13 @@
   /**
    * Extend the DropButton prototype.
    */
-  $.extend(DropButton.prototype, {
+  $.extend(DropButton.prototype, /** @lends Drupal.DropButton# */{
+
     /**
      * Toggle the dropbutton open and closed.
      *
-     * @param {Boolean} show
-     *   (optional) Force the dropbutton to open by passing true or to close by
+     * @param {bool} [show]
+     *   Force the dropbutton to open by passing true or to close by
      *   passing false.
      */
     toggle: function (show) {
@@ -116,6 +156,9 @@
       this.$dropbutton.toggleClass('open', show);
     },
 
+    /**
+     * @method
+     */
     hoverIn: function () {
       // Clear any previous timer we were using.
       if (this.timerID) {
@@ -123,37 +166,53 @@
       }
     },
 
+    /**
+     * @method
+     */
     hoverOut: function () {
       // Wait half a second before closing.
       this.timerID = window.setTimeout($.proxy(this, 'close'), 500);
     },
 
+    /**
+     * @method
+     */
     open: function () {
       this.toggle(true);
     },
 
+    /**
+     * @method
+     */
     close: function () {
       this.toggle(false);
     },
 
+    /**
+     * @param {jQuery.Event} e
+     */
     focusOut: function (e) {
       this.hoverOut.call(this, e);
     },
 
+    /**
+     * @param {jQuery.Event} e
+     */
     focusIn: function (e) {
       this.hoverIn.call(this, e);
     }
   });
 
-  $.extend(Drupal.theme, {
+  $.extend(Drupal.theme, /** @lends Drupal.theme */{
+
     /**
      * A toggle is an interactive element often bound to a click handler.
      *
-     * @param {Object} options
-     *   - {String} title: (optional) The HTML anchor title attribute and
-     *     text for the inner span element.
+     * @param {object} options
+     * @param {string} [options.title]
+     *   The HTML anchor title attribute and text for the inner span element.
      *
-     * @return {String}
+     * @return {string}
      *   A string representing a DOM fragment.
      */
     dropbuttonToggle: function (options) {
diff --git a/core/misc/drupal.js b/core/misc/drupal.js
index 9e9d24e0438cfe1f326094c64b8b5c0e973c3163..75f85bbacdef78ec093c713a3aa96c32c13caf30 100644
--- a/core/misc/drupal.js
+++ b/core/misc/drupal.js
@@ -1,7 +1,40 @@
 /**
- * Base framework for Drupal-specific JavaScript, behaviors, and settings.
+ * @file
+ * Defines the Drupal JS API.
  */
-window.Drupal = {behaviors: {}};
+
+/**
+ * A jQuery object.
+ *
+ * @typedef {object} jQuery
+ *
+ * @prop {number} length=0
+ */
+
+/**
+ * Variable generated by Drupal with all the configuration created from PHP.
+ *
+ * @global
+ *
+ * @var {object} drupalSettings
+ */
+
+/**
+ * Variable generated by Drupal that holds all translated strings from PHP.
+ *
+ * @global
+ *
+ * @var {object} drupalTranslations
+ */
+
+/**
+ * Global Drupal object.
+ *
+ * @global
+ *
+ * @namespace
+ */
+window.Drupal = {behaviors: {}, locale: {}};
 
 // Class indicating that JS is enabled; used for styling purpose.
 document.documentElement.className += ' js';
@@ -18,16 +51,43 @@ if (window.jQuery) {
   "use strict";
 
   /**
-   * Custom error type thrown after attach/detach if one or more behaviors failed.
+   * Custom error type thrown after attach/detach if one or more behaviors
+   * failed.
+   *
+   * @memberof Drupal
    *
-   * @param list
+   * @constructor
+   *
+   * @augments Error
+   *
+   * @param {Array} list
    *   An array of errors thrown during attach/detach.
-   * @param event
+   * @param {string} event
    *   A string containing either 'attach' or 'detach'.
+   *
+   * @inner
    */
   function DrupalBehaviorError(list, event) {
+
+    /**
+     * Setting name helps debuggers.
+     *
+     * @type {string}
+     */
     this.name = 'DrupalBehaviorError';
+
+    /**
+     * Execution phase errors were triggered.
+     *
+     * @type {string}
+     */
     this.event = event || 'attach';
+
+    /**
+     * All thrown errors.
+     *
+     * @type {Array.<Error>}
+     */
     this.list = list;
     // Makes the list of errors readable.
     var messageList = [];
@@ -36,48 +96,100 @@ if (window.jQuery) {
     for (var i = 0; i < il; i++) {
       messageList.push(this.list[i].behavior + ': ' + this.list[i].error.message);
     }
+
+    /**
+     * Final message to send to debuggers.
+     *
+     * @type {string}
+     */
     this.message = messageList.join(' ; ');
   }
 
   DrupalBehaviorError.prototype = new Error();
 
+  /**
+   * Callback function initializing code run on page load and Ajax requests.
+   *
+   * @callback Drupal~behaviorAttach
+   *
+   * @param {HTMLElement} context
+   * @param {object} settings
+   *
+   * @see Drupal.attachBehaviors
+   */
+
+  /**
+   * Callback function for reverting and cleaning up behavior initialization.
+   *
+   * @callback Drupal~behaviorDetach
+   *
+   * @param {HTMLElement} context
+   * @param {object} settings
+   * @param {string} trigger
+   *   One of 'unload', 'serialize' or 'move'.
+   *
+   * @see Drupal.detachBehaviors
+   */
+
+  /**
+   * @typedef {object} Drupal~behavior
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Function run on page load and after an AJAX call.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Function run when content is serialized or removed from the page.
+   */
+
+  /**
+   * Holds all initialization methods.
+   *
+   * @namespace Drupal.behaviors
+   *
+   * @type {Object.<string, Drupal~behavior>}
+   */
+
   /**
    * Attach all registered behaviors to a page element.
    *
-   * Behaviors are event-triggered actions that attach to page elements, enhancing
-   * default non-JavaScript UIs. Behaviors are registered in the Drupal.behaviors
-   * object using the method 'attach' and optionally also 'detach' as follows:
-   * @code
-   *    Drupal.behaviors.behaviorName = {
-   *      attach: function (context, settings) {
-   *        ...
-   *      },
-   *      detach: function (context, settings, trigger) {
-   *        ...
-   *      }
-   *    };
-   * @endcode
-   *
-   * Drupal.attachBehaviors is added below to the jQuery.ready event and therefore
-   * runs on initial page load. Developers implementing Ajax in their solutions
-   * should also call this function after new page content has been loaded,
-   * feeding in an element to be processed, in order to attach all behaviors to
-   * the new content.
+   * Behaviors are event-triggered actions that attach to page elements,
+   * enhancing default non-JavaScript UIs. Behaviors are registered in the
+   * {@link Drupal.behaviors} object using the method 'attach' and optionally
+   * also 'detach' as follows:
+   *
+   * {@link Drupal.attachBehaviors} is added below to the jQuery.ready event and
+   * therefore runs on initial page load. Developers implementing Ajax in their
+   * solutions should also call this function after new page content has been
+   * loaded, feeding in an element to be processed, in order to attach all
+   * behaviors to the new content.
    *
    * Behaviors should use
-   * @code
-   *   var elements = $(context).find(selector).once('behavior-name');
-   * @endcode
+   *     `var elements = $(context).find(selector).once('behavior-name');`
    * to ensure the behavior is attached only once to a given element. (Doing so
-   * enables the reprocessing of given elements, which may be needed on occasion
-   * despite the ability to limit behavior attachment to a particular element.)
+   * enables the reprocessing of given elements, which may be needed on
+   * occasion despite the ability to limit behavior attachment to a particular
+   * element.)
+   *
+   * @example
+   * Drupal.behaviors.behaviorName = {
+   *   attach: function (context, settings) {
+   *     ...
+   *   },
+   *   detach: function (context, settings, trigger) {
+   *     ...
+   *   }
+   * };
    *
-   * @param context
-   *   An element to attach behaviors to. If none is given, the document element
-   *   is used.
-   * @param settings
+   * @param {Element} context
+   *   An element to attach behaviors to. If none is given, the document
+   *   element is used.
+   * @param {object} settings
    *   An object containing settings for the current context. If none is given,
    *   the global drupalSettings object is used.
+   *
+   * @see Drupal~behaviorAttach
+   * @see Drupal.detachBehaviors
+   *
+   * @throws {Drupal~DrupalBehaviorError}
    */
   Drupal.attachBehaviors = function (context, settings) {
     context = context || document;
@@ -115,22 +227,22 @@ if (window.jQuery) {
    *
    * Such implementations should use .findOnce() and .removeOnce() to find
    * elements with their corresponding Drupal.behaviors.behaviorName.attach
-   * implementation, i.e. .removeOnce('behaviorName'), to ensure the behavior is
-   * detached only from previously processed elements.
-   *
-   * @param context
-   *   An element to detach behaviors from. If none is given, the document element
-   *   is used.
-   * @param settings
-   *   An object containing settings for the current context. If none given, the
-   *   global drupalSettings object is used.
-   * @param trigger
+   * implementation, i.e. .removeOnce('behaviorName'), to ensure the behavior
+   * is detached only from previously processed elements.
+   *
+   * @param {Element} context
+   *   An element to detach behaviors from. If none is given, the document
+   *   element is used.
+   * @param {object} settings
+   *   An object containing settings for the current context. If none given,
+   *   the global drupalSettings object is used.
+   * @param {string} trigger
    *   A string containing what's causing the behaviors to be detached. The
    *   possible triggers are:
    *   - unload: (default) The context element is being removed from the DOM.
    *   - move: The element is about to be moved within the DOM (for example,
    *     during a tabledrag row swap). After the move is completed,
-   *     Drupal.attachBehaviors() is called, so that the behavior can undo
+   *     {@link Drupal.attachBehaviors} is called, so that the behavior can undo
    *     whatever it did in response to the move. Many behaviors won't need to
    *     do anything simply in response to the element being moved, but because
    *     IFRAME elements reload their "src" when being moved within the DOM,
@@ -143,6 +255,9 @@ if (window.jQuery) {
    *     that WYSIWYG editors can update the hidden textarea to which they are
    *     bound.
    *
+   * @throws {Drupal~DrupalBehaviorError}
+   *
+   * @see Drupal~behaviorDetach
    * @see Drupal.attachBehaviors
    */
   Drupal.detachBehaviors = function (context, settings, trigger) {
@@ -171,7 +286,12 @@ if (window.jQuery) {
 
   /**
    * Helper to test document width for mobile configurations.
-   * @todo Temporary solution for the mobile initiative.
+   *
+   * @param {number} [width=640]
+   *
+   * @return {bool}
+   *
+   * @deprecated Temporary solution for the mobile initiative.
    */
   Drupal.checkWidthBreakpoint = function (width) {
     width = width || drupalSettings.widthBreakpoint || 640;
@@ -181,10 +301,12 @@ if (window.jQuery) {
   /**
    * Encode special characters in a plain-text string for display as HTML.
    *
-   * @param str
+   * @param {string} str
    *   The string to be encoded.
-   * @return
+   *
+   * @return {string}
    *   The encoded string.
+   *
    * @ingroup sanitization
    */
   Drupal.checkPlain = function (str) {
@@ -199,22 +321,21 @@ if (window.jQuery) {
   /**
    * Replace placeholders with sanitized values in a string.
    *
-   * @param {String} str
+   * @param {string} str
    *   A string with placeholders.
-   * @param {Object} args
+   * @param {object} args
    *   An object of replacements pairs to make. Incidences of any key in this
    *   array are replaced with the corresponding value. Based on the first
    *   character of the key, the value is escaped and/or themed:
    *    - !variable: inserted as is
-   *    - @variable: escape plain text to HTML (Drupal.checkPlain)
+   *    - @variable: escape plain text to HTML ({@link Drupal.checkPlain})
    *    - %variable: escape text and theme as a placeholder for user-submitted
-   *      content (checkPlain + Drupal.theme('placeholder'))
+   *      content ({@link Drupal.checkPlain} +
+   *      {@link Drupal.theme}('placeholder'))
    *
-   * @return {String}
-   *   Returns the replaced string.
+   * @return {string}
    *
-   * @see Drupal.t()
-   * @ingroup sanitization
+   * @see Drupal.t
    */
   Drupal.formatString = function (str, args) {
     // Keep args intact.
@@ -227,10 +348,12 @@ if (window.jQuery) {
           case '@':
             processedArgs[key] = Drupal.checkPlain(args[key]);
             break;
+
           // Pass-through.
           case '!':
             processedArgs[key] = args[key];
             break;
+
           // Escaped and placeholder.
           default:
             processedArgs[key] = Drupal.theme('placeholder', args[key]);
@@ -248,14 +371,14 @@ if (window.jQuery) {
    * The longest keys will be tried first. Once a substring has been replaced,
    * its new value will not be searched again.
    *
-   * @param {String} str
+   * @param {string} str
    *   A string with placeholders.
-   * @param {Object} args
+   * @param {object} args
    *   Key-value pairs.
    * @param {Array|null} keys
    *   Array of keys from the "args".  Internal use only.
    *
-   * @return {String}
+   * @return {string}
    *   Returns the replaced string.
    */
   Drupal.stringReplace = function (str, args, keys) {
@@ -299,18 +422,17 @@ if (window.jQuery) {
    *
    * See the documentation of the server-side t() function for further details.
    *
-   * @param str
+   * @param {string} str
    *   A string containing the English string to translate.
-   * @param args
+   * @param {Object.<string, string>} [args]
    *   An object of replacements pairs to make after translation. Incidences
    *   of any key in this array are replaced with the corresponding value.
-   *   See Drupal.formatString().
+   *   See {@link Drupal.formatString}.
+   * @param {object} [options]
+   * @param {string} [options.context='']
+   *   The context the source string belongs to.
    *
-   * @param options
-   *   - 'context' (defaults to the empty context): The context the source string
-   *     belongs to.
-   *
-   * @return
+   * @return {string}
    *   The translated string.
    */
   Drupal.t = function (str, args, options) {
@@ -330,6 +452,11 @@ if (window.jQuery) {
 
   /**
    * Returns the URL to a Drupal page.
+   *
+   * @param {string} path
+   *   Drupal path to transform to URL.
+   *
+   * @return {string}
    */
   Drupal.url = function (path) {
     return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
@@ -339,33 +466,33 @@ if (window.jQuery) {
    * Format a string containing a count of items.
    *
    * This function ensures that the string is pluralized correctly. Since
-   * Drupal.t() is called by this function, make sure not to pass
+   * {@link Drupal.t} is called by this function, make sure not to pass
    * already-localized strings to it.
    *
    * See the documentation of the server-side
    * \Drupal\Core\StringTranslation\TranslationInterface::formatPlural()
    * function for more details.
    *
-   * @param {Number} count
+   * @param {number} count
    *   The item count to display.
-   * @param {String} singular
+   * @param {string} singular
    *   The string for the singular case. Please make sure it is clear this is
    *   singular, to ease translation (e.g. use "1 new comment" instead of "1
    *   new"). Do not use @count in the singular string.
-   * @param {String} plural
+   * @param {string} plural
    *   The string for the plural case. Please make sure it is clear this is
    *   plural, to ease translation. Use @count in place of the item count, as in
    *   "@count new comments".
-   * @param {Object} args
+   * @param {object} [args]
    *   An object of replacements pairs to make after translation. Incidences
    *   of any key in this array are replaced with the corresponding value.
-   *   See Drupal.formatString().
+   *   See {@link Drupal.formatString}.
    *   Note that you do not need to include @count in this array.
    *   This replacement is done automatically for the plural case.
-   * @param {Object} options
-   *   The options to pass to the Drupal.t() function.
+   * @param {object} [options]
+   *   The options to pass to the {@link Drupal.t} function.
    *
-   * @return {String}
+   * @return {string}
    *   A translated string.
    */
   Drupal.formatPlural = function (count, singular, plural, args, options) {
@@ -391,6 +518,11 @@ if (window.jQuery) {
    * Encodes a Drupal path for use in a URL.
    *
    * For aesthetic reasons slashes are not escaped.
+   *
+   * @param {string} item
+   *   Unencoded path.
+   *
+   * @return {string}
    */
   Drupal.encodePath = function (item) {
     return window.encodeURIComponent(item).replace(/%2F/g, '/');
@@ -406,13 +538,16 @@ if (window.jQuery) {
    *
    * For example, to retrieve the HTML for text that should be emphasized and
    * displayed as a placeholder inside a sentence, call
-   * Drupal.theme('placeholder', text).
+   * `Drupal.theme('placeholder', text)`.
+   *
+   * @namespace
    *
-   * @param func
+   * @param {function} func
    *   The name of the theme function to call.
-   * @param ...
+   * @param {...args}
    *   Additional arguments to pass along to the theme function.
-   * @return
+   *
+   * @return {string|object|HTMLElement|jQuery}
    *   Any data the theme function returns. This could be a plain HTML string,
    *   but also a complex object.
    */
@@ -426,9 +561,10 @@ if (window.jQuery) {
   /**
    * Formats text for emphasized display in a placeholder inside a sentence.
    *
-   * @param str
+   * @param {string} str
    *   The text to format (plain-text).
-   * @return
+   *
+   * @return {string}
    *   The formatted text (html).
    */
   Drupal.theme.placeholder = function (str) {
diff --git a/core/misc/form.js b/core/misc/form.js
index 68b4e9e16723cc89655a7561080c31d092f506a9..7210be5d34ab951c9726aeac5f45eceb6255e54e 100644
--- a/core/misc/form.js
+++ b/core/misc/form.js
@@ -1,9 +1,25 @@
+/**
+ * @file
+ * Form features.
+ */
+
+/**
+ * Triggers when a value in the form changed.
+ *
+ * The event triggers when content is typed or pasted in a text field, before
+ * the change event triggers.
+ *
+ * @event formUpdated
+ */
+
 (function ($, Drupal, debounce) {
 
   "use strict";
 
   /**
    * Retrieves the summary for the first element.
+   *
+   * @return {string}
    */
   $.fn.drupalGetSummary = function () {
     var callback = this.data('summaryCallback');
@@ -13,9 +29,15 @@
   /**
    * Sets the summary for all matched elements.
    *
-   * @param callback
+   * @param {function} callback
    *   Either a function that will be called each time the summary is
    *   retrieved or a string (which is returned each time).
+   *
+   * @return {jQuery}
+   *
+   * @fires event:summaryUpdated
+   *
+   * @listens event:formUpdated
    */
   $.fn.drupalSetSummary = function (callback) {
     var self = this;
@@ -43,13 +65,13 @@
   /**
    * Prevents consecutive form submissions of identical form values.
    *
-   * Repetitive form submissions that would submit the identical form values are
-   * prevented, unless the form values are different to the previously submitted
-   * values.
+   * Repetitive form submissions that would submit the identical form values
+   * are prevented, unless the form values are different to the previously
+   * submitted values.
    *
-   * This is a simplified re-implementation of a user-agent behavior that should
-   * be natively supported by major web browsers, but at this time, only Firefox
-   * has a built-in protection.
+   * This is a simplified re-implementation of a user-agent behavior that
+   * should be natively supported by major web browsers, but at this time, only
+   * Firefox has a built-in protection.
    *
    * A form value-based approach ensures that the constraint is triggered for
    * consecutive, identical form submissions only. Compared to that, a form
@@ -57,26 +79,28 @@
    * technically not required and (2) require more complex state management if
    * there are multiple buttons in a form.
    *
-   * This implementation is based on form-level submit events only and relies on
-   * jQuery's serialize() method to determine submitted form values. As such, the
-   * following limitations exist:
+   * This implementation is based on form-level submit events only and relies
+   * on jQuery's serialize() method to determine submitted form values. As such,
+   * the following limitations exist:
    *
    * - Event handlers on form buttons that preventDefault() do not receive a
    *   double-submit protection. That is deemed to be fine, since such button
-   *   events typically trigger reversible client-side or server-side operations
-   *   that are local to the context of a form only.
-   * - Changed values in advanced form controls, such as file inputs, are not part
-   *   of the form values being compared between consecutive form submits (due to
-   *   limitations of jQuery.serialize()). That is deemed to be acceptable,
-   *   because if the user forgot to attach a file, then the size of HTTP payload
-   *   will most likely be small enough to be fully passed to the server endpoint
-   *   within (milli)seconds. If a user mistakenly attached a wrong file and is
-   *   technically versed enough to cancel the form submission (and HTTP payload)
-   *   in order to attach a different file, then that edge-case is not supported
-   *   here.
-   *
-   * Lastly, all forms submitted via HTTP GET are idempotent by definition of HTTP
-   * standards, so excluded in this implementation.
+   *   events typically trigger reversible client-side or server-side
+   *   operations that are local to the context of a form only.
+   * - Changed values in advanced form controls, such as file inputs, are not
+   *   part of the form values being compared between consecutive form submits
+   *   (due to limitations of jQuery.serialize()). That is deemed to be
+   *   acceptable, because if the user forgot to attach a file, then the size of
+   *   HTTP payload will most likely be small enough to be fully passed to the
+   *   server endpoint within (milli)seconds. If a user mistakenly attached a
+   *   wrong file and is technically versed enough to cancel the form submission
+   *   (and HTTP payload) in order to attach a different file, then that
+   *   edge-case is not supported here.
+   *
+   * Lastly, all forms submitted via HTTP GET are idempotent by definition of
+   * HTTP standards, so excluded in this implementation.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.formSingleSubmit = {
     attach: function () {
@@ -99,6 +123,10 @@
 
   /**
    * Sends a 'formUpdated' event each time a form element is modified.
+   *
+   * @param {HTMLElement} element
+   *
+   * @fires event:formUpdated
    */
   function triggerFormUpdated(element) {
     $(element).trigger('formUpdated');
@@ -108,6 +136,7 @@
    * Collects the IDs of all form fields in the given form.
    *
    * @param {HTMLFormElement} form
+   *
    * @return {Array}
    */
   function fieldsList(form) {
@@ -122,6 +151,10 @@
 
   /**
    * Triggers the 'formUpdated' event on form elements when they are modified.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @fires event:formUpdated
    */
   Drupal.behaviors.formUpdated = {
     attach: function (context) {
@@ -132,7 +165,8 @@
 
       if ($forms.length) {
         // Initialize form behaviors, use $.makeArray to be able to use native
-        // forEach array method and have the callback parameters in the right order.
+        // forEach array method and have the callback parameters in the right
+        // order.
         $.makeArray($forms).forEach(function (form) {
           var events = 'change.formUpdated input.formUpdated ';
           var eventHandler = debounce(function (event) { triggerFormUpdated(event.target); }, 300);
@@ -147,7 +181,7 @@
         formFields = fieldsList(context).join(',');
         // @todo replace with form.getAttribute() when #1979468 is in.
         var currentFields = $(context).attr('data-drupal-form-fields');
-        // if there has been a change in the fields or their order, trigger
+        // If there has been a change in the fields or their order, trigger
         // formUpdated.
         if (formFields !== currentFields) {
           triggerFormUpdated(context);
@@ -172,6 +206,8 @@
 
   /**
    * Prepopulate form fields with information from the visitor browser.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.fillUserInfoFromBrowser = {
     attach: function (context, settings) {
diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js
index 13e0034f2e9d71ec0437b936bcd190559155a0cc..2b304bf87a2290140e9c8b1d31b213bcd858da86 100644
--- a/core/misc/machine-name.js
+++ b/core/misc/machine-name.js
@@ -1,28 +1,39 @@
+/**
+ * @file
+ * Machine name functionality.
+ */
+
 (function ($, Drupal, drupalSettings) {
 
   "use strict";
 
   /**
    * Attach the machine-readable name form element behavior.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.machineName = {
+
     /**
      * Attaches the behavior.
      *
-     * @param settings.machineName
-     *   A list of elements to process, keyed by the HTML ID of the form element
-     *   containing the human-readable value. Each element is an object defining
-     *   the following properties:
+     * @param {Element} context
+     * @param {object} settings
+     * @param {object} settings.machineName
+     *   A list of elements to process, keyed by the HTML ID of the form
+     *   element containing the human-readable value. Each element is an object
+     *   defining the following properties:
      *   - target: The HTML ID of the machine name form element.
-     *   - suffix: The HTML ID of a container to show the machine name preview in
-     *     (usually a field suffix after the human-readable name form element).
+     *   - suffix: The HTML ID of a container to show the machine name preview
+     *     in (usually a field suffix after the human-readable name
+     *     form element).
      *   - label: The label to show for the machine name preview.
      *   - replace_pattern: A regular expression (without modifiers) matching
      *     disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
-     *   - replace: A character to replace disallowed characters with; e.g., '_'
-     *     or '-'.
-     *   - standalone: Whether the preview should stay in its own element rather
-     *     than the suffix of the source element.
+     *   - replace: A character to replace disallowed characters with; e.g.,
+     *     '_' or '-'.
+     *   - standalone: Whether the preview should stay in its own element
+     *     rather than the suffix of the source element.
      *   - field_prefix: The #field_prefix of the form element.
      *   - field_suffix: The #field_suffix of the form element.
      */
@@ -94,9 +105,9 @@
         options.maxlength = $target.attr('maxlength');
         // Hide the form item container of the machine name form element.
         $wrapper.addClass('visually-hidden');
-        // Determine the initial machine name value. Unless the machine name form
-        // element is disabled or not empty, the initial default value is based on
-        // the human-readable form element value.
+        // Determine the initial machine name value. Unless the machine name
+        // form element is disabled or not empty, the initial default value is
+        // based on the human-readable form element value.
         if ($target.is(':disabled') || $target.val() !== '') {
           machine = $target.val();
         }
@@ -163,17 +174,19 @@
     /**
      * Transliterate a human-readable name to a machine name.
      *
-     * @param source
+     * @param {string} source
      *   A string to transliterate.
-     * @param settings
-     *   The machine name settings for the corresponding field, containing:
-     *   - replace_pattern: A regular expression (without modifiers) matching
-     *     disallowed characters in the machine name; e.g., '[^a-z0-9]+'.
-     *   - replace: A character to replace disallowed characters with; e.g., '_'
-     *     or '-'.
-     *   - maxlength: The maximum length of the machine name.
+     * @param {object} settings
+     *   The machine name settings for the corresponding field.
+     * @param {string} settings.replace_pattern
+     *   A regular expression (without modifiers) matching disallowed characters
+     *   in the machine name; e.g., '[^a-z0-9]+'.
+     * @param {string} settings.replace
+     *   A character to replace disallowed characters with; e.g., '_' or '-'.
+     * @param {number} settings.maxlength
+     *   The maximum length of the machine name.
      *
-     * @return
+     * @return {jQuery}
      *   The transliterated source string.
      */
     transliterate: function (source, settings) {
diff --git a/core/misc/progress.js b/core/misc/progress.js
index e3d1223d0b187cb0c71f6ddf8d4f25b422eb2976..fdfd3b69b966ae57cccbf970f7e12123e201dab0 100644
--- a/core/misc/progress.js
+++ b/core/misc/progress.js
@@ -1,3 +1,8 @@
+/**
+ * @file
+ * Progress bar.
+ */
+
 (function ($, Drupal) {
 
   "use strict";
@@ -5,7 +10,9 @@
   /**
    * Theme function for the progress bar.
    *
-   * @return
+   * @param {string} id
+   *
+   * @return {string}
    *   The HTML for the progress bar.
    */
   Drupal.theme.progressBar = function (id) {
@@ -21,11 +28,19 @@
    * A progressbar object. Initialized with the given id. Must be inserted into
    * the DOM afterwards through progressBar.element.
    *
-   * method is the function which will perform the HTTP request to get the
+   * Method is the function which will perform the HTTP request to get the
    * progress bar state. Either "GET" or "POST".
    *
-   * e.g. pb = new Drupal.ProgressBar('myProgressBar');
-   *      some_element.appendChild(pb.element);
+   * @example
+   * pb = new Drupal.ProgressBar('myProgressBar');
+   * some_element.appendChild(pb.element);
+   *
+   * @constructor
+   *
+   * @param {string} id
+   * @param {function} updateCallback
+   * @param {string} method
+   * @param {function} errorCallback
    */
   Drupal.ProgressBar = function (id, updateCallback, method, errorCallback) {
     this.id = id;
@@ -33,14 +48,21 @@
     this.updateCallback = updateCallback;
     this.errorCallback = errorCallback;
 
-    // The WAI-ARIA setting aria-live="polite" will announce changes after users
-    // have completed their current activity and not interrupt the screen reader.
+    // The WAI-ARIA setting aria-live="polite" will announce changes after
+    // users
+    // have completed their current activity and not interrupt the screen
+    // reader.
     this.element = $(Drupal.theme('progressBar', id));
   };
 
-  $.extend(Drupal.ProgressBar.prototype, {
+  $.extend(Drupal.ProgressBar.prototype, /** @lends Drupal.ProgressBar# */{
+
     /**
      * Set the percentage and status message for the progressbar.
+     *
+     * @param {number} percentage
+     * @param {string} message
+     * @param {string} label
      */
     setProgress: function (percentage, message, label) {
       if (percentage >= 0 && percentage <= 100) {
@@ -56,6 +78,9 @@
 
     /**
      * Start monitoring progress via Ajax.
+     *
+     * @param {string} uri
+     * @param {number} delay
      */
     startMonitoring: function (uri, delay) {
       this.delay = delay;
@@ -116,6 +141,8 @@
 
     /**
      * Display errors on the page.
+     *
+     * @param {string} string
      */
     displayError: function (string) {
       var error = $('<div class="messages messages--error"></div>').html(string);
diff --git a/core/misc/states.js b/core/misc/states.js
index b969da76dfb4695b43cdd2088cf089e79804f0f8..3a67aeaae71cd02a373056fc2d460a01e999e052 100644
--- a/core/misc/states.js
+++ b/core/misc/states.js
@@ -1,6 +1,8 @@
 /**
+ * @file
  * Drupal's states library.
  */
+
 (function ($) {
 
   "use strict";
@@ -10,14 +12,21 @@
    *
    * Having the local states variable allows us to use the States namespace
    * without having to always declare "Drupal.states".
+   *
+   * @namespace Drupal.states
    */
   var states = Drupal.states = {
-    // An array of functions that should be postponed.
+
+    /**
+     * An array of functions that should be postponed.
+     */
     postponed: []
   };
 
   /**
    * Attaches the states.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.states = {
     attach: function (context, settings) {
@@ -48,13 +57,18 @@
   /**
    * Object representing an element that depends on other elements.
    *
-   * @param args
-   *   Object with the following keys (all of which are required):
-   *   - element: A jQuery object of the dependent element
-   *   - state: A State object describing the state that is dependent
-   *   - constraints: An object with dependency specifications. Lists all elements
-   *     that this element depends on. It can be nested and can contain arbitrary
-   *     AND and OR clauses.
+   * @constructor Drupal.states.Dependent
+   *
+   * @param {object} args
+   *   Object with the following keys (all of which are required)
+   * @param {jQuery} args.element
+   *   A jQuery object of the dependent element
+   * @param {Drupal.states.State} args.state
+   *   A State object describing the state that is dependent
+   * @param {object} args.constraints
+   *   An object with dependency specifications. Lists all elements that this
+   *   element depends on. It can be nested and can contain
+   *   arbitrary AND and OR clauses.
    */
   states.Dependent = function (args) {
     $.extend(this, {values: {}, oldValue: null}, args);
@@ -71,6 +85,12 @@
    * Comparison functions for comparing the value of an element with the
    * specification from the dependency settings. If the object type can't be
    * found in this list, the === operator is used by default.
+   *
+   * @name Drupal.states.Dependent.comparisons
+   *
+   * @prop {function} RegExp
+   * @prop {function} Function
+   * @prop {function} Number
    */
   states.Dependent.comparisons = {
     'RegExp': function (reference, value) {
@@ -81,21 +101,25 @@
       return reference(value);
     },
     'Number': function (reference, value) {
-      // If "reference" is a number and "value" is a string, then cast reference
-      // as a string before applying the strict comparison in compare(). Otherwise
-      // numeric keys in the form's #states array fail to match string values
-      // returned from jQuery's val().
+      // If "reference" is a number and "value" is a string, then cast
+      // reference as a string before applying the strict comparison in
+      // compare().
+      // Otherwise numeric keys in the form's #states array fail to match
+      // string values returned from jQuery's val().
       return (typeof value === 'string') ? compare(reference.toString(), value) : compare(reference, value);
     }
   };
 
   states.Dependent.prototype = {
+
     /**
      * Initializes one of the elements this dependent depends on.
      *
-     * @param selector
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {string} selector
      *   The CSS selector describing the dependee.
-     * @param dependeeStates
+     * @param {object} dependeeStates
      *   The list of states that have to be monitored for tracking the
      *   dependee's compliance status.
      */
@@ -113,7 +137,8 @@
       for (var i in dependeeStates) {
         if (dependeeStates.hasOwnProperty(i)) {
           state = dependeeStates[i];
-          // Make sure we're not initializing this selector/state combination twice.
+          // Make sure we're not initializing this selector/state combination
+          // twice.
           if ($.inArray(state, dependeeStates) === -1) {
             continue;
           }
@@ -135,14 +160,16 @@
     /**
      * Compares a value with a reference value.
      *
-     * @param reference
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {object} reference
      *   The value used for reference.
-     * @param selector
+     * @param {string} selector
      *   CSS selector describing the dependee.
-     * @param state
+     * @param {Drupal.states.State} state
      *   A State object describing the dependee's updated state.
      *
-     * @return
+     * @return {bool}
      *   true or false.
      */
     compare: function (reference, selector, state) {
@@ -160,11 +187,13 @@
     /**
      * Update the value of a dependee's state.
      *
-     * @param selector
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {string} selector
      *   CSS selector describing the dependee.
-     * @param state
+     * @param {Drupal.states.state} state
      *   A State object describing the dependee's updated state.
-     * @param value
+     * @param {string} value
      *   The new value for the dependee's updated state.
      */
     update: function (selector, state, value) {
@@ -177,6 +206,8 @@
 
     /**
      * Triggers change events in case a state changed.
+     *
+     * @memberof Drupal.states.Dependent#
      */
     reevaluate: function () {
       // Check whether any constraint for this dependent state is satisfied.
@@ -200,14 +231,16 @@
     /**
      * Evaluates child constraints to determine if a constraint is satisfied.
      *
-     * @param constraints
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {object|Array} constraints
      *   A constraint object or an array of constraints.
-     * @param selector
+     * @param {string} selector
      *   The selector for these constraints. If undefined, there isn't yet a
      *   selector that these constraints apply to. In that case, the keys of the
      *   object are interpreted as the selector if encountered.
      *
-     * @return
+     * @return {bool}
      *   true or false, depending on whether these constraints are satisfied.
      */
     verifyConstraints: function (constraints, selector) {
@@ -219,8 +252,8 @@
         for (var i = 0; i < len; i++) {
           if (constraints[i] !== 'xor') {
             var constraint = this.checkConstraints(constraints[i], selector, i);
-            // Return if this is OR and we have a satisfied constraint or if this
-            // is XOR and we have a second satisfied constraint.
+            // Return if this is OR and we have a satisfied constraint or if
+            // this is XOR and we have a second satisfied constraint.
             if (constraint && (hasXor || result)) {
               return hasXor;
             }
@@ -229,15 +262,15 @@
         }
       }
       // Make sure we don't try to iterate over things other than objects. This
-      // shouldn't normally occur, but in case the condition definition is bogus,
-      // we don't want to end up with an infinite loop.
+      // shouldn't normally occur, but in case the condition definition is
+      // bogus, we don't want to end up with an infinite loop.
       else if ($.isPlainObject(constraints)) {
         // This constraint is an object (AND).
         for (var n in constraints) {
           if (constraints.hasOwnProperty(n)) {
             result = ternary(result, this.checkConstraints(constraints[n], selector, n));
-            // False and anything else will evaluate to false, so return when any
-            // false condition is found.
+            // False and anything else will evaluate to false, so return when
+            // any false condition is found.
             if (result === false) { return false; }
           }
         }
@@ -248,27 +281,28 @@
     /**
      * Checks whether the value matches the requirements for this constraint.
      *
-     * @param value
+     * @memberof Drupal.states.Dependent#
+     *
+     * @param {string|Array|object} value
      *   Either the value of a state or an array/object of constraints. In the
      *   latter case, resolving the constraint continues.
-     * @param selector
+     * @param {string} [selector]
      *   The selector for this constraint. If undefined, there isn't yet a
-     *   selector that this constraint applies to. In that case, the state key is
-     *   propagates to a selector and resolving continues.
-     * @param state
+     *   selector that this constraint applies to. In that case, the state key
+     *   is propagates to a selector and resolving continues.
+     * @param {Drupal.states.State} [state]
      *   The state to check for this constraint. If undefined, resolving
-     *   continues.
-     *   If both selector and state aren't undefined and valid non-numeric
-     *   strings, a lookup for the actual value of that selector's state is
-     *   performed. This parameter is not a State object but a pristine state
-     *   string.
+     *   continues. If both selector and state aren't undefined and valid
+     *   non-numeric strings, a lookup for the actual value of that selector's
+     *   state is performed. This parameter is not a State object but a pristine
+     *   state string.
      *
-     * @return
+     * @return {bool}
      *   true or false, depending on whether this constraint is satisfied.
      */
     checkConstraints: function (value, selector, state) {
-      // Normalize the last parameter. If it's non-numeric, we treat it either as
-      // a selector (in case there isn't one yet) or as a trigger/state.
+      // Normalize the last parameter. If it's non-numeric, we treat it either
+      // as a selector (in case there isn't one yet) or as a trigger/state.
       if (typeof state !== 'string' || (/[0-9]/).test(state[0])) {
         state = null;
       }
@@ -279,7 +313,7 @@
       }
 
       if (state !== null) {
-        // constraints is the actual constraints of an element to check for.
+        // Constraints is the actual constraints of an element to check for.
         state = states.State.sanitize(state);
         return invert(this.compare(value, selector, state), state.invert);
       }
@@ -291,11 +325,15 @@
 
     /**
      * Gathers information about all required triggers.
+     *
+     * @memberof Drupal.states.Dependent#
+     *
+     * @return {object}
      */
     getDependees: function () {
       var cache = {};
-      // Swivel the lookup function so that we can record all available selector-
-      // state combinations for initialization.
+      // Swivel the lookup function so that we can record all available
+      // selector- state combinations for initialization.
       var _compare = this.compare;
       this.compare = function (reference, selector, state) {
         (cache[selector] || (cache[selector] = [])).push(state.name);
@@ -317,6 +355,11 @@
     }
   };
 
+  /**
+   * @constructor Drupal.states.Trigger
+   *
+   * @param {object} args
+   */
   states.Trigger = function (args) {
     $.extend(this, args);
 
@@ -332,6 +375,10 @@
   };
 
   states.Trigger.prototype = {
+
+    /**
+     * @memberof Drupal.states.Trigger#
+     */
     initialize: function () {
       var trigger = states.Trigger.states[this.state];
 
@@ -351,6 +398,12 @@
       this.element.data('trigger:' + this.state, true);
     },
 
+    /**
+     * @memberof Drupal.states.Trigger#
+     *
+     * @param {jQuery.Event} event
+     * @param {function} valueFn
+     */
     defaultTrigger: function (event, valueFn) {
       var oldValue = valueFn.call(this.element);
 
@@ -376,9 +429,16 @@
    * of an element. Whenever an element depends on the state of another element,
    * one of these trigger functions is added to the dependee so that the
    * dependent element can be updated.
+   *
+   * @name Drupal.states.Trigger.states
+   *
+   * @prop empty
+   * @prop checked
+   * @prop value
+   * @prop collapsed
    */
   states.Trigger.states = {
-    // 'empty' describes the state to be monitored
+    // 'empty' describes the state to be monitored.
     empty: {
       // 'keyup' is the (native DOM) event that we watch for.
       'keyup': function () {
@@ -390,9 +450,9 @@
 
     checked: {
       'change': function () {
-        // prop() and attr() only takes the first element into account. To support
-        // selectors matching multiple checkboxes, iterate over all and return
-        // whether any is checked.
+        // prop() and attr() only takes the first element into account. To
+        // support selectors matching multiple checkboxes, iterate over all and
+        // return whether any is checked.
         var checked = false;
         this.each(function () {
           // Use prop() here as we want a boolean of the checkbox state.
@@ -434,9 +494,16 @@
 
   /**
    * A state object is used for describing the state and performing aliasing.
+   *
+   * @constructor Drupal.states.State
+   *
+   * @param {string} state
    */
   states.State = function (state) {
-    // We may need the original unresolved name later.
+
+    /**
+     * Original unresolved name.
+     */
     this.pristine = this.name = state;
 
     // Normalize the state name.
@@ -460,6 +527,12 @@
 
   /**
    * Creates a new State object by sanitizing the passed value.
+   *
+   * @name Drupal.states.State.sanitize
+   *
+   * @param {string|Drupal.states.State} state
+   *
+   * @return {Drupal.states.state}
    */
   states.State.sanitize = function (state) {
     if (state instanceof states.State) {
@@ -471,8 +544,10 @@
   };
 
   /**
-   * This list of aliases is used to normalize states and associates negated names
-   * with their respective inverse state.
+   * This list of aliases is used to normalize states and associates negated
+   * names with their respective inverse state.
+   *
+   * @name Drupal.states.State.aliases
    */
   states.State.aliases = {
     'enabled': '!disabled',
@@ -490,10 +565,18 @@
   };
 
   states.State.prototype = {
+
+    /**
+     * @memberof Drupal.states.State#
+     */
     invert: false,
 
     /**
      * Ensures that just using the state object returns the name.
+     *
+     * @memberof Drupal.states.State#
+     *
+     * @return {string}
      */
     toString: function () {
       return this.name;
@@ -563,6 +646,13 @@
 
   /**
    * Bitwise AND with a third undefined state.
+   *
+   * @function Drupal.states~ternary
+   *
+   * @param {*} a
+   * @param {*} b
+   *
+   * @return {bool}
    */
   function ternary(a, b) {
     if (typeof a === 'undefined') {
@@ -578,6 +668,13 @@
 
   /**
    * Inverts a (if it's not undefined) when invertState is true.
+   *
+   * @function Drupal.states~invert
+   *
+   * @param {*} a
+   * @param {bool} invertState
+   *
+   * @return {bool}
    */
   function invert(a, invertState) {
     return (invertState && typeof a !== 'undefined') ? !a : a;
@@ -585,6 +682,13 @@
 
   /**
    * Compares two values while ignoring undefined values.
+   *
+   * @function Drupal.states~compare
+   *
+   * @param {*} a
+   * @param {*} b
+   *
+   * @return {bool}
    */
   function compare(a, b) {
     if (a === b) {
diff --git a/core/misc/tabbingmanager.js b/core/misc/tabbingmanager.js
index dc21c0263bf956f6064205af8f447e3acf79c96e..4593ec48f70194e87fc859832481e14fc8925374 100644
--- a/core/misc/tabbingmanager.js
+++ b/core/misc/tabbingmanager.js
@@ -3,42 +3,76 @@
  * Manages page tabbing modifications made by modules.
  */
 
+/**
+ * Allow modules to respond to the constrain event.
+ *
+ * @event drupalTabbingConstrained
+ */
+
+/**
+ * Allow modules to respond to the tabbingContext release event.
+ *
+ * @event drupalTabbingContextReleased
+ */
+
+/**
+ * Allow modules to respond to the constrain event.
+ *
+ * @event drupalTabbingContextActivated
+ */
+
+/**
+ * Allow modules to respond to the constrain event.
+ *
+ * @event drupalTabbingContextDeactivated
+ */
+
 (function ($, Drupal) {
 
   "use strict";
 
   /**
    * Provides an API for managing page tabbing order modifications.
+   *
+   * @constructor Drupal~TabbingManager
    */
   function TabbingManager() {
-    // Tabbing sets are stored as a stack. The active set is at the top of the
-    // stack. We use a JavaScript array as if it were a stack; we consider the
-    // first element to be the bottom and the last element to be the top. This
-    // allows us to use JavaScript's built-in Array.push() and Array.pop()
-    // methods.
+
+    /**
+     * Tabbing sets are stored as a stack. The active set is at the top of the
+     * stack. We use a JavaScript array as if it were a stack; we consider the
+     * first element to be the bottom and the last element to be the top. This
+     * allows us to use JavaScript's built-in Array.push() and Array.pop()
+     * methods.
+     *
+     * @type {Array.<Drupal~TabbingContext>}
+     */
     this.stack = [];
   }
 
   /**
    * Add public methods to the TabbingManager class.
    */
-  $.extend(TabbingManager.prototype, {
+  $.extend(TabbingManager.prototype, /** @lends Drupal~TabbingManager# */{
+
     /**
      * Constrain tabbing to the specified set of elements only.
      *
-     * Makes elements outside of the specified set of elements unreachable via the
-     * tab key.
+     * Makes elements outside of the specified set of elements unreachable via
+     * the tab key.
+     *
+     * @param {jQuery} elements
+     *   The set of elements to which tabbing should be constrained. Can also
+     *   be a jQuery-compatible selector string.
      *
-     * @param jQuery elements
-     *   The set of elements to which tabbing should be constrained. Can also be
-     *   a jQuery-compatible selector string.
+     * @return {Drupal~TabbingContext}
      *
-     * @return TabbingContext
+     * @fires event:drupalTabbingConstrained
      */
     constrain: function (elements) {
       // Deactivate all tabbingContexts to prepare for the new constraint. A
-      // tabbingContext instance will only be reactivated if the stack is unwound
-      // to it in the _unwindStack() method.
+      // tabbingContext instance will only be reactivated if the stack is
+      // unwound to it in the _unwindStack() method.
       var il = this.stack.length;
       for (var i = 0; i < il; i++) {
         this.stack[i].deactivate();
@@ -68,14 +102,15 @@
     },
 
     /**
-     * Restores a former tabbingContext when an active tabbingContext is released.
+     * Restores a former tabbingContext when an active one is released.
      *
-     * The TabbingManager stack of tabbingContext instances will be unwound from
-     * the top-most released tabbingContext down to the first non-released
+     * The TabbingManager stack of tabbingContext instances will be unwound
+     * from the top-most released tabbingContext down to the first non-released
      * tabbingContext instance. This non-released instance is then activated.
      */
     release: function () {
-      // Unwind as far as possible: find the topmost non-released tabbingContext.
+      // Unwind as far as possible: find the topmost non-released
+      // tabbingContext.
       var toActivate = this.stack.length - 1;
       while (toActivate >= 0 && this.stack[toActivate].released) {
         toActivate--;
@@ -94,11 +129,11 @@
     /**
      * Makes all elements outside the of the tabbingContext's set untabbable.
      *
-     * Elements made untabbable have their original tabindex and autofocus values
-     * stored so that they might be restored later when this tabbingContext
-     * is deactivated.
+     * Elements made untabbable have their original tabindex and autofocus
+     * values stored so that they might be restored later when this
+     * tabbingContext is deactivated.
      *
-     * @param TabbingContext tabbingContext
+     * @param {Drupal~TabbingContext} tabbingContext
      *   The TabbingContext instance that has been activated.
      */
     activate: function (tabbingContext) {
@@ -115,17 +150,18 @@
       for (var i = 0; i < il; i++) {
         this.recordTabindex($disabledSet.eq(i), level);
       }
-      // Make all tabbable elements outside of the active tabbing set unreachable.
+      // Make all tabbable elements outside of the active tabbing set
+      // unreachable.
       $disabledSet
         .prop('tabindex', -1)
         .prop('autofocus', false);
 
-      // Set focus on an element in the tabbingContext's set of tabbable elements.
-      // First, check if there is an element with an autofocus attribute. Select
-      // the last one from the DOM order.
+      // Set focus on an element in the tabbingContext's set of tabbable
+      // elements. First, check if there is an element with an autofocus
+      // attribute. Select the last one from the DOM order.
       var $hasFocus = $set.filter('[autofocus]').eq(-1);
-      // If no element in the tabbable set has an autofocus attribute, select the
-      // first element in the set.
+      // If no element in the tabbable set has an autofocus attribute, select
+      // the first element in the set.
       if ($hasFocus.length === 0) {
         $hasFocus = $set.eq(0);
       }
@@ -135,10 +171,10 @@
     /**
      * Restores that tabbable state of a tabbingContext's disabled elements.
      *
-     * Elements that were made untabbable have their original tabindex and autofocus
-     * values restored.
+     * Elements that were made untabbable have their original tabindex and
+     * autofocus values restored.
      *
-     * @param TabbingContext tabbingContext
+     * @param {Drupal~TabbingContext} tabbingContext
      *   The TabbingContext instance that has been deactivated.
      */
     deactivate: function (tabbingContext) {
@@ -153,9 +189,9 @@
     /**
      * Records the tabindex and autofocus values of an untabbable element.
      *
-     * @param jQuery $set
+     * @param {jQuery} $el
      *   The set of elements that have been disabled.
-     * @param Number level
+     * @param {number} level
      *   The stack level for which the tabindex attribute should be recorded.
      */
     recordTabindex: function ($el, level) {
@@ -170,9 +206,9 @@
     /**
      * Restores the tabindex and autofocus values of a reactivated element.
      *
-     * @param jQuery $el
+     * @param {jQuery} $el
      *   The element that is being reactivated.
-     * @param Number level
+     * @param {number} level
      *   The stack level for which the tabindex attribute should be restored.
      */
     restoreTabindex: function ($el, level) {
@@ -214,26 +250,53 @@
    *
    * This constraint can be removed with the release() method.
    *
-   * @param Object options
-   *   A set of initiating values that include:
-   *   - Number level: The level in the TabbingManager's stack of this
-   *   tabbingContext.
-   *   - jQuery $tabbableElements: The DOM elements that should be reachable via
-   *   the tab key when this tabbingContext is active.
-   *   - jQuery $disabledElements: The DOM elements that should not be reachable
-   *   via the tab key when this tabbingContext is active.
-   *   - Boolean released: A released tabbingContext can never be activated again.
-   *   It will be cleaned up when the TabbingManager unwinds its stack.
-   *   - Boolean active: When true, the tabbable elements of this tabbingContext
-   *   will be reachable via the tab key and the disabled elements will not. Only
-   *   one tabbingContext can be active at a time.
+   * @constructor Drupal~TabbingContext
+   *
+   * @param {object} options
+   *   A set of initiating values
+   * @param {number} options.level
+   *   The level in the TabbingManager's stack of this tabbingContext.
+   * @param {jQuery} options.$tabbableElements
+   *   The DOM elements that should be reachable via the tab key when this
+   *   tabbingContext is active.
+   * @param {jQuery} options.$disabledElements
+   *   The DOM elements that should not be reachable via the tab key when this
+   *   tabbingContext is active.
+   * @param {bool} options.released
+   *   A released tabbingContext can never be activated again. It will be
+   *   cleaned up when the TabbingManager unwinds its stack.
+   * @param {bool} options.active
+   *   When true, the tabbable elements of this tabbingContext will be reachable
+   *   via the tab key and the disabled elements will not. Only one
+   *   tabbingContext can be active at a time.
    */
   function TabbingContext(options) {
-    $.extend(this, {
+
+    $.extend(this, /** @lends Drupal~TabbingContext# */{
+
+      /**
+       * @type {?number}
+       */
       level: null,
+
+      /**
+       * @type {jQuery}
+       */
       $tabbableElements: $(),
+
+      /**
+       * @type {jQuery}
+       */
       $disabledElements: $(),
+
+      /**
+       * @type {bool}
+       */
       released: false,
+
+      /**
+       * @type {bool}
+       */
       active: false
     }, options);
   }
@@ -241,11 +304,15 @@
   /**
    * Add public methods to the TabbingContext class.
    */
-  $.extend(TabbingContext.prototype, {
+  $.extend(TabbingContext.prototype, /** @lends Drupal~TabbingContext# */{
+
     /**
      * Releases this TabbingContext.
      *
-     * Once a TabbingContext object is released, it can never be activated again.
+     * Once a TabbingContext object is released, it can never be activated
+     * again.
+     *
+     * @fires event:drupalTabbingContextReleased
      */
     release: function () {
       if (!this.released) {
@@ -259,6 +326,8 @@
 
     /**
      * Activates this TabbingContext.
+     *
+     * @fires event:drupalTabbingContextActivated
      */
     activate: function () {
       // A released TabbingContext object can never be activated again.
@@ -272,6 +341,8 @@
 
     /**
      * Deactivates this TabbingContext.
+     *
+     * @fires event:drupalTabbingContextDeactivated
      */
     deactivate: function () {
       if (this.active) {
@@ -288,6 +359,10 @@
   if (Drupal.tabbingManager) {
     return;
   }
+
+  /**
+   * @type {Drupal~TabbingManager}
+   */
   Drupal.tabbingManager = new TabbingManager();
 
 }(jQuery, Drupal));
diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js
index faea38bb6296e4e4e86e8b6605886ea22c6eaf50..7b68df376821582687897a5ecdb2625036496299 100644
--- a/core/misc/tabledrag.js
+++ b/core/misc/tabledrag.js
@@ -1,9 +1,21 @@
+/**
+ * @file
+ * Provide dragging capabilities to admin uis.
+ */
+
+/**
+ * Triggers when weights columns are toggled.
+ *
+ * @event columnschange
+ */
+
 (function ($, Drupal, drupalSettings) {
 
   "use strict";
 
   /**
    * Store the state of weight columns display for all tables.
+   *
    * Default value is to hide weight columns.
    */
   var showWeight = JSON.parse(localStorage.getItem('Drupal.tableDrag.showWeight'));
@@ -12,12 +24,15 @@
    * Drag and drop table rows with field manipulation.
    *
    * Using the drupal_attach_tabledrag() function, any table with weights or
-   * parent relationships may be made into draggable tables. Columns containing a
-   * field may optionally be hidden, providing a better user experience.
+   * parent relationships may be made into draggable tables. Columns containing
+   * a field may optionally be hidden, providing a better user experience.
    *
    * Created tableDrag instances may be modified with custom behaviors by
    * overriding the .onDrag, .onDrop, .row.onSwap, and .row.onIndent methods.
-   * See blocks.js for an example of adding additional functionality to tableDrag.
+   * See blocks.js for an example of adding additional functionality to
+   * tableDrag.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.tableDrag = {
     attach: function (context, settings) {
@@ -38,39 +53,126 @@
   };
 
   /**
-   * Constructor for the tableDrag object. Provides table and field manipulation.
+   * Provides table and field manipulation.
+   *
+   * @constructor
    *
-   * @param table
+   * @param {HTMLElement} table
    *   DOM object for the table to be made draggable.
-   * @param tableSettings
+   * @param {object} tableSettings
    *   Settings for the table added via drupal_add_dragtable().
    */
   Drupal.tableDrag = function (table, tableSettings) {
     var self = this;
     var $table = $(table);
 
-    // Required object variables.
+    /**
+     * @type {jQuery}
+     */
     this.$table = $(table);
+
+    /**
+     *
+     * @type {HTMLElement}
+     */
     this.table = table;
+
+    /**
+     * @type {object}
+     */
     this.tableSettings = tableSettings;
-    this.dragObject = null; // Used to hold information about a current drag operation.
-    this.rowObject = null; // Provides operations for row manipulation.
-    this.oldRowElement = null; // Remember the previous element.
-    this.oldY = 0; // Used to determine up or down direction from last mouse move.
-    this.changed = false; // Whether anything in the entire table has changed.
-    this.maxDepth = 0; // Maximum amount of allowed parenting.
-    this.rtl = $(this.table).css('direction') === 'rtl' ? -1 : 1; // Direction of the table.
+
+    /**
+     * Used to hold information about a current drag operation.
+     *
+     * @type {?HTMLElement}
+     */
+    this.dragObject = null;
+
+    /**
+     * Provides operations for row manipulation.
+     *
+     * @type {?HTMLElement}
+     */
+    this.rowObject = null;
+
+    /**
+     * Remember the previous element.
+     *
+     * @type {?HTMLElement}
+     */
+    this.oldRowElement = null;
+
+    /**
+     * Used to determine up or down direction from last mouse move.
+     *
+     * @type {number}
+     */
+    this.oldY = 0;
+
+    /**
+     * Whether anything in the entire table has changed.
+     *
+     * @type {bool}
+     */
+    this.changed = false;
+
+    /**
+     * Maximum amount of allowed parenting.
+     *
+     * @type {number}
+     */
+    this.maxDepth = 0;
+
+    /**
+     * Direction of the table.
+     *
+     * @type {number}
+     */
+    this.rtl = $(this.table).css('direction') === 'rtl' ? -1 : 1;
+
+    /**
+     *
+     * @type {bool}
+     */
     this.striping = $(this.table).data('striping') === 1;
 
-    // Configure the scroll settings.
+    /**
+     * Configure the scroll settings.
+     *
+     * @type {object}
+     *
+     * @prop {number} amount
+     * @prop {number} interval
+     * @prop {number} trigger
+     */
     this.scrollSettings = {amount: 4, interval: 50, trigger: 70};
+
+    /**
+     *
+     * @type {?number}
+     */
     this.scrollInterval = null;
+
+    /**
+     *
+     * @type {number}
+     */
     this.scrollY = 0;
+
+    /**
+     *
+     * @type {number}
+     */
     this.windowHeight = 0;
 
-    // Check this table's settings to see if there are parent relationships in
-    // this table. For efficiency, large sections of code can be skipped if we
-    // don't need to track horizontal movement and indentations.
+    /**
+     * Check this table's settings to see if there are parent relationships in
+     * this table. For efficiency, large sections of code can be skipped if we
+     * don't need to track horizontal movement and indentations.
+     *
+     * @type {bool}
+     */
     this.indentEnabled = false;
     for (var group in tableSettings) {
       if (tableSettings.hasOwnProperty(group)) {
@@ -87,7 +189,13 @@
       }
     }
     if (this.indentEnabled) {
-      this.indentCount = 1; // Total width of indents, set in makeDraggable.
+
+      /**
+       * Total width of indents, set in makeDraggable.
+       *
+       * @type {number}
+       */
+      this.indentCount = 1;
       // Find the width of indentations to measure mouse movements against.
       // Because the table doesn't need to start with any indentations, we
       // manually append 2 indentations in the first draggable row, measure
@@ -96,6 +204,11 @@
       var testRow = $('<tr/>').addClass('draggable').appendTo(table);
       var testCell = $('<td/>').appendTo(testRow).prepend(indent).prepend(indent);
       var $indentation = testCell.find('.js-indentation');
+
+      /**
+       *
+       * @type {number}
+       */
       this.indentAmount = $indentation.get(1).offsetLeft - $indentation.get(0).offsetLeft;
       testRow.remove();
     }
@@ -136,7 +249,8 @@
     $(window).on('storage', $.proxy(function (e) {
       // Only react to 'Drupal.tableDrag.showWeight' value change.
       if (e.originalEvent.key === 'Drupal.tableDrag.showWeight') {
-        // This was changed in another window, get the new value for this window.
+        // This was changed in another window, get the new value for this
+        // window.
         showWeight = JSON.parse(e.originalEvent.newValue);
         this.displayColumns(showWeight);
       }
@@ -144,8 +258,7 @@
   };
 
   /**
-   * Initialize columns containing form elements to be hidden by default,
-   * according to the settings for this tableDrag instance.
+   * Initialize columns containing form elements to be hidden by default.
    *
    * Identify and mark each cell with a CSS class so we can easily toggle
    * show/hide it. Finally, hide columns if user does not have a
@@ -157,7 +270,9 @@
     var cell;
     var columnIndex;
     for (var group in this.tableSettings) {
-      if (this.tableSettings.hasOwnProperty(group)) { // Find the first field in this group.
+      if (this.tableSettings.hasOwnProperty(group)) {
+
+        // Find the first field in this group.
         for (var d in this.tableSettings[group]) {
           if (this.tableSettings[group].hasOwnProperty(d)) {
             var field = $table.find('.' + this.tableSettings[group][d].target).eq(0);
@@ -171,8 +286,9 @@
 
         // Mark the column containing this field so it can be hidden.
         if (hidden && cell[0]) {
-          // Add 1 to our indexes. The nth-child selector is 1 based, not 0 based.
-          // Match immediate children of the parent element to allow nesting.
+          // Add 1 to our indexes. The nth-child selector is 1 based, not 0
+          // based. Match immediate children of the parent element to allow
+          // nesting.
           columnIndex = cell.parent().find('> td').index(cell.get(0)) + 1;
           $table.find('> thead > tr, > tbody > tr, > tr').each(this.addColspanClass(columnIndex));
         }
@@ -182,8 +298,13 @@
   };
 
   /**
-   * Mark cells that have colspan so we can adjust the colspan
-   * instead of hiding them altogether.
+   * Mark cells that have colspan.
+   *
+   * In order to adjust the colspan instead of hiding them altogether.
+   *
+   * @param {number} columnIndex
+   *
+   * @return {function}
    */
   Drupal.tableDrag.prototype.addColspanClass = function (columnIndex) {
     return function () {
@@ -214,7 +335,9 @@
   /**
    * Hide or display weight columns. Triggers an event on change.
    *
-   * @param bool displayWeight
+   * @fires event:columnschange
+   *
+   * @param {bool} displayWeight
    *   'true' will show weight columns.
    */
   Drupal.tableDrag.prototype.displayColumns = function (displayWeight) {
@@ -232,6 +355,7 @@
 
   /**
    * Toggle the weight column depending on 'showWeight' value.
+   *
    * Store only default override.
    */
   Drupal.tableDrag.prototype.toggleColumns = function () {
@@ -249,6 +373,7 @@
 
   /**
    * Hide the columns containing weight/parent form elements.
+   *
    * Undo showColumns().
    */
   Drupal.tableDrag.prototype.hideColumns = function () {
@@ -266,7 +391,8 @@
   };
 
   /**
-   * Show the columns containing weight/parent form elements
+   * Show the columns containing weight/parent form elements.
+   *
    * Undo hideColumns().
    */
   Drupal.tableDrag.prototype.showColumns = function () {
@@ -285,6 +411,11 @@
 
   /**
    * Find the target used within a particular row and group.
+   *
+   * @param {string} group
+   * @param {HTMLElement} row
+   *
+   * @return {object}
    */
   Drupal.tableDrag.prototype.rowSettings = function (group, row) {
     var field = $(row).find('.' + group);
@@ -308,6 +439,8 @@
 
   /**
    * Take an item and add event handlers to make it become draggable.
+   *
+   * @param {HTMLElement} item
    */
   Drupal.tableDrag.prototype.makeDraggable = function (item) {
     var self = this;
@@ -369,13 +502,18 @@
       var keyChange = false;
       var groupHeight;
       switch (event.keyCode) {
-        case 37: // Left arrow.
-        case 63234: // Safari left arrow.
+        // Left arrow.
+        case 37:
+        // Safari left arrow.
+        case 63234:
           keyChange = true;
           self.rowObject.indent(-1 * self.rtl);
           break;
-        case 38: // Up arrow.
-        case 63232: // Safari up arrow.
+
+        // Up arrow.
+        case 38:
+        // Safari up arrow.
+        case 63232:
           var $previousRow = $(self.rowObject.element).prev('tr:first-of-type');
           var previousRow = $previousRow.get(0);
           while (previousRow && $previousRow.is(':hidden')) {
@@ -383,7 +521,8 @@
             previousRow = $previousRow.get(0);
           }
           if (previousRow) {
-            self.safeBlur = false; // Do not allow the onBlur cleanup.
+            // Do not allow the onBlur cleanup.
+            self.safeBlur = false;
             self.rowObject.direction = 'up';
             keyChange = true;
 
@@ -402,23 +541,30 @@
               }
             }
             else if (self.table.tBodies[0].rows[0] !== previousRow || $previousRow.is('.draggable')) {
-              // Swap with the previous row (unless previous row is the first one
-              // and undraggable).
+              // Swap with the previous row (unless previous row is the first
+              // one and undraggable).
               self.rowObject.swap('before', previousRow);
               self.rowObject.interval = null;
               self.rowObject.indent(0);
               window.scrollBy(0, -parseInt(item.offsetHeight, 10));
             }
-            handle.trigger('focus'); // Regain focus after the DOM manipulation.
+            // Regain focus after the DOM manipulation.
+            handle.trigger('focus');
           }
           break;
-        case 39: // Right arrow.
-        case 63235: // Safari right arrow.
+
+        // Right arrow.
+        case 39:
+        // Safari right arrow.
+        case 63235:
           keyChange = true;
           self.rowObject.indent(self.rtl);
           break;
-        case 40: // Down arrow.
-        case 63233: // Safari down arrow.
+
+        // Down arrow.
+        case 40:
+        // Safari down arrow.
+        case 63233:
           var $nextRow = $(self.rowObject.group).eq(-1).next('tr:first-of-type');
           var nextRow = $nextRow.get(0);
           while (nextRow && $nextRow.is(':hidden')) {
@@ -426,7 +572,8 @@
             nextRow = $nextRow.get(0);
           }
           if (nextRow) {
-            self.safeBlur = false; // Do not allow the onBlur cleanup.
+            // Do not allow the onBlur cleanup.
+            self.safeBlur = false;
             self.rowObject.direction = 'down';
             keyChange = true;
 
@@ -451,7 +598,8 @@
               self.rowObject.indent(0);
               window.scrollBy(0, parseInt(item.offsetHeight, 10));
             }
-            handle.trigger('focus'); // Regain focus after the DOM manipulation.
+            // Regain focus after the DOM manipulation.
+            handle.trigger('focus');
           }
           break;
       }
@@ -474,15 +622,20 @@
       }
     });
 
-    // Compatibility addition, return false on keypress to prevent unwanted scrolling.
-    // IE and Safari will suppress scrolling on keydown, but all other browsers
-    // need to return false on keypress. http://www.quirksmode.org/js/keys.html
+    // Compatibility addition, return false on keypress to prevent unwanted
+    // scrolling. IE and Safari will suppress scrolling on keydown, but all
+    // other browsers need to return false on keypress.
+    // http://www.quirksmode.org/js/keys.html
     handle.on('keypress', function (event) {
       switch (event.keyCode) {
-        case 37: // Left arrow.
-        case 38: // Up arrow.
-        case 39: // Right arrow.
-        case 40: // Down arrow.
+        // Left arrow.
+        case 37:
+        // Up arrow.
+        case 38:
+        // Right arrow.
+        case 39:
+        // Down arrow.
+        case 40:
           return false;
       }
     });
@@ -491,11 +644,11 @@
   /**
    * Pointer event initiator, creates drag object and information.
    *
-   * @param jQuery.Event event
+   * @param {jQuery.Event} event
    *   The event object that trigger the drag.
-   * @param Drupal.tableDrag self
+   * @param {Drupal.tableDrag} self
    *   The drag handle.
-   * @param DOM item
+   * @param {HTMLElement} item
    *   The item that that is being dragged.
    */
   Drupal.tableDrag.prototype.dragStart = function (event, self, item) {
@@ -531,6 +684,11 @@
 
   /**
    * Pointer movement handler, bound to document.
+   *
+   * @param {jQuery.Event} event
+   * @param {Drupal.tableDrag} self
+   *
+   * @return {bool|undefined}
    */
   Drupal.tableDrag.prototype.dragRow = function (event, self) {
     if (self.dragObject) {
@@ -541,8 +699,8 @@
       // Check for row swapping and vertical scrolling.
       if (y !== self.oldY) {
         self.rowObject.direction = y > self.oldY ? 'down' : 'up';
-        self.oldY = y; // Update the old value.
-
+        // Update the old value.
+        self.oldY = y;
         // Check if the window should be scrolled (and how fast).
         var scrollAmount = self.checkScroll(self.currentPointerCoords.y);
         // Stop any current scrolling.
@@ -570,7 +728,8 @@
       // Similar to row swapping, handle indentations.
       if (self.indentEnabled) {
         var xDiff = self.currentPointerCoords.x - self.dragObject.indentPointerPos.x;
-        // Set the number of indentations the pointer has been moved left or right.
+        // Set the number of indentations the pointer has been moved left or
+        // right.
         var indentDiff = Math.round(xDiff / self.indentAmount);
         // Indent the row with our estimated diff, which may be further
         // restricted according to the rows around this row.
@@ -586,6 +745,9 @@
 
   /**
    * Pointerup behavior.
+   *
+   * @param {jQuery.Event} event
+   * @param {Drupal.tableDrag} self
    */
   Drupal.tableDrag.prototype.dropRow = function (event, self) {
     var droppedRow;
@@ -644,6 +806,10 @@
 
   /**
    * Get the coordinates from the event (allowing for browser differences).
+   *
+   * @param {jQuery.Event} event
+   *
+   * @return {{x: number, y: number}}
    */
   Drupal.tableDrag.prototype.pointerCoords = function (event) {
     if (event.pageX || event.pageY) {
@@ -656,8 +822,15 @@
   };
 
   /**
+   * Get the event offset from the target element.
+   *
    * Given a target element and a pointer event, get the event offset from that
    * element. To do this we need the element's position and the target position.
+   *
+   * @param {HTMLElement} target
+   * @param {jQuery.Event} event
+   *
+   * @return {{x: number, y: number}}
    */
   Drupal.tableDrag.prototype.getPointerOffset = function (target, event) {
     var docPos = $(target).offset();
@@ -666,13 +839,16 @@
   };
 
   /**
-   * Find the row the mouse is currently over. This row is then taken and swapped
-   * with the one being dragged.
+   * Find the row the mouse is currently over.
+   *
+   * This row is then taken and swapped with the one being dragged.
    *
-   * @param x
+   * @param {number} x
    *   The x coordinate of the mouse on the page (not the screen).
-   * @param y
+   * @param {number} y
    *   The y coordinate of the mouse on the page (not the screen).
+   *
+   * @return {*}
    */
   Drupal.tableDrag.prototype.findDropTargetRow = function (x, y) {
     var rows = $(this.table.tBodies[0].rows).not(':hidden');
@@ -715,8 +891,8 @@
         }
 
         // We may have found the row the mouse just passed over, but it doesn't
-        // take into account hidden rows. Skip backwards until we find a draggable
-        // row.
+        // take into account hidden rows. Skip backwards until we find a
+        // draggable row.
         while ($row.is(':hidden') && $row.prev('tr').is(':hidden')) {
           $row = $row.prev('tr:first-of-type');
           row = $row.get(0);
@@ -728,10 +904,9 @@
   };
 
   /**
-   * After the row is dropped, update the table fields according to the settings
-   * set for this table.
+   * After the row is dropped, update the table fields.
    *
-   * @param changedRow
+   * @param {HTMLElement} changedRow
    *   DOM object for the row that was just dropped.
    */
   Drupal.tableDrag.prototype.updateFields = function (changedRow) {
@@ -745,12 +920,11 @@
   };
 
   /**
-   * After the row is dropped, update a single table field according to specific
-   * settings.
+   * After the row is dropped, update a single table field.
    *
-   * @param changedRow
+   * @param {HTMLElement} changedRow
    *   DOM object for the row that was just dropped.
-   * @param group
+   * @param {string} group
    *   The settings group on which field updates will occur.
    */
   Drupal.tableDrag.prototype.updateField = function (changedRow, group) {
@@ -843,10 +1017,12 @@
           // Get the depth of the target row.
           targetElement.value = $(sourceElement).closest('tr').find('.js-indentation').length;
           break;
+
         case 'match':
           // Update the value.
           targetElement.value = sourceElement.value;
           break;
+
         case 'order':
           var siblings = this.rowObject.findSiblings(rowSettings);
           if ($(targetElement).is('select')) {
@@ -858,7 +1034,8 @@
             var maxVal = values[values.length - 1];
             // Populate the values in the siblings.
             $(siblings).find(targetClass).each(function () {
-              // If there are more items than possible values, assign the maximum value to the row.
+              // If there are more items than possible values, assign the
+              // maximum value to the row.
               if (values.length > 0) {
                 this.value = values.shift();
               }
@@ -881,9 +1058,15 @@
   };
 
   /**
+   * Copy all tableDrag related classes from one row to another.
+   *
    * Copy all special tableDrag classes from one row's form elements to a
    * different one, removing any special classes that the destination row
    * may have had.
+   *
+   * @param {HTMLElement} sourceRow
+   * @param {HTMLElement} targetRow
+   * @param {string} group
    */
   Drupal.tableDrag.prototype.copyDragClasses = function (sourceRow, targetRow, group) {
     var sourceElement = $(sourceRow).find('.' + group);
@@ -893,6 +1076,10 @@
     }
   };
 
+  /**
+   * @param {number} cursorY
+   * @return {number}
+   */
   Drupal.tableDrag.prototype.checkScroll = function (cursorY) {
     var de = document.documentElement;
     var b = document.body;
@@ -921,6 +1108,9 @@
     }
   };
 
+  /**
+   * @param {number} scrollAmount
+   */
   Drupal.tableDrag.prototype.setScroll = function (scrollAmount) {
     var self = this;
 
@@ -935,6 +1125,9 @@
     }, this.scrollSettings.interval);
   };
 
+  /**
+   * Command to restripe table properly.
+   */
   Drupal.tableDrag.prototype.restripeTable = function () {
     // :even and :odd are reversed because jQuery counts from 0 and
     // we count from 1, so we're out of sync.
@@ -947,6 +1140,8 @@
 
   /**
    * Stub function. Allows a custom handler when a row begins dragging.
+   *
+   * @return {?bool}
    */
   Drupal.tableDrag.prototype.onDrag = function () {
     return null;
@@ -954,6 +1149,8 @@
 
   /**
    * Stub function. Allows a custom handler when a row is dropped.
+   *
+   * @return {?bool}
    */
   Drupal.tableDrag.prototype.onDrop = function () {
     return null;
@@ -962,16 +1159,18 @@
   /**
    * Constructor to make a new object to manipulate a table row.
    *
-   * @param tableRow
+   * @param {HTMLElement} tableRow
    *   The DOM element for the table row we will be manipulating.
-   * @param method
-   *   The method in which this row is being moved. Either 'keyboard' or 'mouse'.
-   * @param indentEnabled
+   * @param {string} method
+   *   The method in which this row is being moved. Either 'keyboard' or
+   *   'mouse'.
+   * @param {bool} indentEnabled
    *   Whether the containing table uses indentations. Used for optimizations.
-   * @param maxDepth
+   * @param {number} maxDepth
    *   The maximum amount of indentations this row may contain.
-   * @param addClasses
-   *   Whether we want to add classes to this row to indicate child relationships.
+   * @param {bool} addClasses
+   *   Whether we want to add classes to this row to indicate child
+   *   relationships.
    */
   Drupal.tableDrag.prototype.row = function (tableRow, method, indentEnabled, maxDepth, addClasses) {
     var $tableRow = $(tableRow);
@@ -984,8 +1183,8 @@
     this.table = $tableRow.closest('table')[0];
     this.indentEnabled = indentEnabled;
     this.maxDepth = maxDepth;
-    this.direction = ''; // Direction the row is being moved.
-
+    // Direction the row is being moved.
+    this.direction = '';
     if (this.indentEnabled) {
       this.indents = $tableRow.find('.js-indentation').length;
       this.children = this.findChildren(addClasses);
@@ -1000,8 +1199,11 @@
   /**
    * Find all children of rowObject by indentation.
    *
-   * @param addClasses
-   *   Whether we want to add classes to this row to indicate child relationships.
+   * @param {bool} addClasses
+   *   Whether we want to add classes to this row to indicate child
+   *   relationships.
+   *
+   * @return {Array}
    */
   Drupal.tableDrag.prototype.row.prototype.findChildren = function (addClasses) {
     var parentIndentation = this.indents;
@@ -1045,8 +1247,10 @@
   /**
    * Ensure that two rows are allowed to be swapped.
    *
-   * @param row
+   * @param {HTMLElement} row
    *   DOM object for the row being considered for swapping.
+   *
+   * @return {bool}
    */
   Drupal.tableDrag.prototype.row.prototype.isValidSwap = function (row) {
     var $row = $(row);
@@ -1080,9 +1284,9 @@
   /**
    * Perform the swap between two rows.
    *
-   * @param position
+   * @param {string} position
    *   Whether the swap will occur 'before' or 'after' the given row.
-   * @param row
+   * @param {HTMLElement} row
    *   DOM element what will be swapped with the row group.
    */
   Drupal.tableDrag.prototype.row.prototype.swap = function (position, row) {
@@ -1100,15 +1304,16 @@
   };
 
   /**
-   * Determine the valid indentations interval for the row at a given position
-   * in the table.
+   * Determine the valid indentations interval for the row at a given position.
    *
-   * @param prevRow
+   * @param {?HTMLElement} prevRow
    *   DOM object for the row before the tested position
    *   (or null for first position in the table).
-   * @param nextRow
+   * @param {?HTMLElement} nextRow
    *   DOM object for the row after the tested position
    *   (or null for last position in the table).
+   *
+   * @return {{min: number, max: number}}
    */
   Drupal.tableDrag.prototype.row.prototype.validIndentInterval = function (prevRow, nextRow) {
     var $prevRow = $(prevRow);
@@ -1142,10 +1347,12 @@
   /**
    * Indent a row within the legal bounds of the table.
    *
-   * @param indentDiff
+   * @param {number} indentDiff
    *   The number of additional indentations proposed for the row (can be
    *   positive or negative). This number will be adjusted to nearest valid
    *   indentation level for the row.
+   *
+   * @return {number}
    */
   Drupal.tableDrag.prototype.row.prototype.indent = function (indentDiff) {
     var $group = $(this.group);
@@ -1184,11 +1391,15 @@
   };
 
   /**
-   * Find all siblings for a row, either according to its subgroup or indentation.
-   * Note that the passed-in row is included in the list of siblings.
+   * Find all siblings for a row.
    *
-   * @param settings
+   * According to its subgroup or indentation. Note that the passed-in row is
+   * included in the list of siblings.
+   *
+   * @param {object} rowSettings
    *   The field settings we're using to identify what constitutes a sibling.
+   *
+   * @return {Array}
    */
   Drupal.tableDrag.prototype.row.prototype.findSiblings = function (rowSettings) {
     var siblings = [];
@@ -1257,6 +1468,8 @@
 
   /**
    * Stub function. Allows a custom handler when a row is indented.
+   *
+   * @return {?bool}
    */
   Drupal.tableDrag.prototype.row.prototype.onIndent = function () {
     return null;
@@ -1264,18 +1477,34 @@
 
   /**
    * Stub function. Allows a custom handler when a row is swapped.
+   *
+   * @param {HTMLElement} swappedRow
+   *
+   * @return {?bool}
    */
   Drupal.tableDrag.prototype.row.prototype.onSwap = function (swappedRow) {
     return null;
   };
 
-  $.extend(Drupal.theme, {
+  $.extend(Drupal.theme, /** @lends Drupal.theme */{
+
+    /**
+     * @return {string}
+     */
     tableDragChangedMarker: function () {
       return '<abbr class="warning tabledrag-changed" title="' + Drupal.t('Changed') + '">*</abbr>';
     },
+
+    /**
+     * @return {string}
+     */
     tableDragIndentation: function () {
       return '<div class="js-indentation indentation">&nbsp;</div>';
     },
+
+    /**
+     * @return {string}
+     */
     tableDragChangedWarning: function () {
       return '<div class="tabledrag-changed-warning messages messages--warning" role="alert">' + Drupal.theme('tableDragChangedMarker') + ' ' + Drupal.t('You have unsaved changes.') + '</div>';
     }
diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js
index 2d6ce16e100353072c0e54fd9cf4d03f6dbf2a41..fbdb33c35f284241a104c7cda2f8c38973f18dad 100644
--- a/core/misc/tableheader.js
+++ b/core/misc/tableheader.js
@@ -1,9 +1,16 @@
+/**
+ * @file
+ * Sticky table headers.
+ */
+
 (function ($, Drupal, displace) {
 
   "use strict";
 
   /**
    * Attaches sticky table headers.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.tableHeader = {
     attach: function (context) {
@@ -48,26 +55,36 @@
 
   // Bind event that need to change all tables.
   $(window).on({
+
     /**
      * When resizing table width can change, recalculate everything.
+     *
+     * @ignore
      */
     'resize.TableHeader': tableHeaderResizeHandler,
 
     /**
      * Bind only one event to take care of calling all scroll callbacks.
+     *
+     * @ignore
      */
     'scroll.TableHeader': tableHeaderOnScrollHandler
   });
   // Bind to custom Drupal events.
   $(document).on({
+
     /**
      * Recalculate columns width when window is resized and when show/hide
      * weight is triggered.
+     *
+     * @ignore
      */
     'columnschange.TableHeader': tableHeaderResizeHandler,
 
     /**
-     * Recalculate TableHeader.topOffset when viewport is resized
+     * Recalculate TableHeader.topOffset when viewport is resized.
+     *
+     * @ignore
      */
     'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler
   });
@@ -78,19 +95,37 @@
    * TableHeader will make the current table header stick to the top of the page
    * if the table is very long.
    *
-   * @param table
+   * @constructor Drupal.TableHeader
+   *
+   * @param {HTMLElement} table
    *   DOM object for the table to add a sticky header to.
    *
-   * @constructor
+   * @listens event:columnschange
    */
   function TableHeader(table) {
     var $table = $(table);
 
+    /**
+     * @name Drupal.TableHeader#$originalTable
+     *
+     * @type {HTMLElement}
+     */
     this.$originalTable = $table;
+
+    /**
+     * @type {jQuery}
+     */
     this.$originalHeader = $table.children('thead');
+
+    /**
+     * @type {jQuery}
+     */
     this.$originalHeaderCells = this.$originalHeader.find('> tr > th');
-    this.displayWeight = null;
 
+    /**
+     * @type {null|bool}
+     */
+    this.displayWeight = null;
     this.$originalTable.addClass('sticky-table');
     this.tableHeight = $table[0].clientHeight;
     this.tableOffset = this.$originalTable.offset();
@@ -111,11 +146,12 @@
   /**
    * Store the state of TableHeader.
    */
-  $.extend(TableHeader, {
+  $.extend(TableHeader, /** @lends Drupal.TableHeader */{
+
     /**
      * This will store the state of all processed tables.
      *
-     * @type {Array}
+     * @type {Array.<Drupal.TableHeader>}
      */
     tables: []
   });
@@ -123,24 +159,33 @@
   /**
    * Extend TableHeader prototype.
    */
-  $.extend(TableHeader.prototype, {
+  $.extend(TableHeader.prototype, /** @lends Drupal.TableHeader# */{
+
     /**
      * Minimum height in pixels for the table to have a sticky header.
+     *
+     * @type {number}
      */
     minHeight: 100,
 
     /**
      * Absolute position of the table on the page.
+     *
+     * @type {?Drupal~displaceOffset}
      */
     tableOffset: null,
 
     /**
      * Absolute position of the table on the page.
+     *
+     * @type {?number}
      */
     tableHeight: null,
 
     /**
      * Boolean storing the sticky header visibility state.
+     *
+     * @type {bool}
      */
     stickyVisible: false,
 
@@ -169,8 +214,10 @@
     /**
      * Set absolute position of sticky.
      *
-     * @param offsetTop
-     * @param offsetLeft
+     * @param {number} offsetTop
+     * @param {number} offsetLeft
+     *
+     * @return {jQuery}
      */
     stickyPosition: function (offsetTop, offsetLeft) {
       var css = {};
@@ -185,6 +232,8 @@
 
     /**
      * Returns true if sticky is currently visible.
+     *
+     * @return {bool}
      */
     checkStickyVisible: function () {
       var scrollTop = scrollValue('scrollTop');
@@ -203,9 +252,10 @@
     /**
      * Check if sticky header should be displayed.
      *
-     * This function is throttled to once every 250ms to avoid unnecessary calls.
+     * This function is throttled to once every 250ms to avoid unnecessary
+     * calls.
      *
-     * @param event
+     * @param {jQuery.Event} e
      */
     onScroll: function (e) {
       this.checkStickyVisible();
@@ -217,7 +267,7 @@
     /**
      * Event handler: recalculates position of the sticky table header.
      *
-     * @param event
+     * @param {jQuery.Event} event
      *   Event being triggered.
      */
     recalculateSticky: function (event) {
diff --git a/core/misc/tableresponsive.js b/core/misc/tableresponsive.js
index b4eab625c827ea5c1a4820b7b7090305242b1b38..f2ebd1893791ac35a94a5b22136a1f58069330d8 100644
--- a/core/misc/tableresponsive.js
+++ b/core/misc/tableresponsive.js
@@ -1,9 +1,16 @@
+/**
+ * @file
+ * Responsive table functionality.
+ */
+
 (function ($, Drupal, window) {
 
   "use strict";
 
   /**
-   * Attach the tableResponsive function to Drupal.behaviors.
+   * Attach the tableResponsive function to {@link Drupal.behaviors}.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.tableResponsive = {
     attach: function (context, settings) {
@@ -18,14 +25,18 @@
   };
 
   /**
-   * The TableResponsive object optimizes table presentation for all screen sizes.
+   * The TableResponsive object optimizes table presentation for screen size.
    *
    * A responsive table hides columns at small screen sizes, leaving the most
-   * important columns visible to the end user. Users should not be prevented from
-   * accessing all columns, however. This class adds a toggle to a table with
-   * hidden columns that exposes the columns. Exposing the columns will likely
-   * break layouts, but it provides the user with a means to access data, which
-   * is a guiding principle of responsive design.
+   * important columns visible to the end user. Users should not be prevented
+   * from accessing all columns, however. This class adds a toggle to a table
+   * with hidden columns that exposes the columns. Exposing the columns will
+   * likely break layouts, but it provides the user with a means to access
+   * data, which is a guiding principle of responsive design.
+   *
+   * @constructor Drupal.TableResponsive
+   *
+   * @param {HTMLElement} table
    */
   function TableResponsive(table) {
     this.table = table;
@@ -51,7 +62,13 @@
   /**
    * Extend the TableResponsive function with a list of managed tables.
    */
-  $.extend(TableResponsive, {
+  $.extend(TableResponsive, /** @lends Drupal.TableResponsive */{
+
+    /**
+     * Store all created instances.
+     *
+     * @type {Array.<Drupal.TableResponsive>}
+     */
     tables: []
   });
 
@@ -61,24 +78,34 @@
    * Columns are assumed to be hidden if their header has the class priority-low
    * or priority-medium.
    */
-  $.extend(TableResponsive.prototype, {
+  $.extend(TableResponsive.prototype, /** @lends Drupal.TableResponsive# */{
+
+    /**
+     * @param {jQuery.Event} e
+     */
     eventhandlerEvaluateColumnVisibility: function (e) {
       var pegged = parseInt(this.$link.data('pegged'), 10);
       var hiddenLength = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden').length;
-      // If the table has hidden columns, associate an action link with the table
-      // to show the columns.
+      // If the table has hidden columns, associate an action link with the
+      // table to show the columns.
       if (hiddenLength > 0) {
         this.$link.show().text(this.showText);
       }
       // When the toggle is pegged, its presence is maintained because the user
-      // has interacted with it. This is necessary to keep the link visible if the
-      // user adjusts screen size and changes the visibility of columns.
+      // has interacted with it. This is necessary to keep the link visible if
+      // the user adjusts screen size and changes the visibility of columns.
       if (!pegged && hiddenLength === 0) {
         this.$link.hide().text(this.hideText);
       }
     },
-    // Toggle the visibility of columns classed with either 'priority-low' or
-    // 'priority-medium'.
+
+    /**
+     * Toggle the visibility of columns based on their priority.
+     *
+     * Columns are classed with either 'priority-low' or 'priority-medium'.
+     *
+     * @param {jQuery.Event} e
+     */
     eventhandlerToggleColumns: function (e) {
       e.preventDefault();
       var self = this;
@@ -110,10 +137,10 @@
           var $cell = $(this);
           var properties = $cell.attr('style').split(';');
           var newProps = [];
-          // The hide method adds display none to the element. The element should
-          // be returned to the same state it was in before the columns were
-          // revealed, so it is necessary to remove the display none
-          // value from the style attribute.
+          // The hide method adds display none to the element. The element
+          // should be returned to the same state it was in before the columns
+          // were revealed, so it is necessary to remove the display none value
+          // from the style attribute.
           var match = /^display\s*\:\s*none$/;
           for (var i = 0; i < properties.length; i++) {
             var prop = properties[i];
@@ -134,6 +161,7 @@
       }
     }
   });
+
   // Make the TableResponsive object available in the Drupal namespace.
   Drupal.TableResponsive = TableResponsive;
 
diff --git a/core/misc/tableselect.js b/core/misc/tableselect.js
index 78e8c90fd1046d9f3bbf229b7348477c580cd15d..fc8e9f2dbb999d07ce32182725d7bd6dce1c2d51 100644
--- a/core/misc/tableselect.js
+++ b/core/misc/tableselect.js
@@ -1,7 +1,17 @@
+/**
+ * @file
+ * Table select functionality.
+ */
+
 (function ($, Drupal) {
 
   "use strict";
 
+  /**
+   * Initialize tableSelects.
+   *
+   * @type {Drupal~behavior}
+   */
   Drupal.behaviors.tableSelect = {
     attach: function (context, settings) {
       // Select the inner-most table in case of nested tables.
@@ -9,13 +19,18 @@
     }
   };
 
+  /**
+   * Callback used in {@link Drupal.behaviors.tableSelect}.
+   */
   Drupal.tableSelect = function () {
-    // Do not add a "Select all" checkbox if there are no rows with checkboxes in the table
+    // Do not add a "Select all" checkbox if there are no rows with checkboxes
+    // in the table.
     if ($(this).find('td input[type="checkbox"]').length === 0) {
       return;
     }
 
-    // Keep track of the table, which checkbox is checked and alias the settings.
+    // Keep track of the table, which checkbox is checked and alias the
+    // settings.
     var table = this;
     var checkboxes;
     var lastChecked;
@@ -25,6 +40,10 @@
       // Update table's select-all checkbox (and sticky header's if available).
       $table.prev('table.sticky-header').addBack().find('th.select-all input[type="checkbox"]').each(function () {
         $(this).attr('title', state ? strings.selectNone : strings.selectAll);
+
+        /**
+         * @this {HTMLElement}
+         */
         this.checked = state;
       });
     };
@@ -32,10 +51,20 @@
     // Find all <th> with class select-all, and insert the check all checkbox.
     $table.find('th.select-all').prepend($('<input type="checkbox" class="form-checkbox" />').attr('title', strings.selectAll)).on('click', function (event) {
       if ($(event.target).is('input[type="checkbox"]')) {
-        // Loop through all checkboxes and set their state to the select all checkbox' state.
+        // Loop through all checkboxes and set their state to the select all
+        // checkbox' state.
         checkboxes.each(function () {
+
+          /**
+           * @this {HTMLElement}
+           */
           this.checked = event.target.checked;
-          // Either add or remove the selected class based on the state of the check all checkbox.
+          // Either add or remove the selected class based on the state of the
+          // check all checkbox.
+
+          /**
+           * @this {HTMLElement}
+           */
           $(this).closest('tr').toggleClass('selected', this.checked);
         });
         // Update the title and the state of the check all box.
@@ -45,18 +74,24 @@
 
     // For each of the checkboxes within the table that are not disabled.
     checkboxes = $table.find('td input[type="checkbox"]:enabled').on('click', function (e) {
-      // Either add or remove the selected class based on the state of the check all checkbox.
+      // Either add or remove the selected class based on the state of the
+      // check all checkbox.
+
+      /**
+       * @this {HTMLElement}
+       */
       $(this).closest('tr').toggleClass('selected', this.checked);
 
-      // If this is a shift click, we need to highlight everything in the range.
-      // Also make sure that we are actually checking checkboxes over a range and
-      // that a checkbox has been checked or unchecked before.
+      // If this is a shift click, we need to highlight everything in the
+      // range. Also make sure that we are actually checking checkboxes
+      // over a range and that a checkbox has been checked or unchecked before.
       if (e.shiftKey && lastChecked && lastChecked !== e.target) {
         // We use the checkbox's parent TR to do our range searching.
         Drupal.tableSelectRange($(e.target).closest('tr')[0], $(lastChecked).closest('tr')[0], e.target.checked);
       }
 
-      // If all checkboxes are checked, make sure the select-all one is checked too, otherwise keep unchecked.
+      // If all checkboxes are checked, make sure the select-all one is checked
+      // too, otherwise keep unchecked.
       updateSelectAll((checkboxes.length === checkboxes.filter(':checked').length));
 
       // Keep track of the last checked checkbox.
@@ -68,6 +103,11 @@
     updateSelectAll((checkboxes.length === checkboxes.filter(':checked').length));
   };
 
+  /**
+   * @param {HTMLElement} from
+   * @param {HTMLElement} to
+   * @param {bool} state
+   */
   Drupal.tableSelectRange = function (from, to, state) {
     // We determine the looping mode based on the order of from and to.
     var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
@@ -80,7 +120,8 @@
         continue;
       }
       $i = $(i);
-      // Either add or remove the selected class based on the state of the target checkbox.
+      // Either add or remove the selected class based on the state of the
+      // target checkbox.
       $i.toggleClass('selected', state);
       $i.find('input[type="checkbox"]').prop('checked', state);
 
diff --git a/core/misc/timezone.js b/core/misc/timezone.js
index e7667b878bf6380ed314a78ee40d7ef86cec37fc..801d72839d1db5876adcaeaca7ec4f87db917b6b 100644
--- a/core/misc/timezone.js
+++ b/core/misc/timezone.js
@@ -1,9 +1,16 @@
+/**
+ * @file
+ * Timezone detection.
+ */
+
 (function ($) {
 
   "use strict";
 
   /**
    * Set the client's system time zone as default values of form fields.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.setTimezone = {
     attach: function (context, settings) {
@@ -45,10 +52,11 @@
           isDaylightSavingTime = 0;
         }
 
-        // Submit request to the system/timezone callback and set the form field
-        // to the response time zone. The client date is passed to the callback
-        // for debugging purposes. Submit a synchronous request to avoid database
-        // errors associated with concurrent requests during install.
+        // Submit request to the system/timezone callback and set the form
+        // field to the response time zone. The client date is passed to the
+        // callback for debugging purposes. Submit a synchronous request to
+        // avoid database errors associated with concurrent requests
+        // during install.
         var path = 'system/timezone/' + abbreviation + '/' + offsetNow + '/' + isDaylightSavingTime;
         $.ajax({
           async: false,
diff --git a/core/misc/vertical-tabs.js b/core/misc/vertical-tabs.js
index e7f64dc0356b8eae98c7f491baea794535b0d3c3..a381bdcf12b5e0d85d4bcb9002e9b049c504285e 100644
--- a/core/misc/vertical-tabs.js
+++ b/core/misc/vertical-tabs.js
@@ -1,17 +1,31 @@
+/**
+ * @file
+ * Define vertical tabs functionality.
+ */
+
+/**
+ * Triggers when form values inside a vertical tab changes.
+ *
+ * This is used to update the summary in vertical tabs in order to know what
+ * are the important fields' values.
+ *
+ * @event summaryUpdated
+ */
+
 (function ($) {
 
   "use strict";
 
   /**
-   * This script transforms a set of details into a stack of vertical
-   * tabs. Another tab pane can be selected by clicking on the respective
-   * tab.
+   * This script transforms a set of details into a stack of vertical tabs.
    *
    * Each tab may have a summary which can be updated by another
    * script. For that to work, each details element has an associated
    * 'verticalTabCallback' (with jQuery.data() attached to the details),
    * which is called every time the user performs an update to a form
    * element inside the tab pane.
+   *
+   * @type {Drupal~behavior}
    */
   Drupal.behaviors.verticalTabs = {
     attach: function (context) {
@@ -25,7 +39,8 @@
         var focusID = $this.find(':hidden.vertical-tabs__active-tab').val();
         var tab_focus;
 
-        // Check if there are some details that can be converted to vertical-tabs
+        // Check if there are some details that can be converted to
+        // vertical-tabs.
         var $details = $this.find('> details');
         if ($details.length === 0) {
           return;
@@ -79,10 +94,17 @@
   /**
    * The vertical tab object represents a single tab within a tab group.
    *
-   * @param settings
-   *   An object with the following keys:
-   *   - title: The name of the tab.
-   *   - details: The jQuery object of the details element that is the tab pane.
+   * @constructor
+   *
+   * @param {object} settings
+   * @param {string} settings.title
+   *   The name of the tab.
+   * @param {jQuery} settings.details
+   *   The jQuery object of the details element that is the tab pane.
+   *
+   * @fires event:summaryUpdated
+   *
+   * @listens event:summaryUpdated
    */
   Drupal.verticalTab = function (settings) {
     var self = this;
@@ -114,6 +136,7 @@
   };
 
   Drupal.verticalTab.prototype = {
+
     /**
      * Displays the tab's content pane.
      */
@@ -144,15 +167,17 @@
 
     /**
      * Shows a vertical tab pane.
+     *
+     * @return {Drupal.verticalTab}
      */
     tabShow: function () {
       // Display the tab.
       this.item.show();
       // Show the vertical tabs.
       this.item.closest('.js-form-type-vertical-tabs').show();
-      // Update .first marker for items. We need recurse from parent to retain the
-      // actual DOM element order as jQuery implements sortOrder, but not as public
-      // method.
+      // Update .first marker for items. We need recurse from parent to retain
+      // the actual DOM element order as jQuery implements sortOrder, but not
+      // as public method.
       this.item.parent().children('.vertical-tabs__menu-item').removeClass('first')
         .filter(':visible').eq(0).addClass('first');
       // Display the details element.
@@ -164,13 +189,15 @@
 
     /**
      * Hides a vertical tab pane.
+     *
+     * @return {Drupal.verticalTab}
      */
     tabHide: function () {
       // Hide this tab.
       this.item.hide();
-      // Update .first marker for items. We need recurse from parent to retain the
-      // actual DOM element order as jQuery implements sortOrder, but not as public
-      // method.
+      // Update .first marker for items. We need recurse from parent to retain
+      // the actual DOM element order as jQuery implements sortOrder, but not
+      // as public method.
       this.item.parent().children('.vertical-tabs__menu-item').removeClass('first')
         .filter(':visible').eq(0).addClass('first');
       // Hide the details element.
@@ -191,10 +218,12 @@
   /**
    * Theme function for a vertical tab.
    *
-   * @param settings
+   * @param {object} settings
    *   An object with the following keys:
-   *   - title: The name of the tab.
-   * @return
+   * @param {string} settings.title
+   *   The name of the tab.
+   *
+   * @return {object}
    *   This function has to return an object with at least these keys:
    *   - item: The root tab jQuery element
    *   - link: The anchor tag that acts as the clickable area of the tab