PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | _inc/jetpack-modules.models.js +164 -0 16.2-beta → 16.3 View file →
@@ -1,0 +1,164 @@
1 +window.jetpackModules = window.jetpackModules || {};
2 +
3 +window.jetpackModules.models = ( function ( window, $, Backbone ) {
4 + 'use strict';
5 +
6 + var models = {};
7 +
8 + models.Modules = Backbone.Model.extend( {
9 + visibles: {},
10 +
11 + /**
12 + * Applies the active availability, tag, state/purpose and search filters
13 + * to the raw module set and returns the matching items (unsorted).
14 + *
15 + * @param {Object} [options] Filtering options.
16 + * @param {boolean} [options.ignoreTag] When true, skip the "Show" tag
17 + * facet so counts can be computed independently of the current tag
18 + * selection (faceted counting).
19 + * @param {boolean} [options.ignorePurpose] When true, skip the "Purpose"
20 + * facet so its own faceted counts can be computed.
21 + * @return {Array} Filtered module items.
22 + */
23 + apply_filters: function ( options ) {
24 + options = options || {};
25 +
26 + var subsubsub = $( '.subsubsub .current a' ),
27 + purpose = $( '.purpose-filter .current a' ),
28 + items = Object.values( this.get( 'raw' ) ),
29 + m_availability = $( '.button-group.availability-filter .active' ),
30 + m_search = $( '#srch-term-search-input' ).val().toLowerCase();
31 +
32 + // Offline-mode top-level filter: when "Hide unavailable" is selected,
33 + // drop every module that isn't available offline, regardless of the
34 + // other filters below it.
35 + if ( 'hide-unavailable' === m_availability.data( 'availability' ) ) {
36 + items = items.filter( item => item.available );
37 + }
38 +
39 + // Tag facet ("Show"). Skipped when computing that facet's own counts.
40 + if ( ! options.ignoreTag && ! subsubsub.closest( 'li' ).hasClass( 'all' ) ) {
41 + items = items.filter( item => item.module_tags.includes( subsubsub.data( 'title' ) ) );
42 + }
43 +
44 + // Purpose facet. Skipped when computing that facet's own counts.
45 + if (
46 + ! options.ignorePurpose &&
47 + purpose.length &&
48 + ! purpose.closest( 'li' ).hasClass( 'all' )
49 + ) {
50 + items = items.filter( item => item.product_group === purpose.data( 'group' ) );
51 + }
52 +
53 + // State facet (segmented buttons). "All" carries no data-filter-by.
54 + $( '.button-group.module-filter .active' ).each( function () {
55 + var by = $( this ).data( 'filter-by' ),
56 + value = $( this ).data( 'filter-value' );
57 +
58 + if ( by ) {
59 + items = items.filter( item => item[ by ] === value );
60 + }
61 + } );
62 +
63 + if ( m_search.length ) {
64 + items = items.filter( function ( item ) {
65 + var search_text =
66 + item.name +
67 + ' ' +
68 + item.description +
69 + ' ' +
70 + item.long_description +
71 + ' ' +
72 + item.search_terms +
73 + ' ' +
74 + item.module_tags;
75 + return -1 !== search_text.toLowerCase().indexOf( m_search );
76 + } );
77 + }
78 +
79 + return items;
80 + },
81 +
82 + /**
83 + * Computes, for the "Show" tag list, how many modules match every active
84 + * filter except the tag facet itself. This powers faceted counts that
85 + * stay meaningful as the user narrows the other filters.
86 + *
87 + * @return {Object} Map of translated tag title to count, plus an
88 + * `__all__` key holding the total across all tags.
89 + */
90 + tag_counts: function () {
91 + var base = this.apply_filters( { ignoreTag: true } ),
92 + counts = { __all__: base.length };
93 +
94 + base.forEach( function ( item ) {
95 + ( item.module_tags || [] ).forEach( function ( tag ) {
96 + counts[ tag ] = ( counts[ tag ] || 0 ) + 1;
97 + } );
98 + } );
99 +
100 + return counts;
101 + },
102 +
103 + /**
104 + * Computes, for the "Purpose" list, how many modules fall in each product
105 + * group under every active filter except the Purpose facet itself. Mirrors
106 + * tag_counts() so the two facet lists behave identically.
107 + *
108 + * @return {Object} Map of product-group slug to count, plus an `__all__`
109 + * key holding the total across all groups.
110 + */
111 + purpose_counts: function () {
112 + var base = this.apply_filters( { ignorePurpose: true } ),
113 + counts = { __all__: base.length };
114 +
115 + base.forEach( function ( item ) {
116 + if ( item.product_group ) {
117 + counts[ item.product_group ] = ( counts[ item.product_group ] || 0 ) + 1;
118 + }
119 + } );
120 +
121 + return counts;
122 + },
123 +
124 + /**
125 + * Updates modules.items dataset to be a reflection of both the current
126 + * modules.raw data, as well as any filters or sorting that may be in effect.
127 + */
128 + filter_and_sort: function () {
129 + var items = this.apply_filters();
130 +
131 + // Default alphabetical order by name. The product-group sort below is
132 + // stable, so this ordering is preserved within each group.
133 + items.sort( ( a, b ) => a.name.localeCompare( b.name ) );
134 +
135 + // Group by product group (primary), then push unavailable modules to
136 + // the end of their group. Any user-selected sort above is preserved
137 + // within a group because Array.prototype.sort is stable in the
138 + // browsers we support.
139 + var groupOrder = { growth: 0, performance: 1, security: 2, other: 3 };
140 + items.sort( function ( a, b ) {
141 + var ga = groupOrder[ a.product_group ] !== undefined ? groupOrder[ a.product_group ] : 99;
142 + var gb = groupOrder[ b.product_group ] !== undefined ? groupOrder[ b.product_group ] : 99;
143 +
144 + if ( ga !== gb ) {
145 + return ga - gb;
146 + }
147 +
148 + return ( b.available ? 1 : 0 ) - ( a.available ? 1 : 0 );
149 + } );
150 +
151 + // Now shove it back in.
152 + this.set( 'items', items );
153 +
154 + return this;
155 + },
156 +
157 + initialize: function () {
158 + var items = this.get( 'items' );
159 + this.set( 'raw', items );
160 + },
161 + } );
162 +
163 + return models;
164 +} )( window, jQuery, Backbone );