drupal/core/modules/edit/js/backbone.drupalform.js

165 lines
6.9 KiB
JavaScript

/**
* @file
* Backbone.sync implementation for Edit. This is the beating heart.
*/
(function (jQuery, Backbone, Drupal) {
"use strict";
Backbone.defaultSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
if (options.editor.options.editorName === 'form') {
return Backbone.syncDrupalFormWidget(method, model, options);
}
else {
return Backbone.syncDirect(method, model, options);
}
};
/**
* Performs syncing for "form" PredicateEditor widgets.
*
* Implemented on top of Form API and the AJAX commands framework. Sets up
* scoped AJAX command closures specifically for a given PredicateEditor widget
* (which contains a pre-existing form). By submitting the form through
* Drupal.ajax and leveraging Drupal.ajax' ability to have scoped (per-instance)
* command implementations, we are able to update the VIE model, re-render the
* form when there are validation errors and ensure no Drupal.ajax memory leaks.
*
* @see Drupal.edit.util.form
*/
Backbone.syncDrupalFormWidget = function(method, model, options) {
if (method === 'update') {
var predicate = options.editor.options.property;
var $formContainer = options.editor.$formContainer;
var $submit = $formContainer.find('.edit-form-submit');
var base = $submit.attr('id');
// Successfully saved.
Drupal.ajax[base].commands.editFieldFormSaved = function(ajax, response, status) {
Drupal.edit.util.form.unajaxifySaving(jQuery(ajax.element));
// Call Backbone.sync's success callback with the rerendered field.
var changedAttributes = {};
// @todo: POSTPONED_ON(Drupal core, http://drupal.org/node/1784216)
// Once full JSON-LD support in Drupal core lands, we can ensure that the
// models that VIE maintains are properly updated.
changedAttributes[predicate] = undefined;
changedAttributes[predicate + '/rendered'] = response.data;
options.success(changedAttributes);
};
// Unsuccessfully saved; validation errors.
Drupal.ajax[base].commands.editFieldFormValidationErrors = function(ajax, response, status) {
// Call Backbone.sync's error callback with the validation error messages.
options.error(response.data);
};
// The edit_field_form AJAX command is only called upon loading the form for
// the first time, and when there are validation errors in the form; Form
// API then marks which form items have errors. Therefor, we have to replace
// the existing form, unbind the existing Drupal.ajax instance and create a
// new Drupal.ajax instance.
Drupal.ajax[base].commands.editFieldForm = function(ajax, response, status) {
Drupal.edit.util.form.unajaxifySaving(jQuery(ajax.element));
Drupal.ajax.prototype.commands.insert(ajax, {
data: response.data,
selector: '#' + $formContainer.attr('id') + ' form'
});
// Create a Drupa.ajax instance for the re-rendered ("new") form.
var $newSubmit = $formContainer.find('.edit-form-submit');
Drupal.edit.util.form.ajaxifySaving({ nocssjs: false }, $newSubmit);
};
// Click the form's submit button; the scoped AJAX commands above will
// handle the server's response.
$submit.trigger('click.edit');
}
};
/**
* Performs syncing for "direct" PredicateEditor widgets.
*
* @see Backbone.syncDrupalFormWidget()
* @see Drupal.edit.util.form
*/
Backbone.syncDirect = function(method, model, options) {
if (method === 'update') {
var fillAndSubmitForm = function(value) {
jQuery('#edit_backstage form')
// Fill in the value in any <input> that isn't hidden or a submit button.
.find(':input[type!="hidden"][type!="submit"]:not(select)').val(value).end()
// Submit the form.
.find('.edit-form-submit').trigger('click.edit');
};
var entity = options.editor.options.entity;
var predicate = options.editor.options.property;
var value = model.get(predicate);
// If form doesn't already exist, load it and then submit.
if (jQuery('#edit_backstage form').length === 0) {
var formOptions = {
propertyID: Drupal.edit.util.calcPropertyID(entity, predicate),
$editorElement: options.editor.element,
nocssjs: true
};
Drupal.edit.util.form.load(formOptions, function(form, ajax) {
// Create a backstage area for storing forms that are hidden from view
// (hence "backstage" — since the editing doesn't happen in the form, it
// happens "directly" in the content, the form is only used for saving).
jQuery(Drupal.theme('editBackstage', { id: 'edit_backstage' })).appendTo('body');
// Direct forms are stuffed into #edit_backstage, apparently.
jQuery('#edit_backstage').append(form);
// Disable the browser's HTML5 validation; we only care about server-
// side validation. (Not disabling this will actually cause problems
// because browsers don't like to set HTML5 validation errors on hidden
// forms.)
jQuery('#edit_backstage form').attr('novalidate', true);
var $submit = jQuery('#edit_backstage form .edit-form-submit');
var base = Drupal.edit.util.form.ajaxifySaving(formOptions, $submit);
// Successfully saved.
Drupal.ajax[base].commands.editFieldFormSaved = function (ajax, response, status) {
Drupal.edit.util.form.unajaxifySaving(jQuery(ajax.element));
jQuery('#edit_backstage form').remove();
// Call Backbone.sync's success callback with the rerendered field.
var changedAttributes = {};
// @todo: POSTPONED_ON(Drupal core, http://drupal.org/node/1784216)
// Once full JSON-LD support in Drupal core lands, we can ensure that the
// models that VIE maintains are properly updated.
changedAttributes[predicate] = jQuery(response.data).find('.field-item').html();
changedAttributes[predicate + '/rendered'] = response.data;
options.success(changedAttributes);
};
// Unsuccessfully saved; validation errors.
Drupal.ajax[base].commands.editFieldFormValidationErrors = function(ajax, response, status) {
// Call Backbone.sync's error callback with the validation error messages.
options.error(response.data);
};
// The editFieldForm AJAX command is only called upon loading the form
// for the first time, and when there are validation errors in the form;
// Form API then marks which form items have errors. This is useful for
// "form" editors, but pointless for "direct" editors: the form itself
// won't be visible at all anyway! Therefor, we ignore the new form and
// we continue to use the existing form.
Drupal.ajax[base].commands.editFieldForm = function(ajax, response, status) {
// no-op
};
fillAndSubmitForm(value);
});
}
else {
fillAndSubmitForm(value);
}
}
};
})(jQuery, Backbone, Drupal);