mutation-summary
Version:
Makes observing the DOM fast and easy
156 lines • 6.74 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MutationSummary = void 0;
var Summary_1 = require("./Summary");
var MutationProjection_1 = require("./MutationProjection");
var MutationSummaryOptionProcessor_1 = require("./MutationSummaryOptionProcessor");
/**
* This is the main entry point class for the Mutation Summary library. When
* created, a MutationSummary takes care of the details of observing the DOM
* for changes, computing the "net-effect" of what's changed and then delivers
* these changes to the provided callback.
*
* @example
* ```
*
* const ms = new MutationSummary({
* callback(summaries: Summary[]) {
* summaries.forEach((summary: Summary) => console.log(summary));
* },
* queries: [
* { all: true }
* ]
* });
* ```
*/
var MutationSummary = /** @class */ (function () {
/**
* Creates a new MutationSummary class using the specified options.
*
* @param opts The options that configure how the MutationSummary
* instance will observe and report changes.
*/
function MutationSummary(opts) {
var _this = this;
this._connected = false;
this._options = MutationSummaryOptionProcessor_1.MutationSummaryOptionProcessor.validateOptions(opts);
this._observerOptions = MutationSummaryOptionProcessor_1.MutationSummaryOptionProcessor.createObserverOptions(this._options.queries);
this._root = this._options.rootNode;
this._callback = this._options.callback;
this._elementFilter = Array.prototype.concat.apply([], this._options.queries.map(function (query) {
return query.elementFilter ? query.elementFilter : [];
}));
if (!this._elementFilter.length)
this._elementFilter = undefined;
this._calcReordered = this._options.queries.some(function (query) {
return query.all;
});
this._queryValidators = []; // TODO(rafaelw): Shouldn't always define this.
if (MutationSummary.createQueryValidator) {
this._queryValidators = this._options.queries.map(function (query) {
return MutationSummary.createQueryValidator(_this._root, query);
});
}
this._observer = new MutationObserver(function (mutations) {
_this._observerCallback(mutations);
});
this.reconnect();
}
/**
* Starts observation using an existing `MutationSummary` which has been
* disconnected. Note that this function is just a convenience method for
* creating a new `MutationSummary` with the same options. The next time
* changes are reported, they will relative to the state of the observed
* DOM at the point that `reconnect` was called.
*/
MutationSummary.prototype.reconnect = function () {
if (this._connected)
throw Error('Already connected');
this._observer.observe(this._root, this._observerOptions);
this._connected = true;
this._checkpointQueryValidators();
};
/**
* Immediately calculates changes and returns them as an array of summaries.
* If there are no changes to report, returns undefined.
*/
MutationSummary.prototype.takeSummaries = function () {
if (!this._connected)
throw Error('Not connected');
var summaries = this._createSummaries(this._observer.takeRecords());
return this._changesToReport(summaries) ? summaries : undefined;
};
/**
* Discontinues observation immediately. If DOM changes are pending delivery,
* they will be fetched and reported as the same array of summaries which
* are handed into the callback. If there is nothing to report,
* this function returns undefined.
*
* @returns A list of changes that have not yet been delivered to a callback.
*/
MutationSummary.prototype.disconnect = function () {
var summaries = this.takeSummaries();
this._observer.disconnect();
this._connected = false;
return summaries;
};
MutationSummary.prototype._observerCallback = function (mutations) {
if (!this._options.observeOwnChanges)
this._observer.disconnect();
var summaries = this._createSummaries(mutations);
this._runQueryValidators(summaries);
if (this._options.observeOwnChanges)
this._checkpointQueryValidators();
if (this._changesToReport(summaries))
this._callback(summaries);
// disconnect() may have been called during the callback.
if (!this._options.observeOwnChanges && this._connected) {
this._checkpointQueryValidators();
this._observer.observe(this._root, this._observerOptions);
}
};
MutationSummary.prototype._createSummaries = function (mutations) {
if (!mutations || !mutations.length)
return [];
var projection = new MutationProjection_1.MutationProjection(this._root, mutations, this._elementFilter, this._calcReordered, this._options.oldPreviousSibling);
var summaries = [];
for (var i = 0; i < this._options.queries.length; i++) {
summaries.push(new Summary_1.Summary(projection, this._options.queries[i]));
}
return summaries;
};
MutationSummary.prototype._checkpointQueryValidators = function () {
this._queryValidators.forEach(function (validator) {
if (validator)
validator.recordPreviousState();
});
};
MutationSummary.prototype._runQueryValidators = function (summaries) {
this._queryValidators.forEach(function (validator, index) {
if (validator)
validator.validate(summaries[index]);
});
};
MutationSummary.prototype._changesToReport = function (summaries) {
return summaries.some(function (summary) {
var summaryProps = ['added', 'removed', 'reordered', 'reparented',
'valueChanged', 'characterDataChanged'];
if (summaryProps.some(function (prop) {
return summary[prop] && summary[prop].length;
}))
return true;
if (summary.attributeChanged) {
var attrNames = Object.keys(summary.attributeChanged);
var attrsChanged = attrNames.some(function (attrName) {
return !!summary.attributeChanged[attrName].length;
});
if (attrsChanged)
return true;
}
return false;
});
};
return MutationSummary;
}());
exports.MutationSummary = MutationSummary;
//# sourceMappingURL=MutationSummary.js.map