regexper-static/src/js/parser/javascript/match.js

109 lines
3.2 KiB
JavaScript
Raw Normal View History

2015-04-22 00:23:55 +00:00
// Match nodes are used for the parts of a regular expression between `|`
// symbols. They consist of a series of [MatchFragment](./match_fragment.html)
// nodes. Optional `^` and `$` symbols are also allowed at the beginning and
// end of the Match.
import util from '../../util.js';
import _ from 'lodash';
export default {
type: 'match',
2014-12-17 21:04:55 +00:00
definedProperties: {
2015-04-22 00:23:55 +00:00
// Default anchor is overridden to attach the left point of the anchor to
// the first element, and the right point to the last element.
2014-12-17 21:04:55 +00:00
_anchor: {
get: function() {
var start = util.normalizeBBox(this.start.getBBox()),
end = util.normalizeBBox(this.end.getBBox()),
2014-12-17 21:04:55 +00:00
matrix = this.transform().localMatrix;
return {
ax: matrix.x(start.ax, start.ay),
ax2: matrix.x(end.ax2, end.ay),
ay: matrix.y(start.ax, start.ay)
};
}
}
},
2015-04-22 00:23:55 +00:00
// Renders the match into the currently set container.
_render() {
var partPromises,
items;
2015-04-22 00:23:55 +00:00
// Render each of the match fragments.
2014-12-17 20:12:04 +00:00
partPromises = _.map(this.parts, part => {
return part.render(this.container.group());
});
2014-12-15 02:37:56 +00:00
items = _(partPromises).compact().value();
2015-04-22 00:23:55 +00:00
// Handle the situation where a regular expression of `()` is rendered.
// This leads to a Match node with no fragments. Something must be rendered
// so that the anchor can be calculated based on it.
//
// Furthermore, the content rendered must have height and width or else the
// anchor calculations fail.
if (items.length === 0) {
items = [this.container.group().path('M0,0h10')];
}
2015-03-14 21:11:14 +00:00
return Promise.all(items)
2014-12-17 20:12:04 +00:00
.then(items => {
2015-04-22 00:23:55 +00:00
// Find SVG elements to be used when calculating the anchor.
this.start = _.first(items);
this.end = _.last(items);
util.spaceHorizontally(items, {
2014-12-17 20:12:04 +00:00
padding: 10
});
2014-12-15 02:37:56 +00:00
2015-04-22 00:23:55 +00:00
// Add lines between each item.
2014-12-17 20:12:04 +00:00
this.container.prepend(
2014-12-26 17:48:02 +00:00
this.container.path(this.connectorPaths(items).join('')));
2014-12-17 20:12:04 +00:00
});
},
2015-04-22 00:23:55 +00:00
// Returns an array of SVG path strings between each item.
// - __items__ - Array of SVG elements or nodes.
2014-12-26 17:48:02 +00:00
connectorPaths(items) {
var prev, next;
prev = util.normalizeBBox(_.first(items).getBBox());
return _.map(items.slice(1), item => {
try {
next = util.normalizeBBox(item.getBBox());
return `M${prev.ax2},${prev.ay}H${next.ax}`;
}
finally {
prev = next;
}
});
},
setup() {
2015-04-22 00:23:55 +00:00
// Merged list of MatchFragments to be rendered.
this.parts = _.reduce(this.properties.parts.elements, function(result, node) {
2014-12-11 01:11:51 +00:00
var last = _.last(result);
2014-12-17 19:56:02 +00:00
if (last && node.canMerge && last.canMerge) {
2015-04-22 00:23:55 +00:00
// Merged the content of `node` into `last` when possible. This also
// discards `node` in the process since `result` has not been changed.
2014-12-26 17:48:02 +00:00
last.content.merge(node.content);
2014-12-11 01:11:51 +00:00
} else {
2015-04-22 00:23:55 +00:00
// `node` cannot be merged with the previous node, so it is added to
// the list of parts.
2014-12-11 01:11:51 +00:00
result.push(node);
}
return result;
}, []);
2014-12-15 00:08:14 +00:00
// When there is only one part, then proxy to the part.
if (this.parts.length === 1) {
2014-12-17 20:12:04 +00:00
this.proxy = this.parts[0];
}
}
};