@automattic/newspack-blocks 4.31.1 → 4.31.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## @automattic/newspack-blocks [4.31.2](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.31.1...newspack-blocks@4.31.2) (2026-09-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **iframe:** keep Back working on iframe block pages (NPPM-3180) ([#1042](https://github.com/Automattic/newspack-workspace/issues/1042)) ([6a87cb2](https://github.com/Automattic/newspack-workspace/commit/6a87cb2c6dcab735a81b54e87fb11b93769baac1))
|
|
7
|
+
|
|
1
8
|
## @automattic/newspack-blocks [4.31.1](https://github.com/Automattic/newspack-workspace/compare/newspack-blocks@4.31.0...newspack-blocks@4.31.1) (2026-09-09)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<?php return array('dependencies' => array('wp-dom-ready'), 'version' => '
|
|
1
|
+
<?php return array('dependencies' => array('wp-dom-ready'), 'version' => '0adcb9c939693718d723');
|
package/dist/iframe/view.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var
|
|
1
|
+
(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.domReady;e.n(t)()(()=>{Array.from(document.querySelectorAll(".wp-block-newspack-blocks-iframe iframe")).forEach(e=>{let t=0;const n=setInterval(()=>{!(e=>{const t=e.contentDocument;return null!==t&&"about:blank"===t.URL})(e)||t>=10?clearInterval(n):(t++,e.contentWindow.location.replace(e.src))},2e3);window.addEventListener("message",function(t){if(t.origin!==new URL(e.src).origin||e.contentWindow!==t.source)return;let n=0;t.data&&t.data.height&&("number"==typeof t.data.height?n=t.data.height:"string"==typeof t.data.height&&(n=Number(t.data.height))),!isNaN(n)&&n>0&&(e.parentElement&&"auto"!==e.parentElement.style.height&&(e.parentElement.style.height="auto"),e.style.height=n+"px")})})})})();
|
package/newspack-blocks.php
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Author URI: https://newspack.com/
|
|
8
8
|
* Text Domain: newspack-blocks
|
|
9
9
|
* Domain Path: /languages
|
|
10
|
-
* Version: 4.31.
|
|
10
|
+
* Version: 4.31.2
|
|
11
11
|
*
|
|
12
12
|
* @package Newspack_Blocks
|
|
13
13
|
*/
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
define( 'NEWSPACK_BLOCKS__PLUGIN_FILE', __FILE__ );
|
|
16
16
|
define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', 'dist/' );
|
|
17
17
|
define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) );
|
|
18
|
-
define( 'NEWSPACK_BLOCKS__VERSION', '4.31.
|
|
18
|
+
define( 'NEWSPACK_BLOCKS__VERSION', '4.31.2' );
|
|
19
19
|
|
|
20
20
|
require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks.php';
|
|
21
21
|
require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks-api.php';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/newspack-blocks",
|
|
3
|
-
"version": "4.31.
|
|
3
|
+
"version": "4.31.2",
|
|
4
4
|
"author": "Automattic",
|
|
5
5
|
"description": "=== Newspack Blocks === Contributors: (this should be a list of wordpress.org userid's) Donate link: https://example.com/ Tags: comments, spam Requires at least: 4.5 Tested up to: 5.1.1 Stable tag: 0.1.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html",
|
|
6
6
|
"repository": {
|
|
@@ -9,17 +9,47 @@ import domReady from '@wordpress/dom-ready';
|
|
|
9
9
|
|
|
10
10
|
import './view.scss';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Whether the frame still shows its initial about:blank, so it has loaded nothing.
|
|
14
|
+
* Google Docs Viewer intermittently answers HTTP 204, which leaves the frame blank
|
|
15
|
+
* with no load event. That is the case the retry exists for.
|
|
16
|
+
*
|
|
17
|
+
* contentDocument is null for a loaded cross-origin document, a detached frame, and
|
|
18
|
+
* a sandboxed frame without allow-same-origin (from the first tick, so such a frame
|
|
19
|
+
* would never retry; this block renders no sandbox attribute).
|
|
20
|
+
*
|
|
21
|
+
* @param {HTMLIFrameElement} iframe The iframe.
|
|
22
|
+
* @return {boolean} Whether the frame is still on its initial about:blank.
|
|
23
|
+
*/
|
|
24
|
+
const isStillBlank = iframe => {
|
|
25
|
+
const doc = iframe.contentDocument;
|
|
26
|
+
return doc !== null && doc.URL === 'about:blank';
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Re-navigations before giving up on a frame that never loads. A 204 resolves in a
|
|
31
|
+
* retry or two; without a bound, a permanently blank embed keeps requesting for as
|
|
32
|
+
* long as the page is open.
|
|
33
|
+
*/
|
|
34
|
+
const MAX_RETRIES = 10;
|
|
35
|
+
|
|
12
36
|
domReady( () => {
|
|
13
37
|
const iframes = Array.from( document.querySelectorAll( '.wp-block-newspack-blocks-iframe iframe' ) );
|
|
14
38
|
iframes.forEach( iframe => {
|
|
15
|
-
|
|
16
|
-
|
|
39
|
+
// Don't wait for the load event: it may have fired before this script ran
|
|
40
|
+
// (delayed JS). Navigate with location.replace(), since resetting src on a
|
|
41
|
+
// loaded frame adds a history entry and makes readers press Back twice
|
|
42
|
+
// (NPPM-3180).
|
|
43
|
+
let attempts = 0;
|
|
44
|
+
const retry = setInterval( () => {
|
|
45
|
+
if ( ! isStillBlank( iframe ) || attempts >= MAX_RETRIES ) {
|
|
46
|
+
clearInterval( retry );
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
attempts++;
|
|
50
|
+
iframe.contentWindow.location.replace( iframe.src );
|
|
17
51
|
}, 2000 );
|
|
18
52
|
|
|
19
|
-
iframe.onload = function () {
|
|
20
|
-
clearInterval( timerId );
|
|
21
|
-
};
|
|
22
|
-
|
|
23
53
|
// Add a listener for dynamic resizing if the iframe supports it.
|
|
24
54
|
window.addEventListener( 'message', function ( event ) {
|
|
25
55
|
// Reject messages from untrusted origins.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The iframe block's retry (NPPM-3180) must leave a frame that already holds a
|
|
3
|
+
* document alone, and must never reset `src`, which adds a history entry.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const SRC = 'https://embed.example.test/widget';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Render one iframe block and stub the frame state jsdom cannot provide.
|
|
10
|
+
*
|
|
11
|
+
* @param {Object|null} contentDocument What the attached frame reports: the initial
|
|
12
|
+
* about:blank document while a navigation is in
|
|
13
|
+
* flight or was abandoned (cross-origin included),
|
|
14
|
+
* null once a cross-origin document has loaded.
|
|
15
|
+
* A detached frame reports null, as does its
|
|
16
|
+
* contentWindow.
|
|
17
|
+
* @return {Object} The iframe, its state holder, and the `replace` and `setSrc` spies.
|
|
18
|
+
*/
|
|
19
|
+
function renderIframe( contentDocument ) {
|
|
20
|
+
document.body.innerHTML = `<figure class="wp-block-newspack-blocks-iframe"><div class="wp-block-embed__wrapper"><iframe src="${ SRC }"></iframe></div></figure>`;
|
|
21
|
+
const iframe = document.querySelector( 'iframe' );
|
|
22
|
+
const state = { contentDocument };
|
|
23
|
+
const replace = jest.fn();
|
|
24
|
+
const setSrc = jest.fn();
|
|
25
|
+
const contentWindow = { location: { replace } };
|
|
26
|
+
Object.defineProperty( iframe, 'contentDocument', { configurable: true, get: () => ( iframe.isConnected ? state.contentDocument : null ) } );
|
|
27
|
+
Object.defineProperty( iframe, 'contentWindow', { configurable: true, get: () => ( iframe.isConnected ? contentWindow : null ) } );
|
|
28
|
+
Object.defineProperty( iframe, 'src', { configurable: true, get: () => SRC, set: setSrc } );
|
|
29
|
+
jest.isolateModules( () => require( './view' ) );
|
|
30
|
+
return { iframe, state, replace, setSrc };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe( 'iframe block view script', () => {
|
|
34
|
+
beforeEach( () => {
|
|
35
|
+
jest.useFakeTimers();
|
|
36
|
+
} );
|
|
37
|
+
|
|
38
|
+
afterEach( () => {
|
|
39
|
+
jest.clearAllTimers();
|
|
40
|
+
jest.useRealTimers();
|
|
41
|
+
document.body.innerHTML = '';
|
|
42
|
+
} );
|
|
43
|
+
|
|
44
|
+
it.each( [
|
|
45
|
+
// The delayed-script case: the frame loaded before this script ran.
|
|
46
|
+
[ 'cross-origin', null ],
|
|
47
|
+
[ 'same-origin', { URL: 'https://example.test/embed' } ],
|
|
48
|
+
] )( 'leaves a frame that already holds a %s document alone', ( _, contentDocument ) => {
|
|
49
|
+
const { replace, setSrc } = renderIframe( contentDocument );
|
|
50
|
+
jest.advanceTimersByTime( 10000 );
|
|
51
|
+
expect( replace ).not.toHaveBeenCalled();
|
|
52
|
+
expect( setSrc ).not.toHaveBeenCalled();
|
|
53
|
+
expect( jest.getTimerCount() ).toBe( 0 );
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
it( 'retries with location.replace while the frame is still blank, then stops', () => {
|
|
57
|
+
const { state, replace, setSrc } = renderIframe( { URL: 'about:blank' } );
|
|
58
|
+
|
|
59
|
+
jest.advanceTimersByTime( 2000 );
|
|
60
|
+
expect( replace ).toHaveBeenCalledTimes( 1 );
|
|
61
|
+
expect( replace ).toHaveBeenCalledWith( SRC );
|
|
62
|
+
|
|
63
|
+
jest.advanceTimersByTime( 2000 );
|
|
64
|
+
expect( replace ).toHaveBeenCalledTimes( 2 );
|
|
65
|
+
|
|
66
|
+
// The retry succeeded and a cross-origin document loaded.
|
|
67
|
+
state.contentDocument = null;
|
|
68
|
+
jest.advanceTimersByTime( 10000 );
|
|
69
|
+
expect( replace ).toHaveBeenCalledTimes( 2 );
|
|
70
|
+
expect( jest.getTimerCount() ).toBe( 0 );
|
|
71
|
+
|
|
72
|
+
// Resetting src is what adds the history entry.
|
|
73
|
+
expect( setSrc ).not.toHaveBeenCalled();
|
|
74
|
+
} );
|
|
75
|
+
|
|
76
|
+
it( 'gives up after 10 attempts on a frame that never loads', () => {
|
|
77
|
+
const { replace } = renderIframe( { URL: 'about:blank' } );
|
|
78
|
+
jest.advanceTimersByTime( 20000 );
|
|
79
|
+
expect( replace ).toHaveBeenCalledTimes( 10 );
|
|
80
|
+
|
|
81
|
+
jest.advanceTimersByTime( 20000 );
|
|
82
|
+
expect( replace ).toHaveBeenCalledTimes( 10 );
|
|
83
|
+
expect( jest.getTimerCount() ).toBe( 0 );
|
|
84
|
+
} );
|
|
85
|
+
|
|
86
|
+
it( 'checks the frame before touching contentWindow, so a removed frame does not throw', () => {
|
|
87
|
+
const { iframe, replace } = renderIframe( { URL: 'about:blank' } );
|
|
88
|
+
jest.advanceTimersByTime( 2000 );
|
|
89
|
+
expect( replace ).toHaveBeenCalledTimes( 1 );
|
|
90
|
+
|
|
91
|
+
// A detached frame has no contentWindow; dereferencing it would throw inside the tick.
|
|
92
|
+
iframe.remove();
|
|
93
|
+
expect( () => jest.advanceTimersByTime( 10000 ) ).not.toThrow();
|
|
94
|
+
expect( replace ).toHaveBeenCalledTimes( 1 );
|
|
95
|
+
expect( jest.getTimerCount() ).toBe( 0 );
|
|
96
|
+
} );
|
|
97
|
+
} );
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
'name' => 'automattic/newspack-blocks',
|
|
4
4
|
'pretty_version' => 'dev-main',
|
|
5
5
|
'version' => 'dev-main',
|
|
6
|
-
'reference' => '
|
|
6
|
+
'reference' => '6a87cb2c6dcab735a81b54e87fb11b93769baac1',
|
|
7
7
|
'type' => 'wordpress-plugin',
|
|
8
8
|
'install_path' => __DIR__ . '/../../',
|
|
9
9
|
'aliases' => array(),
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
'automattic/newspack-blocks' => array(
|
|
14
14
|
'pretty_version' => 'dev-main',
|
|
15
15
|
'version' => 'dev-main',
|
|
16
|
-
'reference' => '
|
|
16
|
+
'reference' => '6a87cb2c6dcab735a81b54e87fb11b93769baac1',
|
|
17
17
|
'type' => 'wordpress-plugin',
|
|
18
18
|
'install_path' => __DIR__ . '/../../',
|
|
19
19
|
'aliases' => array(),
|