Metafilters

A "metafilter" is a global filter that's always active in addition to the current "regular" user-selected filter (e.g., an era or ratings filter). This allows a metafilter to further narrow the list of games selected by the current regular filter, or even to override the regular filter's decisions by ruling in some of the games that the regular filter ruled out.

Metafilters are useful for additional layers of filtering that you want to keep in effect at all times while still letting the user select games with the regular filters. For example, a metafilter could be used for a "family mode" setting that excludes games that you've marked as having adult themes. While this family metafilter is in effect, the user can still filter games normally (by era, by rating, etc), but adult-themed games will be excluded no matter what other filter is selected. For a worked example of how to create this type of filter, see Family Filter.

Currently, there are no built-in metafilters, so any metafilters in effect will always be Javascript add-ons.

Creating a metafilter

To create a metafilter, you call gameList.createMetaFilter(desc). The argument desc is an object the describes the new metafilter via its properties. The properties of this object are:

The return value from gameList.createMetaFilter() is an opaque identifier that you can use to later remove the filter via gameList.removeMetaFilter().

Removing a metafilter

Once created, a metafilter stays in effect until it's explicitly removed. Changes to the current main filter selection don't affect it, and the creation or removal or other metafilters don't affect it.

To remove a metafilter, call gameList.removeMetaFilter(), passing the identifier returned from the call to gameList.createMetaFilter() that originally created the filter.

Multiple metafilters and the priority order

Metafilters always have the last say on the filtered game list, because the metafilters are called after the current regular filter has been called. The metafilters therefore override the regular filter: if the regular filter rules a game in, but a metafilter then rules it out, the game is out.

But what if there are multiple metafilters in effect? This is specifically allowed, so we have to consider how they negotiate for control over the final decision.

The main point of negotiation is the priority setting for each filter. When multiple metafilters are simultaneously active, PinballY calls them in ascending numeric order of their priorities. For example, if metafilter A has priority 1000, and metafilter B has priority 2000, A's select function will be called first for each game (because it has the lower numeric value for the priority), and then B's select function will be called after that.

In most situations, going first is the privileged position. In this case, though, going last is where all the power lies. This is because each metafilter's decision replaces the prior filter's decision. There's no concept of voting or combining the decisions; the last filter called simply has the last say.

Narrowing vs. widening metafilters

Most metafilters are "narrowing" filters, meaning that their function is to further narrow the selection that the regular filter produces by excluding some of the games it selects. For example, a "family filter" that excludes adult-themed games is only interested in removing games that match its adult-content test.

A metafilter can also act as a "widening" filter. A widening filter is one that adds games to the regular filter's selections, including games in the final results that the regular filter would have normally excluded. For example, if you wanted to make sure that a certain core set of games was always available in the wheel UI, no matter what filter was selected, you could do that with a widening filter.

To create a filter that can widen the selection, you must set the includeExcluded property in the filter description to true when creating the filter. This allows its select function to be called with every game in the collection, even games that were excluded by other active filters. In the select function, you can tell whether or not a game was accepted by the other filters via the included argument.

Here's an example that keeps the other current filters' decisions intact, but also adds games marked with the "Core" category tag, even if they were excluded by other filters.

gameList.createMetaFilter({ includeExcluded: true, // consider all games, even if excluded by other filters priority: 100000, // high priority so that get the last say select: function(game, included) { // keep it if it's included by the other filters, OR if // it has the "Core" category tag return included || game.categories.indexOf("Core") >= 0; } });