diff --git a/core/misc/active-link.js b/core/misc/active-link.js index 3a2f818..8b1e4ed 100644 --- a/core/misc/active-link.js +++ b/core/misc/active-link.js @@ -28,7 +28,8 @@ var originalSelectors = ['[data-drupal-link-system-path="' + path.currentPath + '"]']; var selectors; - // If this is the front page, we have to check for the path as well. + // If this is the front page, we have to check for the path as + // well. if (path.isFront) { originalSelectors.push('[data-drupal-link-system-path=""]'); } diff --git a/core/misc/ajax.js b/core/misc/ajax.js index e2aeab1..e3b366e 100644 --- a/core/misc/ajax.js +++ b/core/misc/ajax.js @@ -1,19 +1,20 @@ +/** + * @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"; - /** - * Provides Ajax page updating via jQuery $.ajax (Asynchronous JavaScript and XML). - * - * 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. - */ - Drupal.ajax = Drupal.ajax || {}; /** @@ -70,7 +71,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'}; var baseUseAjaxSubmit = $(this).attr('id'); @@ -80,7 +82,16 @@ }; /** - * Extends Error to provide handling for Errors in AJAX + * 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) { @@ -98,9 +109,10 @@ 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)}); } @@ -125,7 +137,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'; }; @@ -142,17 +165,26 @@ * For example, if your Ajax enabled button has the ID 'edit-submit', you can * redefine the function that is called to insert the new content like this * (inside a Drupal.behaviors attach block): - * @code - * Drupal.behaviors.myCustomAJAXStuff = { - * attach: function (context, settings) { - * Drupal.ajax['edit-submit'].commands.insert = function (ajax, response, status) { - * new_content = $(response.data); - * $('#my-wrapper').append(new_content); - * alert('New content was appended to #my-wrapper'); - * } - * } - * }; - * @endcode + * + * @constructor + * + * @param {string} base + * ID of element the event is binded to. + * @param {HTMLElement} element + * DOM element used to find the Ajax URL. + * @param {object} element_settings + * Settings for the Drupal Ajax object. + * + * @example + * Drupal.behaviors.myCustomAJAXStuff = { + * attach: function (context, settings) { + * Drupal.ajax['edit-submit'].commands.insert = function (ajax, response, status) { + * new_content = $(response.data); + * $('#my-wrapper').append(new_content); + * alert('New content was appended to #my-wrapper'); + * } + * } + * }; */ Drupal.ajax = function (base, element, element_settings) { var defaults = { @@ -173,6 +205,9 @@ $.extend(this, defaults, element_settings); + /** + * @type {Drupal.AjaxCommands} + */ this.commands = new Drupal.AjaxCommands(); // @todo Remove this after refactoring the PHP code to: @@ -180,15 +215,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.form) { + + /** + * @type {jQuery} + */ this.$form = $(this.element.form); } @@ -200,15 +250,16 @@ else if (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; } @@ -227,6 +278,26 @@ // Set the options for the ajaxSubmit function. // The 'this' variable will not persist inside of the options object. var ajax = this; + + /** + * Set the 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} complere + * @prop {string} dataType + * @prop {object} accepts + * @prop {string} accepts.json + * @prop {string} type + */ ajax.options = { url: ajax.url, data: ajax.submit, @@ -305,8 +376,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(); @@ -413,28 +484,29 @@ * Prepare the Ajax request before it is sent. */ 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; @@ -507,7 +579,7 @@ }; /** - * 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. */ Drupal.ajax.prototype.getEffect = function (response) { var type = response.effect || this.effect; @@ -557,10 +629,13 @@ }; /** - * Provide a series of commands that the server can request the client perform. + * 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. */ @@ -580,16 +655,17 @@ var new_content_wrapped = $('
').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 http://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 + // http://drupal.org/node/736066. if (new_content.length !== 1 || new_content.get(0).nodeType !== 1) { new_content = new_content_wrapped; } @@ -624,9 +700,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; @@ -679,7 +755,7 @@ }, /** - * 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. */ settings: function (ajax, response, status) { if (response.merge) { diff --git a/core/misc/announce.js b/core/misc/announce.js index 9aafbbc..d323929 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. + * + * @example * $('#search-list') * .on('itemInsert', function (event, data) { * // Insert the new items. @@ -14,6 +17,7 @@ * )); * }); */ + (function (Drupal, debounce) { "use strict"; @@ -22,8 +26,7 @@ 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. */ Drupal.behaviors.drupalAnnounce = { attach: function (context) { @@ -86,9 +89,9 @@ * 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 * A string to indicate the priority of the message. Can be either * 'polite' or 'assertive'. Polite is the default. * diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js index 92bb867..c3ab03d 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,9 +12,9 @@ /** * Helper splitting terms from the autocomplete value. * - * @param {String} value + * @param {string} value * - * @return {Array} + * @return {array} */ function autocompleteSplitValues(value) { // We will match the value against comma-separated terms. @@ -43,9 +48,9 @@ /** * Returns the last value of an multi-value textfield. * - * @param {String} terms + * @param {string} terms * - * @return {String} + * @return {string} */ function extractLastTerm(terms) { return autocomplete.splitValues(terms).pop(); @@ -54,9 +59,9 @@ /** * The search handler is called before a search is performed. * - * @param {Object} event + * @param {object} event * - * @return {Boolean} + * @return {bool} */ function searchHandler(event) { var options = autocomplete.options; @@ -72,8 +77,8 @@ /** * 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 +91,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 +108,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 +133,7 @@ /** * Handles an autocompletefocus event. * - * @return {Boolean} + * @return {bool} */ function focusHandler() { return false; @@ -137,10 +142,10 @@ /** * Handles an autocompleteselect event. * - * @param {Object} event - * @param {Object} ui + * @param {object} event + * @param {object} ui * - * @return {Boolean} + * @return {bool} */ function selectHandler(event, ui) { var terms = autocomplete.splitValues(event.target.value); @@ -161,10 +166,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 $("
  • ") diff --git a/core/misc/batch.js b/core/misc/batch.js index ee6cf68..a984332 100644 --- a/core/misc/batch.js +++ b/core/misc/batch.js @@ -1,6 +1,8 @@ /** + * @file * Drupal's batch API. */ + (function ($, Drupal) { "use strict"; diff --git a/core/misc/collapse.js b/core/misc/collapse.js index 6aa2e25..91b10fd 100644 --- a/core/misc/collapse.js +++ b/core/misc/collapse.js @@ -1,9 +1,20 @@ +/** + * @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 + * + * @name Drupal.CollapsibleDetails + * + * @param {HTMLElement} node */ function CollapsibleDetails(node) { this.$node = $(node); @@ -20,22 +31,24 @@ this.setupLegend(); } - /** - * Extend CollapsibleDetails function. - */ - $.extend(CollapsibleDetails, { + $.extend(CollapsibleDetails, /** @lends Drupal.CollapsibleDetails */{ + /** * Holds references to instantiated CollapsibleDetails objects. + * + * @type {array.} */ 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 = $(''); @@ -43,6 +56,7 @@ .on('summaryUpdated', $.proxy(this.onSummaryUpdated, this)) .trigger('summaryUpdated'); }, + /** * Initialize and setup legend markup. */ @@ -65,6 +79,7 @@ .append(this.$summary) .on('click', $.proxy(this.onLegendClick, this)); }, + /** * Handle legend clicks */ @@ -72,6 +87,7 @@ this.toggle(); e.preventDefault(); }, + /** * Update summary */ @@ -79,6 +95,7 @@ var text = $.trim(this.$node.drupalGetSummary()); this.$summary.html(text ? ' (' + text + ')' : ''); }, + /** * Toggle the visibility of a details element using smooth animations. */ @@ -95,6 +112,9 @@ } }); + /** + * Polyfill HTML5 details element. + */ Drupal.behaviors.collapse = { attach: function (context) { if (Modernizr.details) { diff --git a/core/misc/debounce.js b/core/misc/debounce.js index 45a5b87..e5a81d7 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,14 @@ * 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. */ Drupal.debounce = function (func, wait, immediate) { diff --git a/core/misc/dialog/dialog.ajax.js b/core/misc/dialog/dialog.ajax.js index e786d5a..bc97564 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 {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) { diff --git a/core/misc/dialog/dialog.jquery-ui.js b/core/misc/dialog/dialog.jquery-ui.js index cd6e863..27fff75 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 f63b405..24b87a9 100644 --- a/core/misc/dialog/dialog.js +++ b/core/misc/dialog/dialog.js @@ -1,9 +1,10 @@ /** * @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"; @@ -14,17 +15,43 @@ // 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 DrupalDialog + * + * @type {object} + * + * @param {HTMLElement} context + * + * @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 {DrupalDialog} + */ 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 3e08574..007ef24 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"; @@ -12,6 +23,8 @@ * 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(). + * + * @fires event:dialogContentResize */ function resetSize(event) { var positionOptions = ['width', 'height', 'minWidth', 'minHeight', 'maxHeight', 'maxWidth', 'position']; diff --git a/core/misc/displace.js b/core/misc/displace.js index a52a826..3dde5ba 100644 --- a/core/misc/displace.js +++ b/core/misc/displace.js @@ -1,13 +1,40 @@ /** + * @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 OffsetObject + * + * @type {object} + * + * @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 {OffsetObject} + */ var offsets = { top: 0, right: 0, @@ -17,6 +44,8 @@ /** * Registers a resize handler on the window. + * + * @type {Behavior} */ Drupal.behaviors.drupalDisplace = { attach: function () { @@ -33,11 +62,13 @@ /** * Informs listeners of the current offset dimensions. * - * @param {boolean} broadcast - * (optional) When true or undefined, causes the recalculated offsets values to be + * @fires event:drupalViewportOffsetChange + * + * @param {bool} [broadcast] + * When true or undefined, causes the recalculated offsets values to be * broadcast to listeners. * - * @return {object} + * @return {OffsetObject} * 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. @@ -53,7 +84,7 @@ /** * Determines the viewport offsets. * - * @return {object} + * @return {OffsetObject} * 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 +106,8 @@ * numeric value, that value will be used. If no value is provided, one will * be calculated using the element's dimensions and placement. * + * @name Drupal.displace.calculateOffset + * * @param {string} edge * The name of the edge to calculate. Can be 'top', 'right', * 'bottom' or 'left'. @@ -111,7 +144,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 @@ -166,12 +199,18 @@ */ Drupal.displace = displace; $.extend(Drupal.displace, { + /** * 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 eebf354..d096ac6 100644 --- a/core/misc/dropbutton/dropbutton.js +++ b/core/misc/dropbutton/dropbutton.js @@ -1,3 +1,8 @@ +/** + * @file + * Dropbutton feature. + */ + (function ($, Drupal) { "use strict"; @@ -37,21 +42,38 @@ * 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 + * @constructor + * + * @name Drupal.DropButton + * + * @param {HTMLElement} dropbutton * A jQuery element. * - * @param {Object} settings + * @param {object} settings * A list of options including: - * - {String} title: The text inside the toggle link element. This text is + * - {string} 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 +89,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 +125,11 @@ /** * Extend the DropButton constructor. */ - $.extend(DropButton, { + $.extend(DropButton, /** @lends Drupal.DropButton */{ /** * Store all processed DropButtons. * - * @type {Array} + * @type {array} */ dropbuttons: [] }); @@ -102,12 +137,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 +152,9 @@ this.$dropbutton.toggleClass('open', show); }, + /** + * @function + */ hoverIn: function () { // Clear any previous timer we were using. if (this.timerID) { @@ -123,37 +162,53 @@ } }, + /** + * @function + */ hoverOut: function () { // Wait half a second before closing. this.timerID = window.setTimeout($.proxy(this, 'close'), 500); }, + /** + * @function + */ open: function () { this.toggle(true); }, + /** + * @function + */ close: function () { this.toggle(false); }, + /** + * @function + */ focusOut: function (e) { this.hoverOut.call(this, e); }, + /** + * @function + */ 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 + * @param {object} options + * - {string} title: (optional) 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 9e9d24e..aa13dfd 100644 --- a/core/misc/drupal.js +++ b/core/misc/drupal.js @@ -1,7 +1,38 @@ /** - * Base framework for Drupal-specific JavaScript, behaviors, and settings. + * @file + * Defines the Drupal JS API. */ -window.Drupal = {behaviors: {}}; + +/** + * A jQuery object. + * + * @typedef jQuery + */ + +/** + * Variable generated by Drupal with all the configuration created from PHP. + * + * @global + * + * @var drupalSettings + */ + +/** + * Variable generated by Drupal that holds all translated strings from PHP. + * + * @global + * + * @var 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,11 +49,12 @@ 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. * - * @param list + * @param {array} list * An array of errors thrown during attach/detach. - * @param event + * @param {string} event * A string containing either 'attach' or 'detach'. */ function DrupalBehaviorError(list, event) { @@ -42,42 +74,83 @@ if (window.jQuery) { DrupalBehaviorError.prototype = new Error(); /** + * @typedef BehaviorAttachCallback + * + * @type {function} + * + * @param {HTMLElement} context + * @param {object} settings + */ + + /** + * @typedef BehaviorDetachCallback + * + * @type {function} + * + * @param {HTMLElement} context + * @param {object} settings + * @param {string} trigger + * One of 'unload', 'serialize' or 'move'. + */ + + /** + * @typedef Behavior + * + * @type {object} + * + * @property {BehaviorAttachCallback} attach + * Function run on page load and after an AJAX call. + * @property {BehaviorDetachCallback} detach + * Function run when content is serialized or removed from the page. + */ + + /** + * Holds all initialization methods. + * + * @namespace Drupal.behaviors + * + * @type {Object.} + */ + + /** * 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 + * Drupal.behaviors object using the method 'attach' and optionally also + * 'detach' as follows: + * + * 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 {HTMLElement} 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.detachBehaviors */ Drupal.attachBehaviors = function (context, settings) { context = context || document; @@ -115,16 +188,16 @@ 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 {HTMLElement} 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. @@ -171,7 +244,8 @@ if (window.jQuery) { /** * Helper to test document width for mobile configurations. - * @todo Temporary solution for the mobile initiative. + * + * @deprecated Temporary solution for the mobile initiative. */ Drupal.checkWidthBreakpoint = function (width) { width = width || drupalSettings.widthBreakpoint || 640; @@ -181,10 +255,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 +275,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 text and theme as a placeholder for user-submitted * content (checkPlain + 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. @@ -248,14 +323,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 +374,18 @@ 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.<*>} 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 options - * - 'context' (defaults to the empty context): The context the source string - * belongs to. + * @param {object} options + * @param {string} [options.context=''] + * The context the source string belongs to. * - * @return + * @return {string} * The translated string. */ Drupal.t = function (str, args, options) { @@ -330,6 +405,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; @@ -346,26 +426,26 @@ if (window.jQuery) { * \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(). * Note that you do not need to include @count in this array. * This replacement is done automatically for the plural case. - * @param {Object} options + * @param {object} [options] * The options to pass to the Drupal.t() function. * - * @return {String} + * @return {string} * A translated string. */ Drupal.formatPlural = function (count, singular, plural, args, options) { @@ -391,6 +471,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 +491,15 @@ 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)`. * - * @param func + * @namespace + * @param {function} func * The name of the theme function to call. - * @param ... + * @param {...*} [.] * Additional arguments to pass along to the theme function. - * @return + * + * @return {*} * Any data the theme function returns. This could be a plain HTML string, * but also a complex object. */ @@ -426,9 +513,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 b1d1fff..afc23ec 100644 --- a/core/misc/form.js +++ b/core/misc/form.js @@ -1,3 +1,17 @@ +/** + * @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"; @@ -13,7 +27,11 @@ /** * Sets the summary for all matched elements. * - * @param callback + * @fires event:summaryUpdated + * + * @listens event:formUpdated + * + * @param {function} callback * Either a function that will be called each time the summary is * retrieved or a string (which is returned each time). */ @@ -43,13 +61,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 +75,26 @@ * 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. + * 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. + * Lastly, all forms submitted via HTTP GET are idempotent by definition of + * HTTP standards, so excluded in this implementation. */ Drupal.behaviors.formSingleSubmit = { attach: function () { @@ -99,6 +117,8 @@ /** * Sends a 'formUpdated' event each time a form element is modified. + * + * @fires event:formUpdated */ function triggerFormUpdated(element) { $(element).trigger('formUpdated'); @@ -108,7 +128,8 @@ * Collects the IDs of all form fields in the given form. * * @param {HTMLFormElement} form - * @return {Array} + * + * @return {array} */ function fieldsList(form) { var $fieldList = $(form).find('[name]').map(function (index, element) { @@ -124,6 +145,10 @@ * Triggers the 'formUpdated' event on form elements when they are modified. */ Drupal.behaviors.formUpdated = { + + /** + * @fires event:formUpdated + */ attach: function (context) { var $context = $(context); var contextIsForm = $context.is('form'); @@ -132,7 +157,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 keypress.formUpdated'; var eventHandler = debounce(function (event) { triggerFormUpdated(event.target); }, 300); diff --git a/core/misc/machine-name.js b/core/misc/machine-name.js index d0e4d12..62cb57a 100644 --- a/core/misc/machine-name.js +++ b/core/misc/machine-name.js @@ -1,3 +1,8 @@ +/** + * @file + * Machine name functionality. + */ + (function ($, Drupal, drupalSettings) { "use strict"; @@ -6,23 +11,25 @@ * Attach the machine-readable name form element 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 {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. */ @@ -95,9 +102,9 @@ options.maxlength = $target.attr('maxlength'); // Hide the form item container of the machine name form element. $wrapper.hide(); - // 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(); } @@ -160,15 +167,17 @@ /** * 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 * The transliterated source string. diff --git a/core/misc/progress.js b/core/misc/progress.js index 7305d24..206b4e1 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) { @@ -24,8 +31,16 @@ * 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); + * @constructor + * + * @param {string} id + * @param {function} updateCallback + * @param {string} method + * @param {function} errorCallback + * + * @example + * pb = new Drupal.ProgressBar('myProgressBar'); + * some_element.appendChild(pb.element); */ 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; @@ -109,6 +134,8 @@ /** * Display errors on the page. + * + * @param {string} string */ displayError: function (string) { var error = $('
    ').html(string); diff --git a/core/misc/states.js b/core/misc/states.js index c68d1b5..e521e1f 100644 --- a/core/misc/states.js +++ b/core/misc/states.js @@ -1,6 +1,8 @@ /** + * @file * Drupal's states library. */ + (function ($) { "use strict"; @@ -10,9 +12,16 @@ * * Having the local states variable allows us to use the States namespace * without having to always declare "Drupal.states". + * + * @namespace + * + * @name Drupal.states */ var states = Drupal.states = { - // An array of functions that should be postponed. + + /** + * An array of functions that should be postponed. + */ postponed: [] }; @@ -48,13 +57,20 @@ /** * Object representing an element that depends on other elements. * + * @constructor + * + * @name Drupal.states.Dependent + * * @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. + * Object with the following keys (all of which are required) + * @param args.element + * A jQuery object of the dependent element + * @param args.state + * A State object describing the state that is dependent + * @param 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 +87,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 RegExp + * @prop Function + * @prop Number */ states.Dependent.comparisons = { 'RegExp': function (reference, value) { @@ -81,18 +103,22 @@ 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. * + * @memberof Drupal.states.Dependent# + * * @param selector * The CSS selector describing the dependee. * @param dependeeStates @@ -113,7 +139,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,6 +162,8 @@ /** * Compares a value with a reference value. * + * @memberof Drupal.states.Dependent# + * * @param reference * The value used for reference. * @param selector @@ -160,6 +189,8 @@ /** * Update the value of a dependee's state. * + * @memberof Drupal.states.Dependent# + * * @param selector * CSS selector describing the dependee. * @param state @@ -177,6 +208,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,6 +233,8 @@ /** * Evaluates child constraints to determine if a constraint is satisfied. * + * @memberof Drupal.states.Dependent# + * * @param constraints * A constraint object or an array of constraints. * @param selector @@ -219,8 +254,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 +264,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 +283,28 @@ /** * Checks whether the value matches the requirements for this constraint. * + * @memberof Drupal.states.Dependent# + * * @param value * Either the value of a state or an array/object of constraints. In the * latter case, resolving the constraint continues. - * @param selector + * @param [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 [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 * 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; } @@ -291,11 +327,13 @@ /** * Gathers information about all required triggers. + * + * @memberof Drupal.states.Dependent# */ 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,13 @@ } }; + /** + * @constructor + * + * @name Drupal.states.Trigger + * + * @param args + */ states.Trigger = function (args) { $.extend(this, args); @@ -332,6 +377,10 @@ }; states.Trigger.prototype = { + + /** + * @memberof Drupal.states.Trigger# + */ initialize: function () { var trigger = states.Trigger.states[this.state]; @@ -351,6 +400,12 @@ this.element.data('trigger:' + this.state, true); }, + /** + * @memberof Drupal.states.Trigger# + * + * @param event + * @param valueFn + */ defaultTrigger: function (event, valueFn) { var oldValue = valueFn.call(this.element); @@ -376,6 +431,13 @@ * 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 @@ -390,9 +452,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 +496,18 @@ /** * A state object is used for describing the state and performing aliasing. + * + * @constructor + * + * @name Drupal.states.State + * + * @param 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 +531,8 @@ /** * Creates a new State object by sanitizing the passed value. + * + * @name Drupal.states.State.sanitize */ 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,16 @@ }; states.State.prototype = { + + /** + * @memberof Drupal.states.State# + */ invert: false, /** * Ensures that just using the state object returns the name. + * + * @memberof Drupal.states.State# */ toString: function () { return this.name; diff --git a/core/misc/tabbingmanager.js b/core/misc/tabbingmanager.js index dc21c02..62dee65 100644 --- a/core/misc/tabbingmanager.js +++ b/core/misc/tabbingmanager.js @@ -3,12 +3,38 @@ * 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 */ function TabbingManager() { // Tabbing sets are stored as a stack. The active set is at the top of the @@ -22,23 +48,26 @@ /** * Add public methods to the TabbingManager class. */ - $.extend(TabbingManager.prototype, { + $.extend(TabbingManager.prototype, /** @lends 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. + * + * @fires event:drupalTabbingConstrained * - * @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 TabbingContext + * @return {TabbingContext} */ 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(); @@ -70,12 +99,13 @@ /** * Restores a former tabbingContext when an active tabbingContext 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 +124,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 {TabbingContext} tabbingContext * The TabbingContext instance that has been activated. */ activate: function (tabbingContext) { @@ -115,17 +145,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 +166,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 {TabbingContext} tabbingContext * The TabbingContext instance that has been deactivated. */ deactivate: function (tabbingContext) { @@ -153,9 +184,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 +201,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,19 +245,21 @@ * * This constraint can be removed with the release() method. * - * @param Object options + * @constructor + * + * @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. + * 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. */ function TabbingContext(options) { $.extend(this, { @@ -241,11 +274,15 @@ /** * Add public methods to the TabbingContext class. */ - $.extend(TabbingContext.prototype, { + $.extend(TabbingContext.prototype, /** @lends 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 +296,8 @@ /** * Activates this TabbingContext. + * + * @fires event:drupalTabbingContextActivated */ activate: function () { // A released TabbingContext object can never be activated again. @@ -272,6 +311,8 @@ /** * Deactivates this TabbingContext. + * + * @fires event:drupalTabbingContextDeactivated */ deactivate: function () { if (this.active) { @@ -288,6 +329,10 @@ if (Drupal.tabbingManager) { return; } + + /** + * @type {TabbingManager} + */ Drupal.tabbingManager = new TabbingManager(); }(jQuery, Drupal)); diff --git a/core/misc/tabledrag.js b/core/misc/tabledrag.js index 01d4654..b3440c7 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,13 @@ * 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. */ Drupal.behaviors.tableDrag = { attach: function (context, settings) { @@ -38,11 +51,13 @@ }; /** - * Constructor for the tableDrag object. Provides table and field manipulation. + * Provides table and field manipulation. * - * @param table + * @constructor + * + * @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) { @@ -53,13 +68,17 @@ this.$table = $(table); this.table = table; this.tableSettings = tableSettings; - this.dragObject = null; // Used to hold information about a current drag operation. + 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.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. + this.rtl = $(this.table).css('direction') === 'rtl' ? -1 : 1; // Direction + // of the + // table. this.striping = $(this.table).data('striping') === 1; // Configure the scroll settings. @@ -136,7 +155,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 +164,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 @@ -171,8 +190,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 +202,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 +239,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 +259,7 @@ /** * Toggle the weight column depending on 'showWeight' value. + * * Store only default override. */ Drupal.tableDrag.prototype.toggleColumns = function () { @@ -249,6 +277,7 @@ /** * Hide the columns containing weight/parent form elements. + * * Undo showColumns(). */ Drupal.tableDrag.prototype.hideColumns = function () { @@ -266,7 +295,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 +315,9 @@ /** * Find the target used within a particular row and group. + * + * @param {string} group + * @param {HTMLElement} row */ Drupal.tableDrag.prototype.rowSettings = function (group, row) { var field = $(row).find('.' + group); @@ -308,6 +341,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; @@ -402,8 +437,8 @@ } } 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); @@ -474,9 +509,10 @@ } }); - // 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. @@ -491,11 +527,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) { @@ -570,7 +606,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. @@ -656,8 +693,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 +710,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 +762,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').eq(0); row = $row.get(0); @@ -728,10 +775,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 +791,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) { @@ -858,7 +903,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 +927,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 +945,10 @@ } }; + /** + * @param {number} cursorY + * @return {number} + */ Drupal.tableDrag.prototype.checkScroll = function (cursorY) { var de = document.documentElement; var b = document.body; @@ -921,6 +977,9 @@ } }; + /** + * @param {number} scrollAmount + */ Drupal.tableDrag.prototype.setScroll = function (scrollAmount) { var self = this; @@ -935,6 +994,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. @@ -962,16 +1024,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); @@ -1000,8 +1064,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,7 +1112,7 @@ /** * Ensure that two rows are allowed to be swapped. * - * @param row + * @param {HTMLElement} row * DOM object for the row being considered for swapping. */ Drupal.tableDrag.prototype.row.prototype.isValidSwap = function (row) { @@ -1080,9 +1147,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 +1167,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|null} prevRow * DOM object for the row before the tested position * (or null for first position in the table). - * @param nextRow + * @param {HTMLElement|null} 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 +1210,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,10 +1254,12 @@ }; /** - * 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. + * + * According to its subgroup or indentation. Note that the passed-in row is + * included in the list of siblings. * - * @param settings + * @param {object} rowSettings * The field settings we're using to identify what constitutes a sibling. */ Drupal.tableDrag.prototype.row.prototype.findSiblings = function (rowSettings) { @@ -1264,18 +1336,32 @@ /** * Stub function. Allows a custom handler when a row is swapped. + * + * @param {HTMLElement} swappedRow */ Drupal.tableDrag.prototype.row.prototype.onSwap = function (swappedRow) { return null; }; - $.extend(Drupal.theme, { + $.extend(Drupal.theme, /** @lends Drupal.theme */{ + + /** + * @return {string} + */ tableDragChangedMarker: function () { return '*'; }, + + /** + * @return {string} + */ tableDragIndentation: function () { return '
     
    '; }, + + /** + * @return {string} + */ tableDragChangedWarning: function () { return ''; } diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js index 2d6ce16..606186f 100644 --- a/core/misc/tableheader.js +++ b/core/misc/tableheader.js @@ -1,3 +1,8 @@ +/** + * @file + * Sticky table headers. + */ + (function ($, Drupal, displace) { "use strict"; @@ -48,26 +53,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 + * + * @ignore */ 'drupalViewportOffsetChange.TableHeader': tableHeaderOffsetChangeHandler }); @@ -78,21 +93,60 @@ * TableHeader will make the current table header stick to the top of the page * if the table is very long. * - * @param table - * DOM object for the table to add a sticky header to. - * * @constructor + * + * @name Drupal.TableHeader + * + * @listens event:columnschange + * + * @param {HTMLElement} table + * DOM object for the table to add a sticky header to. */ function TableHeader(table) { var $table = $(table); + /** + * @name Drupal.TableHeader#$originalTable + * + * @type {HTMLElement} + */ this.$originalTable = $table; + + /** + * @name Drupal.TableHeader#$originalHeader + * + * @type {jQuery} + */ this.$originalHeader = $table.children('thead'); + + /** + * @name Drupal.TableHeader#$originalHeaderCells + * + * @type {jQuery} + */ this.$originalHeaderCells = this.$originalHeader.find('> tr > th'); + + /** + * @name Drupal.TableHeader#displayWeight + * + * @type {null|bool} + */ this.displayWeight = null; this.$originalTable.addClass('sticky-table'); + + /** + * @name Drupal.TableHeader#tableHeight + * + * @type {number} + */ this.tableHeight = $table[0].clientHeight; + + /** + * @name Drupal.TableHeader#tableOffset + * + * @type {OffsetObject} + */ this.tableOffset = this.$originalTable.offset(); // React to columns change to avoid making checks in the scroll callback. @@ -111,11 +165,10 @@ /** * Store the state of TableHeader. */ - $.extend(TableHeader, { + $.extend(TableHeader, /** @lends Drupal.TableHeader */{ + /** * This will store the state of all processed tables. - * - * @type {Array} */ tables: [] }); @@ -123,7 +176,8 @@ /** * Extend TableHeader prototype. */ - $.extend(TableHeader.prototype, { + $.extend(TableHeader.prototype, /** @lends Drupal.TableHeader# */{ + /** * Minimum height in pixels for the table to have a sticky header. */ @@ -169,8 +223,8 @@ /** * Set absolute position of sticky. * - * @param offsetTop - * @param offsetLeft + * @param {number} offsetTop + * @param {number} offsetLeft */ stickyPosition: function (offsetTop, offsetLeft) { var css = {}; @@ -203,9 +257,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 +272,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 b4eab62..e311ad2 100644 --- a/core/misc/tableresponsive.js +++ b/core/misc/tableresponsive.js @@ -1,3 +1,8 @@ +/** + * @file + * Responsive table functionality. + */ + (function ($, Drupal, window) { "use strict"; @@ -18,14 +23,20 @@ }; /** - * 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 + * + * @name Drupal.TableResponsive + * + * @param {HTMLElement} table */ function TableResponsive(table) { this.table = table; @@ -51,7 +62,11 @@ /** * Extend the TableResponsive function with a list of managed tables. */ - $.extend(TableResponsive, { + $.extend(TableResponsive, /** @lends Drupal.TableResponsive */{ + + /** + * Store all created instances. + */ tables: [] }); @@ -61,24 +76,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 +135,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 +159,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 78e8c90..64ca89e 100644 --- a/core/misc/tableselect.js +++ b/core/misc/tableselect.js @@ -1,7 +1,15 @@ +/** + * @file + * Table select functionality. + */ + (function ($, Drupal) { "use strict"; + /** + * Initialize tableSelects. + */ Drupal.behaviors.tableSelect = { attach: function (context, settings) { // Select the inner-most table in case of nested tables. @@ -9,13 +17,18 @@ } }; + /** + * @function + */ 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; @@ -32,10 +45,12 @@ // Find all with class select-all, and insert the check all checkbox. $table.find('th.select-all').prepend($('').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.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).closest('tr').toggleClass('selected', this.checked); }); // Update the title and the state of the check all box. @@ -45,18 +60,20 @@ // 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).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 +85,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 +102,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 e7667b8..50a1d30 100644 --- a/core/misc/timezone.js +++ b/core/misc/timezone.js @@ -1,3 +1,8 @@ +/** + * @file + * Timezone detection. + */ + (function ($) { "use strict"; @@ -45,10 +50,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 1b51850..ab57435 100644 --- a/core/misc/vertical-tabs.js +++ b/core/misc/vertical-tabs.js @@ -1,11 +1,23 @@ +/** + * @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 @@ -25,7 +37,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,7 +92,13 @@ /** * The vertical tab object represents a single tab within a tab group. * - * @param settings + * @constructor + * + * @fires event:summaryUpdated + * + * @listens event:summaryUpdated + * + * @param {object} 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. @@ -114,6 +133,7 @@ }; Drupal.verticalTab.prototype = { + /** * Displays the tab's content pane. */ @@ -150,9 +170,9 @@ this.item.show(); // Show the vertical tabs. this.item.closest('.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. @@ -168,9 +188,9 @@ 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. @@ -194,7 +214,8 @@ * @param settings * An object with the following keys: * - title: The name of the tab. - * @return + * + * @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 diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index efbad03..1dd1137 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -201,7 +201,7 @@ /** * A toggle is an interactive element often bound to a click handler. * - * @return {String} + * @return {string} * A string representing a DOM fragment. */ Drupal.theme.toolbarOrientationToggle = function () { diff --git a/core/modules/toolbar/js/toolbar.menu.js b/core/modules/toolbar/js/toolbar.menu.js index c14d0d4..45e24dc 100644 --- a/core/modules/toolbar/js/toolbar.menu.js +++ b/core/modules/toolbar/js/toolbar.menu.js @@ -175,7 +175,7 @@ /** * A toggle is an interactive element often bound to a click handler. * - * @return {String} + * @return {string} * A string representing a DOM fragment. */ Drupal.theme.toolbarMenuItemToggle = function (options) {