Commit b6ed6e74 authored by webchick's avatar webchick
Browse files

Issue #2530764 by eiriksm: JSDoc quickedit module

parent 95757077
......@@ -32,7 +32,9 @@
* @inheritdoc
*
* @param {object} fieldModel
* The field model that holds the state.
* @param {string} state
* The state to change to.
*/
stateChange: function (fieldModel, state) {
var from = fieldModel.previous('state');
......@@ -80,6 +82,7 @@
* @inheritdoc
*
* @return {object}
* A settings object for the quick edit UI.
*/
getQuickEditUISettings: function () {
return {padding: true, unifiedToolbar: true, fullWidthToolbar: true, popup: true};
......
......@@ -20,6 +20,7 @@
* @augments Drupal.quickedit.EditorView
*
* @param {object} options
* Options for the plain text editor.
*/
initialize: function (options) {
Drupal.quickedit.EditorView.prototype.initialize.call(this, options);
......@@ -55,6 +56,7 @@
* @inheritdoc
*
* @return {jQuery}
* The text element for the plain text editor.
*/
getEditedElement: function () {
return this.$textElement;
......@@ -64,8 +66,11 @@
* @inheritdoc
*
* @param {object} fieldModel
* The field model that holds the state.
* @param {string} state
* The state to change to.
* @param {object} options
* State options, if needed by the state change.
*/
stateChange: function (fieldModel, state, options) {
var from = fieldModel.previous('state');
......@@ -121,6 +126,7 @@
* @inheritdoc
*
* @return {object}
* A settings object for the quick edit UI.
*/
getQuickEditUISettings: function () {
return {padding: true, unifiedToolbar: false, fullWidthToolbar: false, popup: false};
......
......@@ -15,8 +15,10 @@
* @augments Backbone.Model
*
* @param {object} options
* Options for the base model-
*
* @return {Drupal.quickedit.BaseModel}
* A quickedit base model.
*/
initialize: function (options) {
this.__initialized = true;
......@@ -24,12 +26,18 @@
},
/**
* Set a value on the model
*
* @param {object|string} key
* The key to set a value for.
* @param {*} val
* The value to set.
* @param {object} [options]
* Options for the model.
*
* @return {*}
* The result of `Backbone.Model.prototype.set` with the specified
* parameters.
*/
set: function (key, val, options) {
if (this.__initialized) {
......
......@@ -159,10 +159,12 @@
* Updates FieldModels' states when an EntityModel change occurs.
*
* @param {Drupal.quickedit.EntityModel} entityModel
* The entity model
* @param {string} state
* The state of the associated entity. One of
* {@link Drupal.quickedit.EntityModel.states}.
* @param {object} options
* Options for the entity model.
*/
stateChange: function (entityModel, state, options) {
var to = state;
......@@ -193,7 +195,8 @@
case 'committing':
// The user indicated they want to save the entity.
var fields = this.get('fields');
// For fields that are in an active state, transition them to candidate.
// For fields that are in an active state, transition them to
// candidate.
fields.chain()
.filter(function (fieldModel) {
return _.intersection([fieldModel.get('state')], ['active']).length;
......@@ -218,15 +221,15 @@
return _.intersection([fieldModel.get('state')], ['changed', 'invalid']).length;
});
// If the entity contains unconfirmed or unsaved changes, return the
// entity to an opened state and ask the user if they would like to save
// the changes or discard the changes.
// 1. One of the fields is in a changed state. The changed field might
// just be a change in the client or it might have been saved to
// tempstore.
// 2. The saved flag is empty and the confirmed flag is empty. If the
// entity has been saved to the server, the fields changed in the
// client are irrelevant. If the changes are confirmed, then proceed
// to set the fields to candidate state.
// entity to an opened state and ask the user if they would like to
// save the changes or discard the changes.
// 1. One of the fields is in a changed state. The changed field
// might just be a change in the client or it might have been saved
// to tempstore.
// 2. The saved flag is empty and the confirmed flag is empty. If
// the entity has been saved to the server, the fields changed in
// the client are irrelevant. If the changes are confirmed, then
// proceed to set the fields to candidate state.
if ((changedFields.length || this.get('fieldsInTempStore').length) && (!options.saved && !options.confirmed)) {
// Cancel deactivation until the user confirms save or discard.
this.set('state', 'opened', {confirming: true});
......@@ -243,12 +246,12 @@
// Indicate if this EntityModel needs to be reloaded in order to
// restore the original values of its fields.
entityModel.set('reload', (this.get('fieldsInTempStore').length || invalidFields.length));
// Set all fields to the 'candidate' state. A changed field may have to
// go through confirmation first.
// Set all fields to the 'candidate' state. A changed field may have
// to go through confirmation first.
entityModel.get('fields').each(function (fieldModel) {
// If the field is already in the candidate state, trigger a change
// event so that the entityModel can move to the next state in
// deactivation.
// If the field is already in the candidate state, trigger a
// change event so that the entityModel can move to the next state
// in deactivation.
if (_.intersection([fieldModel.get('state')], ['candidate', 'highlighted']).length) {
fieldModel.trigger('change:state', fieldModel, fieldModel.get('state'), options);
}
......@@ -278,7 +281,8 @@
* Helper function.
*
* @param {Drupal.quickedit.EntityModel} entityModel
* The model of the entity for which a field's state attribute has changed.
* The model of the entity for which a field's state attribute has
* changed.
* @param {Drupal.quickedit.FieldModel} fieldModel
* The model of the field whose state attribute has changed.
*
......@@ -325,12 +329,12 @@
var entityModel = this;
var fieldState = state;
// Switch on the entityModel state.
// The EntityModel responds to FieldModel state changes as a function of its
// state. For example, a field switching back to 'candidate' state when its
// entity is in the 'opened' state has no effect on the entity. But that
// same switch back to 'candidate' state of a field when the entity is in
// the 'committing' state might allow the entity to proceed with the commit
// flow.
// The EntityModel responds to FieldModel state changes as a function of
// its state. For example, a field switching back to 'candidate' state
// when its entity is in the 'opened' state has no effect on the entity.
// But that same switch back to 'candidate' state of a field when the
// entity is in the 'committing' state might allow the entity to proceed
// with the commit flow.
switch (this.get('state')) {
case 'closed':
case 'launching':
......@@ -339,13 +343,14 @@
break;
case 'opening':
// We must change the entity to the 'opened' state, but it must first be
// confirmed that all of its fieldModels have transitioned to the
// We must change the entity to the 'opened' state, but it must first
// be confirmed that all of its fieldModels have transitioned to the
// 'candidate' state.
// We do this here, because this is called every time a fieldModel
// changes state, hence each time this is called, we get closer to the
// goal of having all fieldModels in the 'candidate' state.
// A state change in reaction to another state change must be deferred.
// A state change in reaction to another state change must be
// deferred.
_.defer(function () {
entityModel.set('state', 'opened', {
'accept-field-states': Drupal.quickedit.app.readyFieldStates
......@@ -374,7 +379,8 @@
// If the field save returned a validation error, set the state of the
// entity back to 'opened'.
if (fieldState === 'invalid') {
// A state change in reaction to another state change must be deferred.
// A state change in reaction to another state change must be
// deferred.
_.defer(function () {
entityModel.set('state', 'opened', {reason: 'invalid'});
});
......@@ -383,8 +389,8 @@
this._updateInTempStoreAttributes(entityModel, fieldModel);
}
// Attempt to save the entity. If the entity's fields are not yet all in
// a ready state, the save will not be processed.
// Attempt to save the entity. If the entity's fields are not yet all
// in a ready state, the save will not be processed.
var options = {
'accept-field-states': Drupal.quickedit.app.readyFieldStates
};
......@@ -399,8 +405,8 @@
error: function () {
// Reset the "isCommitting" mutex.
entityModel.set('isCommitting', false);
// Change the state back to "opened", to allow the user to hit the
// "Save" button again.
// Change the state back to "opened", to allow the user to hit
// the "Save" button again.
entityModel.set('state', 'opened', {reason: 'networkerror'});
// Show a modal to inform the user of the network error.
var message = Drupal.t('Your changes to <q>@entity-title</q> could not be saved, either due to a website problem or a network connection problem.<br>Please try again.', {'@entity-title': entityModel.get('label')});
......@@ -413,7 +419,8 @@
case 'deactivating':
// When setting the entity to 'closing', require that all fieldModels
// are in either the 'candidate' or 'highlighted' state.
// A state change in reaction to another state change must be deferred.
// A state change in reaction to another state change must be
// deferred.
_.defer(function () {
entityModel.set('state', 'closing', {
'accept-field-states': Drupal.quickedit.app.readyFieldStates
......@@ -422,9 +429,10 @@
break;
case 'closing':
// When setting the entity to 'closed', require that all fieldModels are
// in the 'inactive' state.
// A state change in reaction to another state change must be deferred.
// When setting the entity to 'closed', require that all fieldModels
// are in the 'inactive' state.
// A state change in reaction to another state change must be
// deferred.
_.defer(function () {
entityModel.set('state', 'closed', {
'accept-field-states': ['inactive']
......@@ -449,7 +457,7 @@
var entitySaverAjax = Drupal.ajax({
url: Drupal.url('quickedit/entity/' + entityModel.get('entityID')),
error: function () {
// Let the Drupal.quickedit.EntityModel Backbone model's error()=
// Let the Drupal.quickedit.EntityModel Backbone model's error()
// method handle errors.
options.error.call(entityModel);
}
......@@ -476,6 +484,7 @@
},
/**
* Validate the entity model.
*
* @param {object} attrs
* The attributes changes in the save or set call.
......@@ -492,6 +501,7 @@
* validate and proceed.
*
* @return {string}
* A string to say something about the state of the entity model.
*/
validate: function (attrs, options) {
var acceptedFieldStates = options['accept-field-states'] || [];
......@@ -531,14 +541,21 @@
},
/**
* Checks if a state change can be accepted.
*
* @param {string} from
* From state.
* @param {string} to
* To state.
* @param {object} context
* Context for the check.
* @param {string} context.reason
* The reason for the state change.
* @param {bool} context.confirming
* Whether context is confirming or not.
*
* @return {bool}
* Whether the state change is accepted or not.
*
* @see Drupal.quickedit.AppView#acceptEditorStateChange
*/
......@@ -557,8 +574,8 @@
accept = true;
}
// Allow: committing -> opened.
// Necessary to be able to correct an invalid field, or to hit the "Save"
// button again after a server/network error.
// Necessary to be able to correct an invalid field, or to hit the
// "Save" button again after a server/network error.
else if (from === 'committing' && to === 'opened' && context.reason && (context.reason === 'invalid' || context.reason === 'networkerror')) {
accept = true;
}
......@@ -578,9 +595,13 @@
},
/**
* Checks if fields have acceptable states.
*
* @param {Array} acceptedFieldStates
* An array of acceptable field states to check for.
*
* @return {bool}
* Whether the fields have an acceptable state.
*
* @see Drupal.quickedit.EntityModel#validate
*/
......@@ -603,7 +624,10 @@
},
/**
* Destroys the entity model.
*
* @param {object} options
* Options for the entity model.
*/
destroy: function (options) {
Drupal.quickedit.BaseModel.prototype.destroy.call(this, options);
......@@ -646,10 +670,11 @@
'launching',
// Launching has finished.
// - Trigger: application.
// - Guarantees: in-place editors ready for use, all entity and field views
// have been set up, all fields are in the 'inactive' state.
// - Expected behavior: all fields are changed to the 'candidate' state and
// once this is completed, the entity state will be changed to 'opened'.
// - Guarantees: in-place editors ready for use, all entity and field
// views have been set up, all fields are in the 'inactive' state.
// - Expected behavior: all fields are changed to the 'candidate' state
// and once this is completed, the entity state will be changed to
// 'opened'.
'opening',
// Opening has finished.
// - Trigger: EntityModel.
......@@ -668,14 +693,15 @@
// to 'opened', otherwise: save the entity by committing it from
// PrivateTempStore into permanent storage.
'committing',
// User has clicked the 'Close' button, or has clicked the 'Save' button and
// that was successfully completed.
// User has clicked the 'Close' button, or has clicked the 'Save' button
// and that was successfully completed.
// - Trigger: user or EntityModel.
// - Guarantees: when having clicked 'Close' hardly any: fields may be in a
// variety of states; when having clicked 'Save': all fields are in the
// 'candidate' state.
// - Guarantees: when having clicked 'Close' hardly any: fields may be in
// a variety of states; when having clicked 'Save': all fields are in
// the 'candidate' state.
// - Expected behavior: transition all fields to the 'candidate' state,
// possibly requiring confirmation in the case of having clicked 'Close'.
// possibly requiring confirmation in the case of having clicked
// 'Close'.
'deactivating',
// Deactivation has been completed.
// - Trigger: EntityModel.
......@@ -693,6 +719,7 @@
* One of {@link Drupal.quickedit.EntityModel.states}.
*
* @return {bool}
* Whether the 'from' state comes before the 'to' state.
*/
followsStateSequence: function (from, to) {
return _.indexOf(this.states, from) < _.indexOf(this.states, to);
......
......@@ -114,6 +114,7 @@
* @augments Drupal.quickedit.BaseModel
*
* @param {object} options
* Options for the field model.
*/
initialize: function (options) {
// Store the original full HTML representation of this field.
......@@ -130,8 +131,10 @@
},
/**
* Destroys the field model.
*
* @param {object} options
* Options for the field model.
*/
destroy: function (options) {
if (this.get('state') !== 'inactive') {
......@@ -149,6 +152,7 @@
},
/**
* Validate function for the field model.
*
* @param {object} attrs
* The attributes changes in the save or set call.
......@@ -165,6 +169,7 @@
* validate and proceed.
*
* @return {string}
* A string to say something about the state of the field model.
*/
validate: function (attrs, options) {
var current = this.get('state');
......@@ -319,6 +324,7 @@
* One of {@link Drupal.quickedit.FieldModel.states}.
*
* @return {bool}
* Whether the 'from' state comes before the 'to' state.
*/
followsStateSequence: function (from, to) {
return _.indexOf(this.states, from) < _.indexOf(this.states, to);
......
......@@ -160,29 +160,42 @@
metadata: {
/**
* Check if a field exists in storage.
*
* @param {string} fieldID
* The field id to check.
*
* @return {bool}
* Whether it was found or not.
*/
has: function (fieldID) {
return storage.getItem(this._prefixFieldID(fieldID)) !== null;
},
/**
* Add metadata to a field id.
*
* @param {string} fieldID
* The field ID to add data to.
* @param {object} metadata
* Metadata to add.
*/
add: function (fieldID, metadata) {
storage.setItem(this._prefixFieldID(fieldID), JSON.stringify(metadata));
},
/**
* Get a key from a field id.
*
* @param {string} fieldID
* The field ID to check.
* @param {string} [key]
* The key to check. If empty, will return all metadata.
*
* @return {object|*}
* The value for the key, if defined. Otherwise will return all metadata
* for the specified field id.
*
*/
get: function (fieldID, key) {
var metadata = JSON.parse(storage.getItem(this._prefixFieldID(fieldID)));
......@@ -190,20 +203,26 @@
},
/**
* Prefix the field id.
*
* @param {string} fieldID
* The field id to prefix.
*
* @return {string}
* A prefixed field id.
*/
_prefixFieldID: function (fieldID) {
return 'Drupal.quickedit.metadata.' + fieldID;
},
/**
* Unprefix the field id.
*
* @param {string} fieldID
* The field id to unprefix.
*
* @return {string}
* An unprefixed field id.
*/
_unprefixFieldID: function (fieldID) {
// Strip "Drupal.quickedit.metadata.", which is 26 characters long.
......@@ -211,10 +230,13 @@
},
/**
* Intersection calculation.
*
* @param {string} fieldIDs
* @param {Array} fieldIDs
* An array of field ids to compare to prefix field id.
*
* @return {Array}
* The intersection found.
*/
intersection: function (fieldIDs) {
var prefixedFieldIDs = _.map(fieldIDs, this._prefixFieldID);
......@@ -246,7 +268,9 @@
* Queue contextual links to be processed.
*
* @param {jQuery.Event} event
* The `drupalContextualLinkAdded` event.
* @param {object} data
* An object containing the data relevant to the event.
*
* @listens event:drupalContextualLinkAdded
*/
......
......@@ -11,6 +11,7 @@
* Theme function for a "backstage" for the Quick Edit module.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {string} settings.id
* The id to apply to the backstage.
*
......@@ -27,6 +28,7 @@
* Theme function for a toolbar container of the Quick Edit module.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {string} settings.id
* the id to apply to the backstage.
*
......@@ -50,6 +52,7 @@
* Theme function for a toolbar container of the Quick Edit module.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {string} settings.entityLabel
* The title of the active entity.
* @param {string} settings.fieldLabel
......@@ -77,6 +80,7 @@
* Theme function for a toolbar container of the Quick Edit module.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {string} settings.id
* The id to apply to the toolbar container.
*
......@@ -91,6 +95,7 @@
* Theme function for a toolbar toolgroup of the Quick Edit module.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {string} [settings.id]
* The id of the toolgroup.
* @param {string} settings.classes
......@@ -123,6 +128,7 @@
* modal.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {Array} settings.buttons
* - String type: the type of the button (defaults to 'button')
* - Array classes: the classes of the button.
......@@ -157,6 +163,7 @@
* Theme function for a form container of the Quick Edit module.
*
* @param {object} settings
* Settings object used to construct the markup.
* @param {string} settings.id
* The id to apply to the toolbar container.
* @param {string} settings.loadingMsg
......
......@@ -38,6 +38,7 @@
* The Controller route for field processing.
*
* @return {string}
* The formatted URL.
*/
Drupal.quickedit.util.buildUrl = function (id, urlFormat) {
var parts = id.split('/');
......@@ -146,6 +147,7 @@
* Creates a {@link Drupal.Ajax} instance that is used to save a form.
*
* @param {object} options
* Submit options to the form.
* @param {bool} options.nocssjs
* Boolean indicating whether no CSS and JS should be returned (necessary
* when the form is invisible to the user).
......@@ -153,6 +155,7 @@
* Array containing view mode IDs (of other instances of this field on the
* page).
* @param {jQuery} $submit
* The submit element.
*
* @return {Drupal.Ajax}
* A {@link Drupal.Ajax} instance.
......@@ -176,7 +179,9 @@
* form.
*
* @param {Drupal.AjaxCommands~commandDefinition} response
* The Drupal AJAX response.
* @param {number} [status]
* The HTTP status code.
*/
success: function (response, status) {
for (var i in response) {
......
......@@ -127,6 +127,7 @@
* The fieldModel to which this change applies.
*
* @return {bool}
* Whether the editor change was accepted or rejected.
*/
acceptEditorStateChange: function (from, to, context, fieldModel) {
var accept = true;
......@@ -328,6 +329,7 @@
* Asks the user to confirm whether he wants to stop editing via a modal.
*
* @param {Drupal.quickedit.EntityModel} entityModel
* An instance of the EntityModel class.
*
* @see Drupal.quickedit.AppView#acceptEditorStateChange
*/
......@@ -402,6 +404,7 @@
* Reacts to field state changes; tracks global state.
*
* @param {Drupal.quickedit.FieldModel} fieldModel
* The `fieldModel` holding the state.
* @param {string} state
* The state of the associated field. One of
* {@link Drupal.quickedit.FieldModel.states}.
......
......@@ -13,6 +13,7 @@
* Define all events to listen to.
*
* @return {object}
* A map of events.
*/
events: function () {
// Prevents delay and simulated mouse events.