Voltrun
Voltrun

Reputation: 77

Own beforeSave handler for the apostrophe widget

How to code the beforeSave() handler for the apostrophe widget? This code in the widget index.js does not work for me:

module.exports = {
  extend: 'apostrophe-widgets',
  label: 'My widget',
  addFields: [
  {
      name: 'label',
      type: 'string',
      label: 'Caption',
      required: true
  }
  ],
  construct: function(self, options) {

    self.beforeSave = function(callback) {
      console.log("beforeSave");
      return callback();
    }
  }
};

When I save an instance of a widget, the log does not change. Is it possible to code your own beforeSave() handler for widgets as for pieces?

Upvotes: 2

Views: 249

Answers (1)

Tom Boutell
Tom Boutell

Reputation: 7572

A widget is just one part of a document, and documents are saved to the database as a unit, not individual widgets. So there is no beforeSave.

However if what you want to do is take some action each time a widget is sanitized for potential inclusion in a document that may be saved, take a look at the sanitize method:

self.sanitize = function(req, input, callback) {
  var output = self.apos.schemas.newInstance(self.schema);
  var schema = self.allowedSchema(req);
  output._id = self.apos.launder.id(input._id) || self.apos.utils.generateId();
  return self.apos.schemas.convert(req, schema, 'form', input, output, function(err) {
    if (err) {
      return callback(err);
    }
    output.type = self.name;
    return callback(null, output);
  });
};

Notice how this method takes input, which is the data the browser provided, and runs it through apos.schemas.convert to copy only the valid data to output. Then it sends output to its callback.

We can use the "super pattern" to make a change at the end of this process. For instance, rich text widgets usually don't have a schema, they just have a content property containing markup. But, they might have a schema too on some sites. So here is how the apostrophe-rich-text-widgets module uses the "super pattern" to extend the sanitize method to accept the additional content, without losing the ability to save schema content:

var superSanitize = self.sanitize;
self.sanitize = function(req, input, callback) {
  return superSanitize(req, input, function(err, output) {
    if (err) {
      return callback(err);
    }
    output.content = sanitizeHtml(input.content, self.options.sanitizeHtml);
    return callback(null, output);
  });
};

Notice that:

  • The original version of the method is captured in the variable superSanitize. Then a new function is assigned as the method.
  • The original version of superSanitize is called. If it fails we deal with that first.
  • output is modified. Any changes you make to output will go directly into the widget in the document, so make sure you validate any content you are accepting from input. Browsers (and scripts written by hackers) can lie.
  • We end the same way the original method does: by invoking the callback with (null, output).

Upvotes: 2

Related Questions