Jetpack by WordPress.com - Version 5.7

Version Description

  • Release date: January 2, 2018
  • Release post: https://wp.me/p1moTy-6FR

Enhancements

  • Added ability to create revisions of Portfolio Projects.
  • Users hosting their sites with our Pressable partner who have Rewind access can now jump from the new Activity card in the Jetpack dashboard to the Activity Log in WordPress.com and restore or download backups for the site.
  • Comments: Edit links for comments in the frontend can redirect to calypso if the Jetpack option edit_links_calypso_redirect is enabled.
  • Protect: Updated the styling of the Protect page for recovering access to your site when you're locked out of it.
  • Search: Improved the UI for customizing the Search widget.

Improved compatibility

  • Comments: Updated our filtering behavior for Jetpack comments so other plugins appending html to the comments section are able to do it instead of being filtered out by Jetpack.
  • Widgets: We updated Goodreads URLs to support https schema.
  • Masterbar: We now hide the Masterbar settings card in Jetpacks Admin Page for sites that are set to always show the Masterbar.
  • Lazy Images: Added a callback for processing image attributes array when attempting to lazy load images are loaded via wp_get_attachment_image.
  • Search: Added hooks to the search filters widget so that other plugins/themes can hook in and change its output.

Bug fixes

  • REST API: Added a check for avoiding a fatal error when attempting to include Akismet class files in case the Akismet plugin files are present but the permissions on the files there are set to be not readable
  • Markdown: Fixed bug where code inside shortcodes wasn't correctly restored from the hash.
  • Search: Fixed the link that acts as a month and year filter removal toggle.
Download this release

Release Info

Developer oskosk
Plugin Icon 128x128 Jetpack by WordPress.com
Version 5.7
Comparing to
See all releases

Code changes from version 5.7-beta1 to 5.7

_inc/accessible-focus.js ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var keyboardNavigation = false,
2
+ keyboardNavigationKeycodes = [ 9, 32, 37, 38, 39, 40 ]; // keyCodes for tab, space, left, up, right, down respectively
3
+
4
+ document.addEventListener( 'keydown', function( event ) {
5
+ if ( keyboardNavigation ) {
6
+ return;
7
+ }
8
+ if ( keyboardNavigationKeycodes.indexOf( event.keyCode ) !== -1 ) {
9
+ keyboardNavigation = true;
10
+ document.documentElement.classList.add( 'accessible-focus' );
11
+ }
12
+ } );
13
+ document.addEventListener( 'mouseup', function() {
14
+ if ( ! keyboardNavigation ) {
15
+ return;
16
+ }
17
+ keyboardNavigation = false;
18
+ document.documentElement.classList.remove( 'accessible-focus' );
19
+ } );
_inc/facebook-embed.js ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global FB, jpfbembed */
2
+ (function( window ) {
3
+ var facebookEmbed = function() {
4
+ var fbroot, src;
5
+
6
+ if ( 'undefined' !== typeof FB && FB.XFBML ) {
7
+ FB.XFBML.parse();
8
+ } else {
9
+ fbroot = document.createElement( 'div' );
10
+ fbroot.id = 'fb-root';
11
+ document.getElementsByTagName( 'body' )[0].appendChild( fbroot );
12
+
13
+ src = '//connect.facebook.net/' + jpfbembed.locale + '/sdk.js#xfbml=1';
14
+ if ( jpfbembed.appid ) {
15
+ src += '&appId=' + jpfbembed.appid;
16
+ }
17
+ src += '&version=v2.3';
18
+ jQuery.getScript( src );
19
+ }
20
+ };
21
+
22
+ window.fbAsyncInit = function() {
23
+ FB.init( {
24
+ appId : jpfbembed.appid,
25
+ version: 'v2.3'
26
+ } );
27
+
28
+ FB.XFBML.parse();
29
+ };
30
+
31
+ if ( 'undefined' !== typeof infiniteScroll ) {
32
+ jQuery( document.body ).on( 'post-load', facebookEmbed );
33
+ }
34
+
35
+ facebookEmbed();
36
+ })( this );
_inc/gallery-settings.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Jetpack Gallery Settings
3
+ */
4
+ (function($) {
5
+ var media = wp.media;
6
+
7
+ // Wrap the render() function to append controls.
8
+ media.view.Settings.Gallery = media.view.Settings.Gallery.extend({
9
+ render: function() {
10
+ var $el = this.$el;
11
+
12
+ media.view.Settings.prototype.render.apply( this, arguments );
13
+
14
+ // Append the type template and update the settings.
15
+ $el.append( media.template( 'jetpack-gallery-settings' ) );
16
+ media.gallery.defaults.type = 'default'; // lil hack that lets media know there's a type attribute.
17
+ this.update.apply( this, ['type'] );
18
+
19
+ // Hide the Columns setting for all types except Default
20
+ $el.find( 'select[name=type]' ).on( 'change', function () {
21
+ var columnSetting = $el.find( 'select[name=columns]' ).closest( 'label.setting' );
22
+
23
+ if ( 'default' === $( this ).val() || 'thumbnails' === $( this ).val() ) {
24
+ columnSetting.show();
25
+ } else {
26
+ columnSetting.hide();
27
+ }
28
+ } ).change();
29
+
30
+ return this;
31
+ }
32
+ });
33
+ })(jQuery);
_inc/idc-notice.js ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global idcL10n, jQuery, analytics, history, wpCookies */
2
+
3
+ ( function( $ ) {
4
+ var restNonce = idcL10n.nonce,
5
+ currentUrl = idcL10n.currentUrl,
6
+ restRoot = idcL10n.apiRoot,
7
+ notice = $( '.jp-idc-notice' ),
8
+ idcButtons = $( '.jp-idc-notice .dops-button' ),
9
+ tracksUser = idcL10n.tracksUserData,
10
+ tracksEvent = idcL10n.tracksEventData,
11
+ adminBarMenu = $( '#wp-admin-bar-jetpack-idc' ),
12
+ confirmSafeModeButton = $( '#jp-idc-confirm-safe-mode-action' ),
13
+ fixConnectionButton = $( '#jp-idc-fix-connection-action' ),
14
+ migrateButton = $( '#jp-idc-migrate-action'),
15
+ reconnectButton = $( '#jp-idc-reconnect-site-action' ),
16
+ errorNotice = $( '.jp-idc-error__notice'),
17
+ erroredAction = false;
18
+
19
+ // Initialize Tracks and bump stats.
20
+ if ( 'undefined' !== typeof analytics ) {
21
+ analytics.initialize( tracksUser.userid, tracksUser.username );
22
+ }
23
+
24
+ if ( tracksEvent.isAdmin ) {
25
+ trackAndBumpMCStats( 'notice_view' );
26
+ } else {
27
+ trackAndBumpMCStats( 'non_admin_notice_view', { 'page': tracksEvent.currentScreen } );
28
+ }
29
+ clearConfirmationArgsFromUrl();
30
+
31
+ // If the user dismisses the notice, set a cookie for one week so we don't display it for that time.
32
+ notice.on( 'click', '.notice-dismiss', function() {
33
+ var secure = ( 'https:' === window.location.protocol );
34
+ wpCookies.set( 'jetpack_idc_dismiss_notice', '1', 7 * 24 * 60 * 60, false, false, secure );
35
+ trackAndBumpMCStats( 'non_admin_notice_dismiss', { 'page': tracksEvent.currentScreen } );
36
+ } );
37
+
38
+ notice.on( 'click', '#jp-idc-error__action', function() {
39
+ errorNotice.hide();
40
+ switch( erroredAction ) {
41
+ case 'confirm':
42
+ confirmSafeMode();
43
+ break;
44
+ case 'start-fresh':
45
+ startFreshConnection();
46
+ break;
47
+ case 'migrate':
48
+ migrateStatsAndSubscribers();
49
+ break;
50
+ default:
51
+ return;
52
+ }
53
+ } );
54
+
55
+ // Confirm Safe Mode
56
+ confirmSafeModeButton.on( 'click', confirmSafeMode );
57
+
58
+ // Fix connection
59
+ fixConnectionButton.on( 'click', fixJetpackConnection );
60
+
61
+ // Start fresh connection
62
+ reconnectButton.on( 'click', startFreshConnection );
63
+
64
+ // Starts migration process.
65
+ migrateButton.on( 'click', migrateStatsAndSubscribers );
66
+
67
+ function disableDopsButtons() {
68
+ idcButtons.prop( 'disabled', true );
69
+ }
70
+
71
+ function enableDopsButtons() {
72
+ idcButtons.prop( 'disabled', false );
73
+ }
74
+
75
+ function clearConfirmationArgsFromUrl( allowReload ) {
76
+ allowReload = 'undefined' === typeof allowReload ? false : allowReload;
77
+
78
+ // If the jetpack_idc_clear_confirmation query arg is present, let's try to clear it.
79
+ //
80
+ // Otherwise, there's a weird flow where if the user dismisses the notice, then shows the notice, then clicks
81
+ // the confirm safe mode button again, and then reloads the page, then the notice never disappears.
82
+ if ( window.location.search && -1 !== window.location.search.indexOf( 'jetpack_idc_clear_confirmation' ) ) {
83
+ trackAndBumpMCStats( 'clear_confirmation_clicked' );
84
+
85
+ // If push state is available, let's use that to minimize reloading the page.
86
+ // Otherwise, we can clear the args by reloading the page.
87
+ if ( history && history.pushState ) {
88
+ history.pushState( {}, '', currentUrl );
89
+ } else if ( allowReload ) {
90
+ window.location.href = currentUrl;
91
+ }
92
+ }
93
+ }
94
+
95
+ function confirmSafeMode() {
96
+ errorNotice.hide();
97
+ trackAndBumpMCStats( 'confirm_safe_mode' );
98
+
99
+ var route = restRoot + 'jetpack/v4/identity-crisis/confirm-safe-mode';
100
+ disableDopsButtons();
101
+ $.ajax( {
102
+ method: 'POST',
103
+ beforeSend : function ( xhr ) {
104
+ xhr.setRequestHeader( 'X-WP-Nonce', restNonce );
105
+ },
106
+ url: route,
107
+ data: {},
108
+ success: function() {
109
+ notice.hide();
110
+ adminBarMenu.removeClass( 'hide' );
111
+
112
+ // We must refresh the Jetpack admin UI page in order for the React UI to render.
113
+ if ( window.location.search && 1 === window.location.search.indexOf( 'page=jetpack' ) ) {
114
+ window.location.reload();
115
+ }
116
+ },
117
+ error: function( error ) {
118
+ erroredAction = 'confirm';
119
+ displayErrorNotice( error );
120
+ enableDopsButtons();
121
+ }
122
+ } );
123
+ }
124
+
125
+ function migrateStatsAndSubscribers() {
126
+ errorNotice.hide();
127
+ trackAndBumpMCStats( 'migrate' );
128
+
129
+ var route = restRoot + 'jetpack/v4/identity-crisis/migrate';
130
+ disableDopsButtons();
131
+ $.ajax( {
132
+ method: 'POST',
133
+ beforeSend : function ( xhr ) {
134
+ xhr.setRequestHeader( 'X-WP-Nonce', restNonce );
135
+ },
136
+ url: route,
137
+ data: {},
138
+ success: function() {
139
+ notice.hide();
140
+ if ( $( 'body' ).hasClass( 'toplevel_page_jetpack' ) ) {
141
+ // On the main Jetpack page, sites in IDC will not see Jetpack's interface.
142
+ // Once IDC is resolved, we need to refresh the page to regain access to the UI.
143
+ window.location.reload( true );
144
+ }
145
+ },
146
+ error: function( error ) {
147
+ erroredAction = 'migrate';
148
+ displayErrorNotice( error );
149
+ enableDopsButtons();
150
+ }
151
+ } );
152
+ }
153
+
154
+ function fixJetpackConnection() {
155
+ errorNotice.hide();
156
+ trackAndBumpMCStats( 'fix_connection' );
157
+ notice.addClass( 'jp-idc-show-second-step' );
158
+ }
159
+
160
+ /**
161
+ * On successful request of the endpoint, we will redirect to the
162
+ * connection auth flow after appending a specific 'from=' param for tracking.
163
+ */
164
+ function startFreshConnection() {
165
+ errorNotice.hide();
166
+ trackAndBumpMCStats( 'start_fresh' );
167
+
168
+ var route = restRoot + 'jetpack/v4/identity-crisis/start-fresh';
169
+ disableDopsButtons();
170
+ $.ajax( {
171
+ method: 'POST',
172
+ beforeSend : function ( xhr ) {
173
+ xhr.setRequestHeader( 'X-WP-Nonce', restNonce );
174
+ },
175
+ url: route,
176
+ data: {},
177
+ success: function( connectUrl ){
178
+ // Add a from param and take them to connect.
179
+ window.location = connectUrl + '&from=idc-notice';
180
+ },
181
+ error: function( error ) {
182
+ erroredAction = 'start-fresh';
183
+ displayErrorNotice( error );
184
+ enableDopsButtons();
185
+ }
186
+ } );
187
+ }
188
+
189
+ /**
190
+ * Displays an error message from the REST endpoints we're hitting.
191
+ *
192
+ * @param error {Object} Object containing the errored response from the API
193
+ */
194
+ function displayErrorNotice( error ) {
195
+ var errorDescription = $( '.jp-idc-error__desc' );
196
+ if ( error && error.responseJSON && error.responseJSON.message ) {
197
+ errorDescription.html( error.responseJSON.message );
198
+ } else {
199
+ errorDescription.html( '' );
200
+ }
201
+ errorNotice.css( 'display', 'flex' );
202
+ }
203
+
204
+ /**
205
+ * This function will fire both a Tracks and MC stat.
206
+ * It will make sure to format the event name properly for the given stat home.
207
+ *
208
+ * Tracks: Will be prefixed by 'jetpack_idc_' and use underscores.
209
+ * MC: Will not be prefixed, and will use dashes.
210
+ *
211
+ * @param eventName string
212
+ * @param extraProps object
213
+ */
214
+ function trackAndBumpMCStats( eventName, extraProps ) {
215
+ if ( 'undefined' === typeof extraProps || 'object' !== typeof extraProps ) {
216
+ extraProps = {};
217
+ }
218
+
219
+ if ( eventName && eventName.length && 'undefined' !== typeof analytics && analytics.tracks && analytics.mc ) {
220
+ // Format for Tracks
221
+ eventName = eventName.replace( /-/g, '_' );
222
+ eventName = eventName.indexOf( 'jetpack_idc_' ) !== 0 ? 'jetpack_idc_' + eventName : eventName;
223
+ analytics.tracks.recordEvent( eventName, extraProps );
224
+
225
+ // Now format for MC stats
226
+ eventName = eventName.replace( 'jetpack_idc_', '' );
227
+ eventName = eventName.replace( /_/g, '-' );
228
+ analytics.mc.bumpStat( 'jetpack-idc', eventName );
229
+ }
230
+ }
231
+ })( jQuery );
_inc/jetpack-admin.js ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($) {
2
+
3
+ ///////////////////////////////////////
4
+ // INIT
5
+ ///////////////////////////////////////
6
+
7
+ $(document).ready(function () {
8
+ initEvents();
9
+ configFixedElements();
10
+ });
11
+
12
+ ///////////////////////////////////////
13
+ // FUNCTIONS
14
+ ///////////////////////////////////////
15
+
16
+ function configFixedElements() {
17
+ var jpTopFrame = $('.frame.top'),
18
+ jpBottomFrame = $('.frame.bottom'),
19
+ $body = $('body');
20
+
21
+ $body.scroll(function(){
22
+ if ( 33 > jpTopFrame.offset().top ) {
23
+ jpTopFrame.addClass('fixed');
24
+ $body.addClass('jp-frame-top-fixed');
25
+ }
26
+ if ( 120 <= jpBottomFrame.offset().top ) {
27
+ jpTopFrame.removeClass('fixed');
28
+ $body.removeClass('jp-frame-top-fixed');
29
+ }
30
+ });
31
+
32
+ $( 'table.jetpack-modules', jpBottomFrame ).addClass( 'with-transparency' );
33
+ $( '.manage-left', jpBottomFrame ).css( 'width', '' );
34
+ $( '.manage-right', jpBottomFrame ).show();
35
+ }
36
+
37
+ function initEvents() {
38
+ // toggle search and filters at mobile resolution
39
+ $('.filter-search').on('click', function () {
40
+ $(this).toggleClass('active');
41
+ $('.manage-right').toggleClass('show');
42
+ $('.shade').toggle();
43
+ });
44
+
45
+ // Toggle all checkboxes
46
+ $('.checkall').on('click', function () {
47
+ $('.table-bordered').find(':checkbox').prop('checked', this.checked);
48
+ });
49
+
50
+ // Clicking outside modal, or close X closes modal
51
+ $('.shade, .modal .close').on('click', function ( event ) {
52
+ $('.shade, .modal').hide();
53
+ $('.manage-right').removeClass('show');
54
+ event.preventDefault();
55
+ });
56
+ }
57
+
58
+ })(jQuery);
_inc/jetpack-connection-banner.js ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global jQuery, jp_banner */
2
+
3
+ ( function( $ ) {
4
+ var nav = $( '.jp-wpcom-connect__vertical-nav-container' ),
5
+ contentContainer = $( '.jp-wpcom-connect__content-container' ),
6
+ nextFeatureButtons = $( '.jp-banner__button-container .next-feature' ),
7
+ fullScreenContainer = $( '.jp-connect-full__container' ),
8
+ fullScreenDismiss = $( '.jp-connect-full__dismiss' ),
9
+ wpWelcomeNotice = $( '#welcome-panel' ),
10
+ connectionBanner = $( '#message' ),
11
+ connectionBannerDismiss = $( '.connection-banner-dismiss' );
12
+
13
+ // Move the banner below the WP Welcome notice on the dashboard
14
+ $( window ).on( 'load', function() {
15
+ wpWelcomeNotice.insertBefore( connectionBanner );
16
+ } );
17
+
18
+ // Dismiss the connection banner via AJAX
19
+ connectionBannerDismiss.on( 'click', function() {
20
+ $( connectionBanner ).hide();
21
+
22
+ var data = {
23
+ action: 'jetpack_connection_banner',
24
+ nonce: jp_banner.connectionBannerNonce,
25
+ dismissBanner: true
26
+ };
27
+
28
+ $.post( jp_banner.ajax_url, data, function( response ) {
29
+ if ( true !== response.success ) {
30
+ $( connectionBanner ).show();
31
+ }
32
+ } );
33
+ } );
34
+
35
+ nav.on( 'click', '.vertical-menu__feature-item:not( .vertical-menu__feature-item-is-selected )', function() {
36
+ transitionSlideToIndex( $( this ).index() );
37
+ } );
38
+
39
+ nextFeatureButtons.on( 'click', function() {
40
+ var slideIndex = $( this )
41
+ .closest( '.jp-wpcom-connect__slide' )
42
+ .index();
43
+
44
+ transitionSlideToIndex( slideIndex + 1 );
45
+ } );
46
+
47
+ function transitionSlideToIndex( index ) {
48
+ // Remove classes from previously selected menu item and content
49
+ nav
50
+ .find( '.vertical-menu__feature-item-is-selected' )
51
+ .removeClass( 'vertical-menu__feature-item-is-selected' );
52
+
53
+ contentContainer
54
+ .find( '.jp__slide-is-active' )
55
+ .removeClass( 'jp__slide-is-active' );
56
+
57
+ // Add classes to selected menu item and content
58
+ nav
59
+ .children()
60
+ .eq( index )
61
+ .addClass( 'vertical-menu__feature-item-is-selected' );
62
+
63
+ contentContainer
64
+ .children()
65
+ .eq( index )
66
+ .addClass( 'jp__slide-is-active' );
67
+ }
68
+
69
+ /**
70
+ * Full-screen connection prompt
71
+ */
72
+ fullScreenDismiss.on( 'click', function() {
73
+ $( fullScreenContainer ).hide();
74
+
75
+ // Re-enable scrolling
76
+ $( 'body' ).css( 'overflow', 'visible' );
77
+ } );
78
+
79
+ $( document ).keyup( function( e ) {
80
+ if ( 27 === e.keyCode ) {
81
+ $( fullScreenDismiss ).click();
82
+ }
83
+ } );
84
+
85
+ // Prevent scrolling if full-page prompt is showing
86
+ if ( $( fullScreenContainer ).is( ':visible' ) ) {
87
+ $( 'body' ).css( 'overflow', 'hidden' );
88
+ }
89
+ } )( jQuery );
_inc/jetpack-jitm.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( document ).ready( function( $ ) {
2
+ var templates = {
3
+ 'default': function( envelope ) {
4
+ var html = '<div class="jitm-card jitm-banner ' + (
5
+ envelope.CTA.message ? 'has-call-to-action' : ''
6
+ ) + ' is-upgrade-premium ' + envelope.content.classes + '" data-stats_url="' + envelope.jitm_stats_url + '">';
7
+ html += '<div class="jitm-banner__icon-plan">' + envelope.content.icon + '</div>';
8
+ html += '<div class="jitm-banner__content">';
9
+ html += '<div class="jitm-banner__info">';
10
+ html += '<div class="jitm-banner__title">' + envelope.content.message + '</div>';
11
+ if ( envelope.content.description && envelope.content.description !== '' ) {
12
+ html += '<div class="jitm-banner__description">' + envelope.content.description + '</div>';
13
+ }
14
+ html += '</div>';
15
+ if ( envelope.CTA.message ) {
16
+ html += '<div class="jitm-banner__action">';
17
+ html += '<a href="' + envelope.url + '" target="_blank" title="' + envelope.CTA.message + '" data-module="' + envelope.feature_class + '" type="button" class="jitm-button is-compact ' + ( envelope.CTA.primary ? 'is-primary' : '' ) + ' jptracks" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-' + envelope.id + '">' + envelope.CTA.message + '</a>';
18
+ html += '</div>';
19
+ }
20
+ html += '<a href="#" data-module="' + envelope.feature_class + '" class="jitm-banner__dismiss"></a>';
21
+ html += '</div>';
22
+ html += '</div>';
23
+
24
+ return $( html );
25
+ }
26
+ };
27
+
28
+ var setJITMContent = function( $el, response ) {
29
+ var template;
30
+
31
+ var render = function( $my_template ) {
32
+ return function( e ) {
33
+ e.preventDefault();
34
+
35
+ $my_template.hide();
36
+
37
+ $.ajax( {
38
+ url: window.jitm_config.api_root + 'jetpack/v4/jitm',
39
+ method: 'POST', // using DELETE without permalinks is broken in default nginx configuration
40
+ data: {
41
+ id: response.id,
42
+ feature_class: response.feature_class
43
+ }
44
+ } );
45
+ };
46
+ };
47
+
48
+ template = response.template;
49
+
50
+ // if we don't have a template for this version, just use the default template
51
+ if ( ! template || ! templates[ template ] ) {
52
+ template = 'default';
53
+ }
54
+
55
+ var $template = templates[ template ]( response );
56
+ $template.find( '.jitm-banner__dismiss' ).click( render( $template ) );
57
+
58
+ $el.replaceWith( $template );
59
+ };
60
+
61
+ $( '.jetpack-jitm-message' ).each( function() {
62
+ var $el = $( this );
63
+
64
+ var message_path = $el.data( 'message-path' );
65
+ var query = $el.data( 'query' );
66
+
67
+ $.get( window.jitm_config.api_root + 'jetpack/v4/jitm', {
68
+ message_path: message_path,
69
+ query: query,
70
+ _wpnonce: $el.data( 'nonce' )
71
+ } ).then( function( response ) {
72
+ if ( 'object' === typeof response && response['1'] ) {
73
+ response = [ response['1'] ];
74
+ }
75
+
76
+ // properly handle the case of an empty array or no content set
77
+ if ( 0 === response.length || ! response[ 0 ].content ) {
78
+ return;
79
+ }
80
+
81
+ // for now, always take the first response
82
+ setJITMContent( $el, response[ 0 ] );
83
+ } );
84
+ } );
85
+ } );
_inc/jetpack-modules.js ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ ( function( window, $, items, models, views, i18n, modalinfo, nonces ) {
3
+ 'use strict';
4
+
5
+ var modules, list_table, handle_module_tag_click, $the_table, $the_filters, $the_search, $jp_frame, $bulk_button;
6
+
7
+ $the_table = $( '.wp-list-table.jetpack-modules' );
8
+ $the_filters = $( '.navbar-form' );
9
+ $the_search = $( '#srch-term-search-input' );
10
+ $jp_frame = $( '.jp-frame' );
11
+ $bulk_button = $( '#doaction' );
12
+
13
+ modules = new models.Modules( {
14
+ items : items
15
+ } );
16
+
17
+ list_table = new views.List_Table( {
18
+ el : '#the-list',
19
+ model : modules
20
+ } );
21
+
22
+ // Kick off an initial redraw.
23
+ modules.trigger( 'change' );
24
+
25
+ // Handle the filtering of modules.
26
+ handle_module_tag_click = function( event ) {
27
+ // Switch the item in the subsubsub list that's flagged as current.
28
+ $( '.subsubsub' ).find( 'a[data-title="' + $(this).data('title') + '"]' ).addClass( 'current' )
29
+ .closest( 'li' ).siblings().find( 'a.current' ).removeClass( 'current' );
30
+
31
+ event.preventDefault();
32
+ modules.trigger( 'change' );
33
+ };
34
+
35
+ $( '.subsubsub a' ).on( 'click', { modules : modules }, handle_module_tag_click );
36
+
37
+ $the_filters.on( 'click', '.button-group .button', { modules : modules }, function( event ) {
38
+ event.preventDefault();
39
+ $(this).addClass('active').siblings('.active').removeClass('active');
40
+ modules.trigger( 'change' );
41
+ } );
42
+
43
+ $the_search.on( 'keyup search', function( e ) {
44
+ // Don't trigger change on tab, since it's only used for accessibility
45
+ // anyway, and will remove all checked boxes
46
+ if ( e.keyCode !== 9 ) {
47
+ modules.trigger( 'change' );
48
+ }
49
+ } );
50
+
51
+ $the_search.prop( 'placeholder', i18n.search_placeholder );
52
+
53
+ $bulk_button.on( 'click', function( event ) {
54
+ var selectedModules = $('.jetpack-modules-list-table-form').serialize(),
55
+ selectedAction = $(this).siblings('select').val(),
56
+ url;
57
+
58
+ if ( selectedModules.length && '-1' !== selectedAction ) {
59
+ url = 'admin.php?page=jetpack&action=' + encodeURIComponent( selectedAction );
60
+ url += '&' + selectedModules;
61
+ url += '&_wpnonce=' + encodeURIComponent( nonces.bulk );
62
+
63
+ window.location.href = url;
64
+ } else {
65
+ // Possibly add in an alert here explaining why nothing's happening?
66
+ }
67
+
68
+ event.preventDefault();
69
+ } );
70
+
71
+ } ) ( this, jQuery, window.jetpackModulesData.modules, this.jetpackModules.models, this.jetpackModules.views, window.jetpackModulesData.i18n, window.jetpackModulesData.modalinfo, window.jetpackModulesData.nonces );
_inc/jetpack-modules.models.js ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ this.jetpackModules = this.jetpackModules || {};
3
+
4
+ window.jetpackModules.models = (function( window, $, _, Backbone ) {
5
+ 'use strict';
6
+
7
+ var models = {};
8
+
9
+ models.Modules = Backbone.Model.extend({
10
+ visibles : {},
11
+
12
+ /**
13
+ * Updates modules.items dataset to be a reflection of both the current
14
+ * modules.raw data, as well as any filters or sorting that may be in effect.
15
+ */
16
+ filter_and_sort : function() {
17
+ var subsubsub = $('.subsubsub .current'),
18
+ items = this.get( 'raw' ),
19
+ m_filter = $('.button-group.filter-active .active'),
20
+ m_sort = $('.button-group.sort .active'),
21
+ m_search = $('#srch-term-search-input').val().toLowerCase(),
22
+ groups;
23
+
24
+ // If a module filter has been selected, filter it!
25
+ if ( ! subsubsub.closest('li').hasClass( 'all' ) ) {
26
+ items = _.filter( items, function( item ) {
27
+ return _.contains( item.module_tags, subsubsub.data( 'title' ) );
28
+ } );
29
+ }
30
+
31
+ if ( m_filter.data('filter-by') ) {
32
+ items = _.filter( items, function( item ) {
33
+ return item[ m_filter.data('filter-by') ] === m_filter.data('filter-value');
34
+ } );
35
+ }
36
+
37
+ if ( m_search.length ) {
38
+ items = _.filter( items, function( item ) {
39
+ var search_text = item.name + ' ' + item.description + ' ' + item.long_description + ' ' + item.search_terms + ' ' + item.jumpstart_desc + ' ' + item.module_tags;
40
+ return ( -1 !== search_text.toLowerCase().indexOf( m_search ) );
41
+ } );
42
+ }
43
+
44
+ if ( m_sort.data('sort-by') ) {
45
+ items = _.sortBy( items, m_sort.data('sort-by') );
46
+ if ( 'reverse' === m_sort.data('sort-order') ) {
47
+ items.reverse();
48
+ }
49
+ }
50
+
51
+ // Sort unavailable modules to the end if the user is running in local mode.
52
+ groups = _.groupBy( items, 'available' );
53
+ if ( _.has( groups, 'false' ) ) {
54
+ items = [].concat( groups[true], groups[false] );
55
+ }
56
+
57
+ // Now shove it back in.
58
+ this.set( 'items', items );
59
+
60
+ return this;
61
+ },
62
+
63
+ initialize : function() {
64
+ var items = this.get( 'items' );
65
+ this.set( 'raw', items );
66
+ }
67
+
68
+ });
69
+
70
+ return models;
71
+
72
+ })( this, jQuery, _, Backbone );
_inc/jetpack-modules.views.js ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ this.jetpackModules = this.jetpackModules || {};
3
+
4
+ window.jetpackModules.views = (function( window, $, _, Backbone, wp ) {
5
+ 'use strict';
6
+
7
+ var views = {};
8
+
9
+ views.List_Table = Backbone.View.extend({
10
+
11
+ template : wp.template( 'Jetpack_Modules_List_Table_Template' ),
12
+
13
+ /**
14
+ * If we can, use replaceState to change the URL and indicate the new filtering.
15
+ * This will be handy with redirecting back to the same state after activating/deactivating.
16
+ */
17
+ updateUrl : function() {
18
+ if ( ! window.history.replaceState ) {
19
+ return;
20
+ }
21
+
22
+ var url = window.location.href.split('?')[0] + '?page=jetpack_modules',
23
+ m_tag = $('.subsubsub .current'),
24
+ m_filter = $('.button-group.filter-active .active'),
25
+ m_sort = $('.button-group.sort .active'),
26
+ m_search = $('#srch-term-search-input').val();
27
+
28
+ if ( m_search.length ) {
29
+ url += '&s=' + encodeURIComponent( m_search );
30
+ }
31
+
32
+ if ( ! m_tag.hasClass('all') ) {
33
+ url += '&module_tag=' + encodeURIComponent( m_tag.data('title') );
34
+ }
35
+
36
+ if ( m_filter.data('filter-by') ) {
37
+ url += '&' + encodeURIComponent( m_filter.data('filter-by') ) + '=' + encodeURIComponent( m_filter.data('filter-value') );
38
+ }
39
+
40
+ if ( 'name' !== m_sort.data('sort-by') ) {
41
+ url += '&sort_by=' + encodeURIComponent( m_sort.data('sort-by') );
42
+ }
43
+
44
+ window.history.replaceState( {}, '', url );
45
+ },
46
+
47
+ render : function() {
48
+ this.model.filter_and_sort();
49
+ this.$el.html( this.template( this.model.attributes ) );
50
+ this.updateUrl();
51
+ return this;
52
+ },
53
+
54
+ initialize : function() {
55
+ this.listenTo( this.model, 'change', this.render );
56
+ }
57
+
58
+ });
59
+
60
+ return views;
61
+
62
+ })( this, jQuery, _, Backbone, wp );
_inc/jquery.jetpack-resize.js ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global Jetpack, JSON */
2
+ /**
3
+ * Resizeable Iframes.
4
+ *
5
+ * Start listening to resize postMessage events for selected iframes:
6
+ * $( selector ).Jetpack( 'resizeable' );
7
+ * - OR -
8
+ * Jetpack.resizeable( 'on', context );
9
+ *
10
+ * Resize selected iframes:
11
+ * $( selector ).Jetpack( 'resizeable', 'resize', { width: 100, height: 200 } );
12
+ * - OR -
13
+ * Jetpack.resizeable( 'resize', { width: 100, height: 200 }, context );
14
+ *
15
+ * Stop listening to resize postMessage events for selected iframes:
16
+ * $( selector ).Jetpack( 'resizeable', 'off' );
17
+ * - OR -
18
+ * Jetpack.resizeable( 'off', context );
19
+ *
20
+ * Stop listening to all resize postMessage events:
21
+ * Jetpack.resizeable( 'off' );
22
+ */
23
+ (function($) {
24
+ var listening = false, // Are we listening for resize postMessage events
25
+ sourceOrigins = [], // What origins are allowed to send resize postMessage events
26
+ $sources = false, // What iframe elements are we tracking resize postMessage events from
27
+
28
+ URLtoOrigin, // Utility to convert URLs into origins
29
+ setupListener, // Binds global resize postMessage event handler
30
+ destroyListener, // Unbinds global resize postMessage event handler
31
+
32
+ methods; // Jetpack.resizeable methods
33
+
34
+ // Setup the Jetpack global
35
+ if ( 'undefined' === typeof window.Jetpack ) {
36
+ window.Jetpack = {
37
+ /**
38
+ * Handles the two different calling methods:
39
+ * $( selector ).Jetpack( 'namespace', 'method', context ) // here, context is optional and is used to filter the collection
40
+ * - vs. -
41
+ * Jetpack.namespace( 'method', context ) // here context defines the collection
42
+ *
43
+ * @internal
44
+ *
45
+ * Call as: Jetpack.getTarget.call( this, context )
46
+ *
47
+ * @param string context: jQuery selector
48
+ * @return jQuery|undefined object on which to perform operations or undefined when context cannot be determined
49
+ */
50
+ getTarget: function( context ) {
51
+ if ( this instanceof jQuery ) {
52
+ return context ? this.filter( context ) : this;
53
+ }
54
+
55
+ return context ? $( context ) : context;
56
+ }
57
+ };
58
+ }
59
+
60
+ // Setup the Jetpack jQuery method
61
+ if ( 'undefined' === typeof $.fn.Jetpack ) {
62
+ /**
63
+ * Dispatches calls to the correct namespace
64
+ *
65
+ * @param string namespace
66
+ * @param ...
67
+ * @return mixed|jQuery (chainable)
68
+ */
69
+ $.fn.Jetpack = function( namespace ) {
70
+ if ( 'function' === typeof Jetpack[namespace] ) {
71
+ // Send the call to the correct Jetpack.namespace
72
+ return Jetpack[namespace].apply( this, Array.prototype.slice.call( arguments, 1 ) );
73
+ } else {
74
+ $.error( 'Namespace "' + namespace + '" does not exist on jQuery.Jetpack' );
75
+ }
76
+ };
77
+ }
78
+
79
+ // Define Jetpack.resizeable() namespace to just always bail if no postMessage
80
+ if ( 'function' !== typeof window.postMessage ) {
81
+ $.extend( window.Jetpack, {
82
+ /**
83
+ * Defines the Jetpack.resizeable() namespace.
84
+ * See below for non-trivial definition for browsers with postMessage.
85
+ */
86
+ resizeable: function() {
87
+ $.error( 'Browser does not support window.postMessage' );
88
+ }
89
+ } );
90
+
91
+ return;
92
+ }
93
+
94
+ /**
95
+ * Utility to convert URLs into origins
96
+ *
97
+ * http://example.com:port/path?query#fragment -> http://example.com:port
98
+ *
99
+ * @param string URL
100
+ * @return string origin
101
+ */
102
+ URLtoOrigin = function( URL ) {
103
+ if ( ! URL.match( /^https?:\/\// ) ) {
104
+ URL = document.location.href;
105
+ }
106
+ return URL.split( '/' ).slice( 0, 3 ).join( '/' );
107
+ };
108
+
109
+ /**
110
+ * Binds global resize postMessage event handler
111
+ */
112
+ setupListener = function() {
113
+ listening = true;
114
+
115
+ $( window ).on( 'message.JetpackResizeableIframe', function( e ) {
116
+ var event = e.originalEvent,
117
+ data;
118
+
119
+ // Ensure origin is allowed
120
+ if ( -1 === $.inArray( event.origin, sourceOrigins ) ) {
121
+ return;
122
+ }
123
+
124
+ // Some browsers send structured data, some send JSON strings
125
+ if ( 'object' === typeof event.data ) {
126
+ data = event.data.data;
127
+ } else {
128
+ try {
129
+ data = JSON.parse( event.data );
130
+ } catch ( err ) {
131
+ data = false;
132
+ }
133
+ }
134
+
135
+ if ( !data.data ) {
136
+ return;
137
+ }
138
+
139
+ // Un-nest
140
+ data = data.data;
141
+
142
+ // Is it a resize event?
143
+ if ( 'undefined' === typeof data.action || 'resize' !== data.action ) {
144
+ return;
145
+ }
146
+
147
+ // Find the correct iframe and resize it
148
+ $sources.filter( function() {
149
+ if ( 'undefined' !== typeof data.name ) {
150
+ return this.name === data.name;
151
+ } else {
152
+ return event.source === this.contentWindow;
153
+ }
154
+ } ).first().Jetpack( 'resizeable', 'resize', data );
155
+ } );
156
+ };
157
+
158
+ /**
159
+ * Unbinds global resize postMessage event handler
160
+ */
161
+ destroyListener = function() {
162
+ listening = false;
163
+ $( window ).off( 'message.JetpackResizeableIframe' );
164
+
165
+ sourceOrigins = [];
166
+ $( '.jetpack-resizeable' ).removeClass( 'jetpack-resizeable' );
167
+ $sources = false;
168
+ };
169
+
170
+ // Methods for Jetpack.resizeable() namespace
171
+ methods = {
172
+ /**
173
+ * Start listening for resize postMessage events on the given iframes
174
+ *
175
+ * Call statically as: Jetpack.resizeable( 'on', context )
176
+ * Call as: $( selector ).Jetpack( 'resizeable', 'on', context ) // context optional: used to filter the collectino
177
+ *
178
+ * @param string context jQuery selector.
179
+ * @return jQuery (chainable)
180
+ */
181
+ on: function( context ) {
182
+ var target = Jetpack.getTarget.call( this, context );
183
+
184
+ if ( ! listening ) {
185
+ setupListener();
186
+ }
187
+
188
+ target.each( function() {
189
+ sourceOrigins.push( URLtoOrigin( $( this ).attr( 'src' ) ) );
190
+ } ).addClass( 'jetpack-resizeable' );
191
+
192
+ $sources = $( '.jetpack-resizeable' );
193
+
194
+ return target;
195
+ },
196
+
197
+ /**
198
+ * Stop listening for resize postMessage events on the given iframes
199
+ *
200
+ * Call statically as: Jetpack.resizeable( 'off', context )
201
+ * Call as: $( selector ).Jetpack( 'resizeable', 'off', context ) // context optional: used to filter the collectino
202
+ *
203
+ * @param string context jQuery selector
204
+ * @return jQuery (chainable)
205
+ */
206
+ off: function( context ) {
207
+ var target = Jetpack.getTarget.call( this, context );
208
+
209
+ if ( 'undefined' === typeof target ) {
210
+ destroyListener();
211
+
212
+ return target;
213
+ }
214
+
215
+ target.each( function() {
216
+ var origin = URLtoOrigin( $( this ).attr( 'src' ) ),
217
+ pos = $.inArray( origin, sourceOrigins );
218
+
219
+ if ( -1 !== pos ) {
220
+ sourceOrigins.splice( pos, 1 );
221
+ }
222
+ } ).removeClass( 'jetpack-resizeable' );
223
+
224
+ $sources = $( '.jetpack-resizeable' );
225
+
226
+ return target;
227
+ },
228
+
229
+ /**
230
+ * Resize the given iframes
231
+ *
232
+ * Call statically as: Jetpack.resizeable( 'resize', dimensions, context )
233
+ * Call as: $( selector ).Jetpack( 'resizeable', 'resize', dimensions, context ) // context optional: used to filter the collectino
234
+ *
235
+ * @param object dimensions in pixels: { width: (int), height: (int) }
236
+ * @param string context jQuery selector
237
+ * @return jQuery (chainable)
238
+ */
239
+ resize: function( dimensions, context ) {
240
+ var target = Jetpack.getTarget.call( this, context );
241
+
242
+ $.each( [ 'width', 'height' ], function( i, variable ) {
243
+ var value = 0,
244
+ container;
245
+ if ( 'undefined' !== typeof dimensions[variable] ) {
246
+ value = parseInt( dimensions[variable], 10 );
247
+ }
248
+
249
+ if ( 0 !== value ) {
250
+ target[variable]( value );
251
+ container = target.parent();
252
+ if ( container.hasClass( 'slim-likes-widget' ) ) {
253
+ container[variable]( value );
254
+ }
255
+ }
256
+ } );
257
+
258
+ return target;
259
+ }
260
+ };
261
+
262
+ // Define Jetpack.resizeable() namespace
263
+ $.extend( window.Jetpack, {
264
+ /**
265
+ * Defines the Jetpack.resizeable() namespace.
266
+ * See above for trivial definition for browsers with no postMessage.
267
+ *
268
+ * @param string method
269
+ * @param ...
270
+ * @return mixed|jQuery (chainable)
271
+ */
272
+ resizeable: function( method ) {
273
+ if ( methods[method] ) {
274
+ // Send the call to the correct Jetpack.resizeable() method
275
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
276
+ } else if ( ! method ) {
277
+ // By default, send to Jetpack.resizeable( 'on' ), which isn't useful in that form but is when called as
278
+ // jQuery( selector ).Jetpack( 'resizeable' )
279
+ return methods.on.apply( this );
280
+ } else {
281
+ $.error( 'Method ' + method + ' does not exist on Jetpack.resizeable' );
282
+ }
283
+ }
284
+ } );
285
+ })(jQuery);
_inc/jquery.spin.js ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Copyright (c) 2011-2013 Felix Gnass
3
+ * Licensed under the MIT license
4
+ */
5
+
6
+ /*
7
+
8
+ Basic Usage:
9
+ ============
10
+
11
+ $('#el').spin(); // Creates a default Spinner using the text color of #el.
12
+ $('#el').spin({ ... }); // Creates a Spinner using the provided options.
13
+
14
+ $('#el').spin(false); // Stops and removes the spinner.
15
+
16
+ Using Presets:
17
+ ==============
18
+
19
+ $('#el').spin('small'); // Creates a 'small' Spinner using the text color of #el.
20
+ $('#el').spin('large', '#fff'); // Creates a 'large' white Spinner.
21
+
22
+ Adding a custom preset:
23
+ =======================
24
+
25
+ $.fn.spin.presets.flower = {
26
+ lines: 9
27
+ length: 10
28
+ width: 20
29
+ radius: 0
30
+ }
31
+
32
+ $('#el').spin('flower', 'red');
33
+
34
+ */
35
+
36
+ (function(factory) {
37
+
38
+ if (typeof exports == 'object') {
39
+ // CommonJS
40
+ factory(require('jquery'), require('spin'))
41
+ }
42
+ else if (typeof define == 'function' && define.amd) {
43
+ // AMD, register as anonymous module
44
+ define(['jquery', 'spin'], factory)
45
+ }
46
+ else {
47
+ // Browser globals
48
+ if (!window.Spinner) throw new Error('Spin.js not present')
49
+ factory(window.jQuery, window.Spinner)
50
+ }
51
+
52
+ }(function($, Spinner) {
53
+
54
+ $.fn.spin = function(opts, color) {
55
+
56
+ return this.each(function() {
57
+ var $this = $(this),
58
+ data = $this.data();
59
+
60
+ if (data.spinner) {
61
+ data.spinner.stop();
62
+ delete data.spinner;
63
+ }
64
+ if (opts !== false) {
65
+ opts = $.extend(
66
+ { color: color || $this.css('color') },
67
+ $.fn.spin.presets[opts] || opts
68
+ )
69
+ // Begin WordPress Additions
70
+ // To use opts.right, you need to have specified a length, width, and radius.
71
+ if ( typeof opts.right !== 'undefined' && typeof opts.length !== 'undefined'
72
+ && typeof opts.width !== 'undefined' && typeof opts.radius !== 'undefined' ) {
73
+ var pad = $this.css( 'padding-left' );
74
+ pad = ( typeof pad === 'undefined' ) ? 0 : parseInt( pad, 10 );
75
+ opts.left = $this.outerWidth() - ( 2 * ( opts.length + opts.width + opts.radius ) ) - pad - opts.right;
76
+ delete opts.right;
77
+ }
78
+ // End WordPress Additions
79
+ data.spinner = new Spinner(opts).spin(this)
80
+ }
81
+ })
82
+ }
83
+
84
+ $.fn.spin.presets = {
85
+ tiny: { lines: 8, length: 2, width: 2, radius: 3 },
86
+ small: { lines: 8, length: 4, width: 3, radius: 5 },
87
+ large: { lines: 10, length: 8, width: 4, radius: 8 }
88
+ }
89
+
90
+ }));
91
+
92
+ // Jetpack Presets Overrides:
93
+ (function($){
94
+ $.fn.spin.presets.wp = { trail: 60, speed: 1.3 };
95
+ $.fn.spin.presets.small = $.extend( { lines: 8, length: 2, width: 2, radius: 3 }, $.fn.spin.presets.wp );
96
+ $.fn.spin.presets.medium = $.extend( { lines: 8, length: 4, width: 3, radius: 5 }, $.fn.spin.presets.wp );
97
+ $.fn.spin.presets.large = $.extend( { lines: 10, length: 6, width: 4, radius: 7 }, $.fn.spin.presets.wp );
98
+ $.fn.spin.presets['small-left'] = $.extend( { left: 5 }, $.fn.spin.presets.small );
99
+ $.fn.spin.presets['small-right'] = $.extend( { right: 5 }, $.fn.spin.presets.small );
100
+ $.fn.spin.presets['medium-left'] = $.extend( { left: 5 }, $.fn.spin.presets.medium );
101
+ $.fn.spin.presets['medium-right'] = $.extend( { right: 5 }, $.fn.spin.presets.medium );
102
+ $.fn.spin.presets['large-left'] = $.extend( { left: 5 }, $.fn.spin.presets.large );
103
+ $.fn.spin.presets['large-right'] = $.extend( { right: 5 }, $.fn.spin.presets.large );
104
+ })(jQuery);
_inc/postmessage.js ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 <