From 19fe932ee3f9653975c74f0de4b8f7265b4f414e Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Thu, 18 Sep 2025 11:52:00 -0400 Subject: [PATCH 1/6] Sets version to 0.7.0 --- .gitignore | 5 ++++- README.md | 2 ++ src/documentcloud/documentcloud.php | 2 +- src/documentcloud/readme.txt | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 291381c..4711d61 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,7 @@ dist **/vendor # Testing -.phpunit.cache \ No newline at end of file +.phpunit.cache + +# Claude Code +CLAUDE.md diff --git a/README.md b/README.md index 3986b01..42b4d3e 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,8 @@ To create a new release: ## Changelog +### 0.7.0 + ### 0.6.0 * Add Gutenberg block for embedding DocumentCloud documents resonating a functionality similar to the shortcode. * Update the shortcode to support the following attributes diff --git a/src/documentcloud/documentcloud.php b/src/documentcloud/documentcloud.php index 2cfa1c4..3d368d6 100644 --- a/src/documentcloud/documentcloud.php +++ b/src/documentcloud/documentcloud.php @@ -3,7 +3,7 @@ * Plugin Name: DocumentCloud * Plugin URI: https://www.documentcloud.org/ * Description: Embed DocumentCloud resources in WordPress content. - * Version: 0.6.0 + * Version: 0.7.0 * Authors: Allan Lasser, Chris Amico, Justin Reese, Dylan Freedman * Text Domain: documentcloud * License: GPLv2 diff --git a/src/documentcloud/readme.txt b/src/documentcloud/readme.txt index c992bed..d35c3fa 100644 --- a/src/documentcloud/readme.txt +++ b/src/documentcloud/readme.txt @@ -3,7 +3,7 @@ Contributors: chrisamico, reefdog, freedmand Tags: documentcloud, documents, journalism, reporting, research Requires at least: 5.0 Tested up to: 6.8 -Stable tag: 0.6.0 +Stable tag: 0.7.0 License: GPLv2 License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -96,6 +96,8 @@ You can read more about publishing and embedding DocumentCloud resources on http == Changelog == += 0.7.0 = + = 0.6.0 = * Add Gutenberg block for embedding DocumentCloud documents resonating a functionality similar to the shortcode. * Update the shortcode to support the following attributes From dd910514c7e9d4e7115b1322f2f6db460018736f Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Thu, 18 Sep 2025 11:52:22 -0400 Subject: [PATCH 2/6] Removes responsive option Closes #8 --- README.md | 11 ++++++----- .../blocks/__tests__/utils.test.js | 8 ++++---- .../blocks/src/documentcloud/edit.js | 6 ------ .../blocks/src/documentcloud/utils/utils.js | 3 --- src/documentcloud/documentcloud.php | 19 ------------------- src/documentcloud/readme.txt | 9 +++++---- tests/Test_WP_DocumentCloud.php | 5 +++-- 7 files changed, 18 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 42b4d3e..38aede8 100644 --- a/README.md +++ b/README.md @@ -55,10 +55,8 @@ Here's the full list of embed options you can pass via shortcode attributes; som ### Documents only: -- `height` (integer): Height (in pixels) of the embed. -- `width` (integer): Width (in pixels) of the embed. If used, will implicitly set `responsive="false"`. -- `responsive` (boolean): Use responsive layout, which dynamically adjusts width to fill content area. Defaults `true`. -- `responsive_offset` (integer): Distance (in pixels) to vertically offset the viewer for some responsive embeds. +- `height` (integer): Maximum height (in pixels) of the embed. +- `width` (integer): Maximum width (in pixels) of the embed. - `page` (integer): Page number to have the document scroll to by default. - `note` (integer): ID of the note that the document should highlight by default. - `notes` (boolean): Hide or show notes. @@ -153,7 +151,7 @@ docker compose exec -it testing bash cd src/documentcloud/blocks # 3. Install Node modules -npm i +npm i --force # 4. Now the container is ready to run Jest tests npm test @@ -172,6 +170,9 @@ To create a new release: ## Changelog ### 0.7.0 +* Removes the `responsive` and `responsive_offset` options. + All embeds are rendered responsively, so this option is now deprecated. + The `height` and `width` of the embed can still be limited with their respective options, but the embeds will respond to the size of their container. ### 0.6.0 * Add Gutenberg block for embedding DocumentCloud documents resonating a functionality similar to the shortcode. diff --git a/src/documentcloud/blocks/__tests__/utils.test.js b/src/documentcloud/blocks/__tests__/utils.test.js index eef784e..07f6ae2 100644 --- a/src/documentcloud/blocks/__tests__/utils.test.js +++ b/src/documentcloud/blocks/__tests__/utils.test.js @@ -59,10 +59,10 @@ describe( 'DocumentCloud Utils', () => { onlyshoworg: false, pdf: true, style: 'custom-style', - responsive: true, + responsive: true, // Check that we ignore the responsive option }; expect( getEmbedUrl( params ) ).toBe( - 'https://www.documentcloud.org/documents/123?embed=1&title=1&fullscreen=0&onlyshoworg=0&pdf=1&style=custom-style&responsive=1' + 'https://www.documentcloud.org/documents/123?embed=1&title=1&fullscreen=0&onlyshoworg=0&pdf=1&style=custom-style' ); } ); @@ -76,10 +76,10 @@ describe( 'DocumentCloud Utils', () => { onlyshoworg: true, pdf: false, style: 'border: 1px solid #000;', - responsive: false, + responsive: false, // Check that we ignore the responsive option }; expect( getEmbedUrl( params ) ).toBe( - 'https://embed.documentcloud.org/documents/24479621-24-03-13-epic-motion-to-enforce-injunction?embed=1&title=0&fullscreen=1&onlyshoworg=1&pdf=0&style=border%3A%201px%20solid%20%23000%3B&responsive=0' + 'https://embed.documentcloud.org/documents/24479621-24-03-13-epic-motion-to-enforce-injunction?embed=1&title=0&fullscreen=1&onlyshoworg=1&pdf=0&style=border%3A%201px%20solid%20%23000%3B' ); } ); } ); diff --git a/src/documentcloud/blocks/src/documentcloud/edit.js b/src/documentcloud/blocks/src/documentcloud/edit.js index 441d423..9f2ebc4 100644 --- a/src/documentcloud/blocks/src/documentcloud/edit.js +++ b/src/documentcloud/blocks/src/documentcloud/edit.js @@ -272,15 +272,10 @@ export default function Edit( { attributes, setAttributes } ) { /** * Generates the embed URL based on current attributes and settings. - * Determines if responsive layout should be used based on dimensions. * * This function is used for both preview and API fetching. */ const generateEmbedUrl = useCallback( () => { - const responsive = - String( tempDimensions.width ).length === 0 && - String( tempDimensions.height ).length === 0; - return getEmbedUrl( { useDocumentId, documentId, @@ -291,7 +286,6 @@ export default function Edit( { attributes, setAttributes } ) { pdf, width: tempDimensions.width, height: tempDimensions.height, - responsive, } ); }, [ useDocumentId, diff --git a/src/documentcloud/blocks/src/documentcloud/utils/utils.js b/src/documentcloud/blocks/src/documentcloud/utils/utils.js index 311ccef..99ce6a1 100644 --- a/src/documentcloud/blocks/src/documentcloud/utils/utils.js +++ b/src/documentcloud/blocks/src/documentcloud/utils/utils.js @@ -45,7 +45,6 @@ export function getDocumentCloudUrlType( url ) { * @param {boolean} params.onlyshoworg - Whether to only show organization. * @param {boolean} params.pdf - Whether to show PDF download link. * @param {string} params.style - Custom CSS style. - * @param {boolean} params.responsive - Should it be responsive. * @return {string} The generated embed URL. */ export const getEmbedUrl = ( { @@ -57,7 +56,6 @@ export const getEmbedUrl = ( { onlyshoworg, pdf, style, - responsive = true, } ) => { if ( ! ( useDocumentId ? documentId : url ) ) { return ''; @@ -121,7 +119,6 @@ export const getEmbedUrl = ( { onlyshoworg: onlyshoworg ? 1 : 0, pdf: pdf ? 1 : 0, style: style || '', - responsive: responsive ? 1 : 0, }; const queryString = Object.entries( params ) diff --git a/src/documentcloud/documentcloud.php b/src/documentcloud/documentcloud.php index 3d368d6..f814d97 100644 --- a/src/documentcloud/documentcloud.php +++ b/src/documentcloud/documentcloud.php @@ -177,12 +177,10 @@ public function get_default_atts() { 'url' => null, 'container' => null, 'notes' => null, - 'responsive_offset' => null, 'page' => null, 'note' => null, 'zoom' => null, 'search' => null, - 'responsive' => null, 'sidebar' => null, 'text' => null, 'pdf' => 0, @@ -236,10 +234,6 @@ public function prepare_oembed_fetch( $provider, $url, $args ) { $args['maxheight'] = $url_args['height']; } - // If the width is set from url we should set the responsive to false just like how the shortcode works. - if ( isset( $url_args['width'] ) && ! array_key_exists( 'responsive', $url_args ) ) { - $args['responsive'] = 0; - } } $atts = wp_parse_args( $args, $default_atts ); @@ -319,15 +313,6 @@ public function process_dc_shortcode( $atts ) { $filtered_atts['maxwidth'] = $atts['width']; } - // `responsive` defaults true, but our responsive layout - // ignores width declarations. If a user indicates a width and - // hasn't otherwise specifically indicated `responsive='true'`, - // it's safe to assume they expect us to respect the width, so - // we disable the responsive flag. - if ( ( isset( $atts['width'] ) || isset( $atts['maxwidth'] ) ) && ( ! array_key_exists( 'responsive', $atts ) || 'true' !== $atts['responsive'] ) ) { - $filtered_atts['responsive'] = 'false'; - } - // If the format is set to wide, it blows away all other width // settings. if ( 'wide' === $filtered_atts['format'] ) { @@ -414,14 +399,10 @@ public function add_options_page() { * Render the DocumentCloud options page. */ public function render_options_page() { - // TODO: remove the responsive warning after the switch. ?>

-

- -

responsive="false" on an embed.', 'documentcloud' ) ); ?>

- diff --git a/src/documentcloud/readme.txt b/src/documentcloud/readme.txt index d35c3fa..27de0bc 100644 --- a/src/documentcloud/readme.txt +++ b/src/documentcloud/readme.txt @@ -52,10 +52,8 @@ Here's the full list of embed options you can pass via shortcode attributes; som **Documents only:** -- `height` (integer): Height (in pixels) of the embed. -- `width` (integer): Width (in pixels) of the embed. If used, will implicitly set `responsive="false"`. -- `responsive` (boolean): Use responsive layout, which dynamically adjusts width to fill content area. Defaults `true`. -- `responsive_offset` (integer): Distance (in pixels) to vertically offset the viewer for some responsive embeds. +- `height` (integer): Maximum height (in pixels) of the embed. +- `width` (integer): Maximum width (in pixels) of the embed. - `page` (integer): Page number to have the document scroll to by default. - `note` (integer): ID of the note that the document should highlight by default. - `notes` (boolean): Hide or show notes. @@ -97,6 +95,9 @@ You can read more about publishing and embedding DocumentCloud resources on http == Changelog == = 0.7.0 = +* Removes the `responsive` URL parameter option. + All embeds are rendered responsively, so this option is now deprecated. + The height and width of the embed can still be controlled with their respective options. = 0.6.0 = * Add Gutenberg block for embedding DocumentCloud documents resonating a functionality similar to the shortcode. diff --git a/tests/Test_WP_DocumentCloud.php b/tests/Test_WP_DocumentCloud.php index cce4aef..3e0448d 100644 --- a/tests/Test_WP_DocumentCloud.php +++ b/tests/Test_WP_DocumentCloud.php @@ -153,7 +153,7 @@ public function test_process_dc_shortcode_with_attributes() { 'url' => 'https://www.documentcloud.org/documents/24475232-2024-03-08-rcfp-letter-to-nj-leg-re-sb-2930/', 'page' => 2, 'zoom' => 150, - 'responsive' => 'true', + 'responsive' => 'true', // check that we ignore the responsive attribute 'sidebar' => 'false', 'width' => 1000, 'height' => 700, @@ -165,10 +165,11 @@ public function test_process_dc_shortcode_with_attributes() { $this->assertStringContainsString( 'embed.documentcloud.org/documents/24475232-2024-03-08-rcfp-letter-to-nj-leg-re-sb-2930', $result ); $this->assertStringContainsString( 'page=2', $result ); $this->assertStringContainsString( 'zoom=150', $result ); - $this->assertStringContainsString( 'responsive=true', $result ); $this->assertStringContainsString( 'sidebar=false', $result ); $this->assertStringContainsString( 'width="1000"', $result ); $this->assertStringContainsString( 'height="700"', $result ); + // Assert the things we don't expect to be present + $this->assertStringNotContainsString( 'responsive=true', $result ); } /** From 64d5a40baf5f1cb6f7d28ca1bda64ebecdfa3095 Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Thu, 18 Sep 2025 13:36:06 -0400 Subject: [PATCH 3/6] Supports "mode" URL parameter and adds block option for picking default mode Fixes #9 --- README.md | 8 +++ .../blocks/__mocks__/@wordpress/components.js | 25 ++++++++ .../blocks/__tests__/edit.test.js | 25 ++++++++ .../blocks/__tests__/utils.test.js | 64 +++++++++++++++++++ .../blocks/build/blocks-manifest.php | 4 ++ .../blocks/build/documentcloud/block.json | 4 ++ .../build/documentcloud/index.asset.php | 2 +- .../blocks/build/documentcloud/index.js | 2 +- .../blocks/src/documentcloud/block.json | 4 ++ .../blocks/src/documentcloud/edit.js | 40 ++++++++++++ .../blocks/src/documentcloud/utils/utils.js | 26 ++++++++ src/documentcloud/documentcloud.php | 27 ++++++++ src/documentcloud/readme.txt | 8 +++ tests/Test_WP_DocumentCloud.php | 62 ++++++++++++++++++ 14 files changed, 299 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38aede8..cfeee1d 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ To embed a note, use any note-specific URL. Notes ignore `width/height` and alwa [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html#document/p1/a53674"] +To control which view is displayed by default, use the `mode` parameter: + + [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html" mode="notes"] + [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html" mode="text"] + [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html" mode="grid"] + Here's the full list of embed options you can pass via shortcode attributes; some are specific to the type of resource you're embedding. @@ -65,6 +71,7 @@ Here's the full list of embed options you can pass via shortcode attributes; som - `pdf` (boolean): Hide or show link to download original PDF. - `text` (boolean): Hide or show text tab. - `zoom` (boolean): Hide or show zoom slider. +- `mode` (string): Display mode for the document viewer. Valid values: `document`, `notes`, `text`, `grid`. Controls which view is shown by default. - `format` (string): Indicate to the theme that this is a wide asset by setting this to `wide`. Defaults `normal`. Or as a Gutenberg Block : @@ -173,6 +180,7 @@ To create a new release: * Removes the `responsive` and `responsive_offset` options. All embeds are rendered responsively, so this option is now deprecated. The `height` and `width` of the embed can still be limited with their respective options, but the embeds will respond to the size of their container. +* Add `mode` parameter to control document viewer display mode. Valid values: `document`, `notes`, `text`, `grid`. ### 0.6.0 * Add Gutenberg block for embedding DocumentCloud documents resonating a functionality similar to the shortcode. diff --git a/src/documentcloud/blocks/__mocks__/@wordpress/components.js b/src/documentcloud/blocks/__mocks__/@wordpress/components.js index 0f297d4..bc4d88c 100644 --- a/src/documentcloud/blocks/__mocks__/@wordpress/components.js +++ b/src/documentcloud/blocks/__mocks__/@wordpress/components.js @@ -40,6 +40,31 @@ export const ToggleControl = ( { label, checked, onChange } ) => { ); }; +export const SelectControl = ( { label, value, options, onChange, help } ) => { + const id = label + ? `select-control-${ label.replace( /\s+/g, '-' ).toLowerCase() }` + : 'select-control-undefined'; + return ( +
+ { label && } + + { help && ( +

{ help }

+ ) } +
+ ); +}; export const Placeholder = ( { children, instructions } ) => (
{ instructions &&

{ instructions }

} diff --git a/src/documentcloud/blocks/__tests__/edit.test.js b/src/documentcloud/blocks/__tests__/edit.test.js index a1f1351..22e5b53 100644 --- a/src/documentcloud/blocks/__tests__/edit.test.js +++ b/src/documentcloud/blocks/__tests__/edit.test.js @@ -17,6 +17,7 @@ describe( 'DocumentCloud Block Edit Component', () => { fullscreen: false, onlyshoworg: false, pdf: false, + mode: 'document', style: '', embeddedHtml: '', }; @@ -264,4 +265,28 @@ describe( 'DocumentCloud Block Edit Component', () => { } ); expect( mockSetAttributes ).toHaveBeenCalledWith( { pdf: true } ); } ); + + // Test: Mode selector calls setAttributes when changed + it( 'calls setAttributes when mode selector is changed', () => { + const attributesWithUrl = { + ...defaultAttributes, + url: 'https://www.documentcloud.org/documents/282753-lefler-thesis/', + }; + + render( + + ); + + // Find the mode selector + const modeSelector = screen.getByLabelText( 'Default Viewer Mode' ); + + // Change the mode to 'notes' + fireEvent.change( modeSelector, { target: { value: 'notes' } } ); + + // Check that setAttributes is called with the new mode + expect( mockSetAttributes ).toHaveBeenCalledWith( { mode: 'notes' } ); + } ); } ); diff --git a/src/documentcloud/blocks/__tests__/utils.test.js b/src/documentcloud/blocks/__tests__/utils.test.js index 07f6ae2..711e94e 100644 --- a/src/documentcloud/blocks/__tests__/utils.test.js +++ b/src/documentcloud/blocks/__tests__/utils.test.js @@ -4,6 +4,7 @@ import { getOEmbedApiUrl, parseDocumentCloudUrl, cleanDocumentCloudUrl, + validateMode, } from '../src/documentcloud/utils/utils'; describe( 'DocumentCloud Utils', () => { @@ -82,6 +83,50 @@ describe( 'DocumentCloud Utils', () => { 'https://embed.documentcloud.org/documents/24479621-24-03-13-epic-motion-to-enforce-injunction?embed=1&title=0&fullscreen=1&onlyshoworg=1&pdf=0&style=border%3A%201px%20solid%20%23000%3B' ); } ); + + it( 'should include valid mode parameter in embed URL', () => { + // Validates that valid mode values are included in the embed URL + const validModes = [ 'document', 'notes', 'text', 'grid' ]; + + validModes.forEach( ( mode ) => { + const params = { + useDocumentId: true, + documentId: '123', + mode: mode, + }; + const result = getEmbedUrl( params ); + expect( result ).toContain( `mode=${ mode }` ); + } ); + } ); + + it( 'should exclude invalid mode parameter from embed URL', () => { + // Validates that invalid mode values are not included in the embed URL + const invalidModes = [ 'invalid', 'foo', 'bar', '', null, undefined ]; + + invalidModes.forEach( ( mode ) => { + const params = { + useDocumentId: true, + documentId: '123', + mode: mode, + }; + const result = getEmbedUrl( params ); + if ( mode && mode !== '' ) { + expect( result ).not.toContain( `mode=${ mode }` ); + } + expect( result ).not.toContain( 'mode=' ); + } ); + } ); + + it( 'should not include mode parameter when not specified', () => { + // Validates that no mode parameter is added when not specified + const params = { + useDocumentId: true, + documentId: '123', + title: true, + }; + const result = getEmbedUrl( params ); + expect( result ).not.toContain( 'mode=' ); + } ); } ); // Tests for getOEmbedApiUrl @@ -143,4 +188,23 @@ describe( 'DocumentCloud Utils', () => { } ); } ); } ); + + // Tests for validateMode + describe( 'validateMode', () => { + it( 'should return valid mode values', () => { + // Tests that valid mode values are returned unchanged + const validModes = [ 'document', 'notes', 'text', 'grid' ]; + validModes.forEach( ( mode ) => { + expect( validateMode( mode ) ).toBe( mode ); + } ); + } ); + + it( 'should return null for invalid mode values', () => { + // Tests that invalid mode values return null + const invalidModes = [ 'invalid', 'foo', 'bar', '', null, undefined ]; + invalidModes.forEach( ( mode ) => { + expect( validateMode( mode ) ).toBeNull(); + } ); + } ); + } ); } ); diff --git a/src/documentcloud/blocks/build/blocks-manifest.php b/src/documentcloud/blocks/build/blocks-manifest.php index 4fe3327..6d5fa81 100644 --- a/src/documentcloud/blocks/build/blocks-manifest.php +++ b/src/documentcloud/blocks/build/blocks-manifest.php @@ -49,6 +49,10 @@ 'type' => 'boolean', 'default' => null ), + 'mode' => array( + 'type' => 'string', + 'default' => 'document' + ), 'embeddedHtml' => array( 'type' => 'string', 'default' => '' diff --git a/src/documentcloud/blocks/build/documentcloud/block.json b/src/documentcloud/blocks/build/documentcloud/block.json index 6b53d88..d817e00 100644 --- a/src/documentcloud/blocks/build/documentcloud/block.json +++ b/src/documentcloud/blocks/build/documentcloud/block.json @@ -44,6 +44,10 @@ "type": "boolean", "default": null }, + "mode": { + "type": "string", + "default": "document" + }, "embeddedHtml": { "type": "string", "default": "" diff --git a/src/documentcloud/blocks/build/documentcloud/index.asset.php b/src/documentcloud/blocks/build/documentcloud/index.asset.php index 147ef6b..87ba1f2 100644 --- a/src/documentcloud/blocks/build/documentcloud/index.asset.php +++ b/src/documentcloud/blocks/build/documentcloud/index.asset.php @@ -1 +1 @@ - array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n'), 'version' => 'd389acc9710d4bc5b62a'); + array('react', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n'), 'version' => '4cbafde8dfd690bf44f0'); diff --git a/src/documentcloud/blocks/build/documentcloud/index.js b/src/documentcloud/blocks/build/documentcloud/index.js index 9d891a7..79b3216 100644 --- a/src/documentcloud/blocks/build/documentcloud/index.js +++ b/src/documentcloud/blocks/build/documentcloud/index.js @@ -1 +1 @@ -(()=>{"use strict";const e=window.wp.blocks,t=window.wp.i18n,n=window.wp.blockEditor,o=window.wp.components,c=window.wp.element,l=window.wp.compose,u="(https?):\\/\\/([\\w.-]*documentcloud\\.org)\\/documents\\/([0-9]+(?:-[\\w\\d%-]*)?)",d=[{type:"document",regex:new RegExp(`^${u}(\\.html)?$`)},{type:"page_hash",regex:new RegExp(`^${u}(\\.html)?\\/?\\??.*#document\\/p([0-9]+)$`),pageGroup:5},{type:"page_ext",regex:new RegExp(`^${u}\\/pages\\/([0-9]+)\\.(html|js)$`),pageGroup:4},{type:"page_no_ext",regex:new RegExp(`^${u}\\/pages\\/([0-9]+)\\/?\\??.*$`),pageGroup:4},{type:"note_annotations",regex:new RegExp(`^${u}\\/annotations\\/([0-9]+)\\.(html|js)$`),noteGroup:4},{type:"note_annotations_embed",regex:new RegExp(`^${u}\\/annotations\\/([0-9]+)\\/?\\??.*$`),noteGroup:4},{type:"note_hash_page",regex:new RegExp(`^${u}(\\.html)?\\/?\\??.*#document\\/p([0-9]+)\\/a([0-9]+)$`),pageGroup:5,noteGroup:6},{type:"note_hash_annotation",regex:new RegExp(`^${u}(\\.html)?\\/?\\??.*#annotation\\/a([0-9]+)(\\.[a-z]+)?$`),noteGroup:5}];function r(e){if(!e)return"document";const t=s(e);return t.note_id?"note":t.page_number?"page":e.includes("/annotations/")?"note":"document"}const s=e=>{if(!e)return{};const t=function(e){return e.includes("/pages/")?d.filter((e=>"page_ext"===e.type||"page_no_ext"===e.type)):e.includes("/annotations/")?d.filter((e=>"note_annotations"===e.type)):e.includes("#document/p")?e.includes("/a")?d.filter((e=>"note_hash_page"===e.type)):d.filter((e=>"page_hash"===e.type)):e.includes("#annotation/a")?d.filter((e=>"note_hash_annotation"===e.type)):d.filter((e=>"document"===e.type))}(e);for(const n of t){const t=e.match(n.regex);if(t){const e={protocol:t[1],dc_host:t[2],document_slug:t[3]};return n.pageGroup&&t[n.pageGroup]&&(e.page_number=t[n.pageGroup]),n.noteGroup&&t[n.noteGroup]&&(e.note_id=t[n.noteGroup]),e}}return{}},a=window.ReactJSXRuntime;function i({embeddedHtml:e,isLoading:l,fetchError:u,onChangeDocument:d}){const r=(0,c.useRef)(null),s=(0,n.useBlockProps)(),i=(0,c.useMemo)((()=>s.className?.includes("is-selected")),[s.className]);return null===l||l?(0,a.jsxs)("div",{className:"documentcloud-loading",children:[(0,a.jsx)(o.Spinner,{}),(0,a.jsx)("p",{children:(0,t.__)("Loading document…","documentcloud")})]}):u?(0,a.jsxs)("div",{className:"documentcloud-error-container",children:[(0,a.jsx)(o.Notice,{status:"error",isDismissible:!1,children:u}),(0,a.jsx)(m,{onChangeDocument:d})]}):e?(0,a.jsxs)("div",{className:"documentcloud-preview",ref:r,children:[(0,a.jsx)("div",{className:"documentcloud-embed documentcloud-oembed",dangerouslySetInnerHTML:{__html:e}}),i?null:(0,a.jsx)("div",{className:"documentcloud-overlay"}),(0,a.jsx)(m,{onChangeDocument:d})]}):(0,a.jsxs)("div",{className:"documentcloud-preview",ref:r,children:[(0,a.jsx)("div",{className:"documentcloud-placeholder",children:(0,a.jsx)("p",{children:(0,t.__)("Document preview not available.","documentcloud")})}),(0,a.jsx)(m,{onChangeDocument:d})]})}function m({onChangeDocument:e}){return(0,a.jsx)("div",{className:"documentcloud-preview-footer",children:(0,a.jsx)(o.Button,{variant:"secondary",onClick:e,className:"documentcloud-clear-button",children:(0,t.__)("Change Document","documentcloud")})})}const h=window.React;var p,g;function _(){return _=Object.assign?Object.assign.bind():function(e){for(var t=1;t""===j),[j]),M="document"===I,O=(0,c.useCallback)(((e,t)=>{k((n=>({...n,[e]:t}))),u({[e]:t})}),[u]),z=(0,c.useCallback)((e=>{D(e),v("")}),[]),F=(0,c.useCallback)((e=>{/[^0-9]/.test(String(String(e).trim()))?v((0,t.__)("Document ID can only contain digits.","documentcloud")):(E(e),v(""))}),[]),q=(0,c.useCallback)((()=>{u({useDocumentId:!m}),v("")}),[m,u]),A=(0,c.useCallback)((e=>{e.preventDefault(),$(null);try{if(m){const e=R.trim(),n=e?{valid:!0,message:""}:{valid:!1,message:(0,t.__)("Please enter a DocumentCloud ID.","documentcloud")};v(n.message),n.valid&&(u({documentId:e,url:"",embeddedHtml:""}),B("document"),T(!1))}else{let e=C.trim();const n=(e=>{if(!e)return{valid:!1,message:(0,t.__)("Please enter a DocumentCloud URL.","documentcloud")};const n=e.trim(),o=new Set(["documentcloud.org","www.documentcloud.org","beta.documentcloud.org","embed.documentcloud.org","assets.documentcloud.org"]);try{const e=new URL(n);return"https:"!==e.protocol?{valid:!1,message:(0,t.__)("URL must use HTTPS protocol.","documentcloud")}:o.has(e.hostname)?{valid:!0,message:""}:{valid:!1,message:(0,t.__)("URL must be from a valid DocumentCloud domain.","documentcloud")}}catch(e){return{valid:!1,message:(0,t.__)("Please enter a valid URL.","documentcloud")}}})(e);if(v(n.message),n.valid){const t=r(e);if(B(t),"document"===t){const t=((e,t,n)=>{if(!e)return;const o=new URL(e);if(o)try{const e=o.searchParams,c=e.get("height");e.delete("height"),c&&t("height",c);const l=e.get("width");e.delete("width"),l&&t("width",l);const u=String(e.get("title"));e.delete("title"),["0","1"].includes(u)&&n({title:"1"===u});const d=String(e.get("onlyshoworg"));e.delete("onlyshoworg"),["0","1"].includes(d)&&n({onlyshoworg:"1"===d});const r=String(e.get("fullscreen"));e.delete("fullscreen"),["0","1"].includes(r)&&n({fullscreen:"1"===r});const s=String(e.get("pdf"));e.delete("pdf"),["0","1"].includes(s)&&n({pdf:"1"===s})}catch{}return o})(e,O,u);t&&(e=t.toString())}u({url:e,documentId:"",embeddedHtml:""}),T(!1)}}}catch(e){v((0,t.__)("An unexpected error occurred. Please try again.","documentcloud"))}}),[m,R,C,u,O]),J=(0,c.useCallback)((()=>{T(!0),v("")}),[]),W=(0,c.useCallback)((()=>{const e=0===String(N.width).length&&0===String(N.height).length;return(({useDocumentId:e,documentId:t,url:n,title:o,fullscreen:c,onlyshoworg:l,pdf:u,style:d,responsive:s=!0})=>{if(!(e?t:n))return"";let a="";e&&t?a=`https://www.documentcloud.org/documents/${encodeURIComponent(t.trim())}`:!e&&n&&(a=n.trim(),a.startsWith("https://")||(a=a.replace(/^http:\/\//,"https://")));const i=r(a);if(("page"===i||"note"===i)&&(a.includes("#document/p")||a.includes("#annotation/a"))){if(!a.includes("embed=1"))if(a.includes("?"))a=a.replace("?","?embed=1&");else{const e=a.indexOf("#");-1!==e?a=a.substring(0,e)+"?embed=1"+a.substring(e):a+="?embed=1"}return a}"boolean"!=typeof o&&(o=!0),"boolean"!=typeof c&&(c=!0);const m={embed:1,title:o?1:0,fullscreen:c?1:0,onlyshoworg:l?1:0,pdf:u?1:0,style:d||"",responsive:s?1:0},h=Object.entries(m).filter((([,e])=>""!==e)).map((([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(t)}`)).join("&");return h?`${a}?${h}`:a})({useDocumentId:m,documentId:s,url:d,title:g,fullscreen:_,onlyshoworg:f,pdf:x,width:N.width,height:N.height,responsive:e})}),[m,s,d,g,_,f,x,N]),V=(0,c.useCallback)((()=>((e,t,n)=>{if(!e)return"";const o=new URLSearchParams;if(o.append("url",e),o.append("format","json"),o.append("dnt","1"),t){const e=t.toString().replace(/[^0-9]/g,"");e&&o.append("maxwidth",e)}if(n){const e=n.toString().replace(/[^0-9]/g,"");e&&o.append("maxheight",e)}return`https://api.www.documentcloud.org/api/oembed/?${o.toString()}`})(W(),p,h)),[W,p,h]);(0,c.useEffect)((()=>(U.current=!0,()=>{U.current=!1})),[]),(0,c.useEffect)((()=>{H&&(D(d||""),E(s||""))}),[H,d,s]),(0,c.useEffect)((()=>{d&&U.current&&B(r(d))}),[d]),(0,c.useEffect)((()=>{U.current&&k({width:p||"",height:h||""})}),[p,h]),(0,c.useEffect)((()=>(L.current=(0,l.debounce)((async e=>{if(!e||H||!G||!U.current)return;$(!0),S("");const{html:t,error:n}=await(async e=>{try{const t=await fetch(e);if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);return{html:(await t.json()).html||"",error:""}}catch(e){return{html:"",error:"Failed to load document preview."}}})(e);U.current&&(n&&S(n),u({embeddedHtml:t}),$(!1))}),700),()=>{L.current&&L.current.cancel()})),[H,G,u]),(0,c.useEffect)((()=>{const e=V();e&&!H&&G&&L.current&&L.current(e)}),[V,H,G]);const X=(0,n.useBlockProps)();return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(n.InspectorControls,{children:[(0,a.jsxs)(o.PanelBody,{title:(0,t.__)("Document Settings","documentcloud"),initialOpen:!0,children:[(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.TextControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,type:"number",label:(0,t.__)("Height","documentcloud"),value:N.height,onChange:e=>O("height",e),help:(0,t.__)("Set the height (Only numeric values allowed).","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.TextControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,type:"number",label:(0,t.__)("Width","documentcloud"),value:N.width,onChange:e=>O("width",e),help:(0,t.__)("Set the width (Only Numberic Values are allowed).","documentcloud")})})]}),M&&(0,a.jsxs)(o.PanelBody,{title:(0,t.__)("Display Options","documentcloud"),initialOpen:!0,children:[(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Show Title","documentcloud"),checked:g,onChange:()=>u({title:!g}),help:(0,t.__)("Show document title and contributor name.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Show Fullscreen Button","documentcloud"),checked:_,onChange:()=>u({fullscreen:!_}),help:(0,t.__)("Show fullscreen control.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Only Show Organization","documentcloud"),checked:f,onChange:()=>u({onlyshoworg:!f}),help:(0,t.__)("Show affiliation without username.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Show PDF Download Link","documentcloud"),checked:x,onChange:()=>u({pdf:!x}),help:(0,t.__)("Shows PDF download link.","documentcloud")})})]})]}),(0,a.jsx)("div",{...X,children:!H&&G?(0,a.jsx)(i,{embeddedHtml:b,isLoading:P,fetchError:y,urlType:I,width:p,height:h,onChangeDocument:J}):(0,a.jsxs)(o.Placeholder,{icon:(0,a.jsx)(w,{}),label:(0,t.__)("DocumentCloud","documentcloud"),instructions:m?(0,t.__)("Enter a DocumentCloud ID to embed a document.","documentcloud"):(0,t.__)("Enter a DocumentCloud URL to embed a document, page or note.","documentcloud"),children:[!G&&j&&(0,a.jsx)(o.Notice,{status:"error",isDismissible:!1,children:j}),(0,a.jsx)("form",{onSubmit:A,className:"documentcloud-form",children:(0,a.jsxs)("div",{className:"documentcloud-input-wrapper",children:[(0,a.jsx)(o.ToggleControl,{label:(0,t.__)("Use Document ID","documentcloud"),checked:m,onChange:q,help:(0,t.__)("Toggle between URL and Document ID input.","documentcloud")}),(0,a.jsxs)("div",{className:"documentcloud-input-row",children:[m?(0,a.jsx)(a.Fragment,{children:(0,a.jsx)(o.TextControl,{value:R,inputMode:"numeric",pattern:"[0-9]*",onChange:F,type:"text",placeholder:(0,t.__)("123456789","documentcloud"),className:!G&&R?"has-error":""})}):(0,a.jsx)(o.TextControl,{value:C,onChange:z,placeholder:(0,t.__)("https://www.documentcloud.org/documents/…","documentcloud"),className:!G&&C?"has-error":""}),(0,a.jsx)(o.Button,{variant:"primary",type:"submit",children:(0,t.__)("Embed","documentcloud")})]})]})})]})})]})},save:function({attributes:e}){const{embeddedHtml:t}=e,o=n.useBlockProps.save();return t?(0,a.jsx)("div",{...o,children:(0,a.jsx)("div",{className:"documentcloud-embed",dangerouslySetInnerHTML:{__html:t}})}):(0,a.jsx)("div",{...o})}})})(); \ No newline at end of file +(()=>{"use strict";const e=window.wp.blocks,t=window.wp.i18n,n=window.wp.blockEditor,o=window.wp.components,l=window.wp.element,c=window.wp.compose,u="(https?):\\/\\/([\\w.-]*documentcloud\\.org)\\/documents\\/([0-9]+(?:-[\\w\\d%-]*)?)",d=[{type:"document",regex:new RegExp(`^${u}(\\.html)?$`)},{type:"page_hash",regex:new RegExp(`^${u}(\\.html)?\\/?\\??.*#document\\/p([0-9]+)$`),pageGroup:5},{type:"page_ext",regex:new RegExp(`^${u}\\/pages\\/([0-9]+)\\.(html|js)$`),pageGroup:4},{type:"page_no_ext",regex:new RegExp(`^${u}\\/pages\\/([0-9]+)\\/?\\??.*$`),pageGroup:4},{type:"note_annotations",regex:new RegExp(`^${u}\\/annotations\\/([0-9]+)\\.(html|js)$`),noteGroup:4},{type:"note_annotations_embed",regex:new RegExp(`^${u}\\/annotations\\/([0-9]+)\\/?\\??.*$`),noteGroup:4},{type:"note_hash_page",regex:new RegExp(`^${u}(\\.html)?\\/?\\??.*#document\\/p([0-9]+)\\/a([0-9]+)$`),pageGroup:5,noteGroup:6},{type:"note_hash_annotation",regex:new RegExp(`^${u}(\\.html)?\\/?\\??.*#annotation\\/a([0-9]+)(\\.[a-z]+)?$`),noteGroup:5}];function r(e){if(!e)return"document";const t=s(e);return t.note_id?"note":t.page_number?"page":e.includes("/annotations/")?"note":"document"}const s=e=>{if(!e)return{};const t=function(e){return e.includes("/pages/")?d.filter((e=>"page_ext"===e.type||"page_no_ext"===e.type)):e.includes("/annotations/")?d.filter((e=>"note_annotations"===e.type)):e.includes("#document/p")?e.includes("/a")?d.filter((e=>"note_hash_page"===e.type)):d.filter((e=>"page_hash"===e.type)):e.includes("#annotation/a")?d.filter((e=>"note_hash_annotation"===e.type)):d.filter((e=>"document"===e.type))}(e);for(const n of t){const t=e.match(n.regex);if(t){const e={protocol:t[1],dc_host:t[2],document_slug:t[3]};return n.pageGroup&&t[n.pageGroup]&&(e.page_number=t[n.pageGroup]),n.noteGroup&&t[n.noteGroup]&&(e.note_id=t[n.noteGroup]),e}}return{}},a=window.ReactJSXRuntime;function i({embeddedHtml:e,isLoading:c,fetchError:u,onChangeDocument:d}){const r=(0,l.useRef)(null),s=(0,n.useBlockProps)(),i=(0,l.useMemo)((()=>s.className?.includes("is-selected")),[s.className]);return null===c||c?(0,a.jsxs)("div",{className:"documentcloud-loading",children:[(0,a.jsx)(o.Spinner,{}),(0,a.jsx)("p",{children:(0,t.__)("Loading document…","documentcloud")})]}):u?(0,a.jsxs)("div",{className:"documentcloud-error-container",children:[(0,a.jsx)(o.Notice,{status:"error",isDismissible:!1,children:u}),(0,a.jsx)(m,{onChangeDocument:d})]}):e?(0,a.jsxs)("div",{className:"documentcloud-preview",ref:r,children:[(0,a.jsx)("div",{className:"documentcloud-embed documentcloud-oembed",dangerouslySetInnerHTML:{__html:e}}),i?null:(0,a.jsx)("div",{className:"documentcloud-overlay"}),(0,a.jsx)(m,{onChangeDocument:d})]}):(0,a.jsxs)("div",{className:"documentcloud-preview",ref:r,children:[(0,a.jsx)("div",{className:"documentcloud-placeholder",children:(0,a.jsx)("p",{children:(0,t.__)("Document preview not available.","documentcloud")})}),(0,a.jsx)(m,{onChangeDocument:d})]})}function m({onChangeDocument:e}){return(0,a.jsx)("div",{className:"documentcloud-preview-footer",children:(0,a.jsx)(o.Button,{variant:"secondary",onClick:e,className:"documentcloud-clear-button",children:(0,t.__)("Change Document","documentcloud")})})}const h=window.React;var p,g;function _(){return _=Object.assign?Object.assign.bind():function(e){for(var t=1;t""===v),[v]),O="document"===B,z=(0,l.useCallback)(((e,t)=>{k((n=>({...n,[e]:t}))),u({[e]:t})}),[u]),F=(0,l.useCallback)((e=>{R(e),y("")}),[]),q=(0,l.useCallback)((e=>{/[^0-9]/.test(String(String(e).trim()))?y((0,t.__)("Document ID can only contain digits.","documentcloud")):(E(e),y(""))}),[]),A=(0,l.useCallback)((()=>{u({useDocumentId:!m}),y("")}),[m,u]),J=(0,l.useCallback)((e=>{e.preventDefault(),I(null);try{if(m){const e=N.trim(),n=e?{valid:!0,message:""}:{valid:!1,message:(0,t.__)("Please enter a DocumentCloud ID.","documentcloud")};y(n.message),n.valid&&(u({documentId:e,url:"",embeddedHtml:""}),H("document"),U(!1))}else{let e=D.trim();const n=(e=>{if(!e)return{valid:!1,message:(0,t.__)("Please enter a DocumentCloud URL.","documentcloud")};const n=e.trim(),o=new Set(["documentcloud.org","www.documentcloud.org","beta.documentcloud.org","embed.documentcloud.org","assets.documentcloud.org"]);try{const e=new URL(n);return"https:"!==e.protocol?{valid:!1,message:(0,t.__)("URL must use HTTPS protocol.","documentcloud")}:o.has(e.hostname)?{valid:!0,message:""}:{valid:!1,message:(0,t.__)("URL must be from a valid DocumentCloud domain.","documentcloud")}}catch(e){return{valid:!1,message:(0,t.__)("Please enter a valid URL.","documentcloud")}}})(e);if(y(n.message),n.valid){const t=r(e);if(H(t),"document"===t){const t=((e,t,n)=>{if(!e)return;const o=new URL(e);if(o)try{const e=o.searchParams,l=e.get("height");e.delete("height"),l&&t("height",l);const c=e.get("width");e.delete("width"),c&&t("width",c);const u=String(e.get("title"));e.delete("title"),["0","1"].includes(u)&&n({title:"1"===u});const d=String(e.get("onlyshoworg"));e.delete("onlyshoworg"),["0","1"].includes(d)&&n({onlyshoworg:"1"===d});const r=String(e.get("fullscreen"));e.delete("fullscreen"),["0","1"].includes(r)&&n({fullscreen:"1"===r});const s=String(e.get("pdf"));e.delete("pdf"),["0","1"].includes(s)&&n({pdf:"1"===s})}catch{}return o})(e,z,u);t&&(e=t.toString())}u({url:e,documentId:"",embeddedHtml:""}),U(!1)}}}catch(e){y((0,t.__)("An unexpected error occurred. Please try again.","documentcloud"))}}),[m,N,D,u,z]),V=(0,l.useCallback)((()=>{U(!0),y("")}),[]),W=(0,l.useCallback)((()=>(({useDocumentId:e,documentId:t,url:n,title:o,fullscreen:l,onlyshoworg:c,pdf:u,style:d,mode:s})=>{if(!(e?t:n))return"";let a="";e&&t?a=`https://www.documentcloud.org/documents/${encodeURIComponent(t.trim())}`:!e&&n&&(a=n.trim(),a.startsWith("https://")||(a=a.replace(/^http:\/\//,"https://")));const i=r(a);if(("page"===i||"note"===i)&&(a.includes("#document/p")||a.includes("#annotation/a"))){if(!a.includes("embed=1"))if(a.includes("?"))a=a.replace("?","?embed=1&");else{const e=a.indexOf("#");-1!==e?a=a.substring(0,e)+"?embed=1"+a.substring(e):a+="?embed=1"}return a}"boolean"!=typeof o&&(o=!0),"boolean"!=typeof l&&(l=!0);const m=function(e){return["document","notes","text","grid"].includes(e)?e:null}(s),h={embed:1,title:o?1:0,fullscreen:l?1:0,onlyshoworg:c?1:0,pdf:u?1:0,style:d||""};m&&(h.mode=m);const p=Object.entries(h).filter((([,e])=>""!==e)).map((([e,t])=>`${encodeURIComponent(e)}=${encodeURIComponent(t)}`)).join("&");return p?`${a}?${p}`:a})({useDocumentId:m,documentId:s,url:d,title:g,fullscreen:_,onlyshoworg:x,pdf:f,mode:b,width:P.width,height:P.height})),[m,s,d,g,_,x,f,b,P]),X=(0,l.useCallback)((()=>((e,t,n)=>{if(!e)return"";const o=new URLSearchParams;if(o.append("url",e),o.append("format","json"),o.append("dnt","1"),t){const e=t.toString().replace(/[^0-9]/g,"");e&&o.append("maxwidth",e)}if(n){const e=n.toString().replace(/[^0-9]/g,"");e&&o.append("maxheight",e)}return`https://api.www.documentcloud.org/api/oembed/?${o.toString()}`})(W(),p,h)),[W,p,h]);(0,l.useEffect)((()=>(G.current=!0,()=>{G.current=!1})),[]),(0,l.useEffect)((()=>{T&&(R(d||""),E(s||""))}),[T,d,s]),(0,l.useEffect)((()=>{d&&G.current&&H(r(d))}),[d]),(0,l.useEffect)((()=>{G.current&&k({width:p||"",height:h||""})}),[p,h]),(0,l.useEffect)((()=>(L.current=(0,c.debounce)((async e=>{if(!e||T||!M||!G.current)return;I(!0),S("");const{html:t,error:n}=await(async e=>{try{const t=await fetch(e);if(!t.ok)throw new Error(`HTTP error! Status: ${t.status}`);return{html:(await t.json()).html||"",error:""}}catch(e){return{html:"",error:"Failed to load document preview."}}})(e);G.current&&(n&&S(n),u({embeddedHtml:t}),I(!1))}),700),()=>{L.current&&L.current.cancel()})),[T,M,u]),(0,l.useEffect)((()=>{const e=X();e&&!T&&M&&L.current&&L.current(e)}),[X,T,M]);const K=(0,n.useBlockProps)();return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(n.InspectorControls,{children:[(0,a.jsxs)(o.PanelBody,{title:(0,t.__)("Document Settings","documentcloud"),initialOpen:!0,children:[(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.TextControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,type:"number",label:(0,t.__)("Height","documentcloud"),value:P.height,onChange:e=>z("height",e),help:(0,t.__)("Set the height (Only numeric values allowed).","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.TextControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,type:"number",label:(0,t.__)("Width","documentcloud"),value:P.width,onChange:e=>z("width",e),help:(0,t.__)("Set the width (Only Numberic Values are allowed).","documentcloud")})})]}),O&&(0,a.jsxs)(o.PanelBody,{title:(0,t.__)("Display Options","documentcloud"),initialOpen:!0,children:[(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.SelectControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Default Viewer Mode","documentcloud"),value:b,options:[{label:(0,t.__)("Document","documentcloud"),value:"document"},{label:(0,t.__)("Notes","documentcloud"),value:"notes"},{label:(0,t.__)("Text","documentcloud"),value:"text"},{label:(0,t.__)("Grid","documentcloud"),value:"grid"}],onChange:e=>u({mode:e}),help:(0,t.__)("Select which view to show by default.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Show Title","documentcloud"),checked:g,onChange:()=>u({title:!g}),help:(0,t.__)("Show document title and contributor name.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Show Fullscreen Button","documentcloud"),checked:_,onChange:()=>u({fullscreen:!_}),help:(0,t.__)("Show fullscreen control.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Only Show Organization","documentcloud"),checked:x,onChange:()=>u({onlyshoworg:!x}),help:(0,t.__)("Show affiliation without username.","documentcloud")})}),(0,a.jsx)(o.PanelRow,{children:(0,a.jsx)(o.ToggleControl,{__next40pxDefaultSize:!0,__nextHasNoMarginBottom:!0,label:(0,t.__)("Show PDF Download Link","documentcloud"),checked:f,onChange:()=>u({pdf:!f}),help:(0,t.__)("Shows PDF download link.","documentcloud")})})]})]}),(0,a.jsx)("div",{...K,children:!T&&M?(0,a.jsx)(i,{embeddedHtml:j,isLoading:$,fetchError:C,urlType:B,width:p,height:h,onChangeDocument:V}):(0,a.jsxs)(o.Placeholder,{icon:(0,a.jsx)(w,{}),label:(0,t.__)("DocumentCloud","documentcloud"),instructions:m?(0,t.__)("Enter a DocumentCloud ID to embed a document.","documentcloud"):(0,t.__)("Enter a DocumentCloud URL to embed a document, page or note.","documentcloud"),children:[!M&&v&&(0,a.jsx)(o.Notice,{status:"error",isDismissible:!1,children:v}),(0,a.jsx)("form",{onSubmit:J,className:"documentcloud-form",children:(0,a.jsxs)("div",{className:"documentcloud-input-wrapper",children:[(0,a.jsx)(o.ToggleControl,{label:(0,t.__)("Use Document ID","documentcloud"),checked:m,onChange:A,help:(0,t.__)("Toggle between URL and Document ID input.","documentcloud")}),(0,a.jsxs)("div",{className:"documentcloud-input-row",children:[m?(0,a.jsx)(a.Fragment,{children:(0,a.jsx)(o.TextControl,{value:N,inputMode:"numeric",pattern:"[0-9]*",onChange:q,type:"text",placeholder:(0,t.__)("123456789","documentcloud"),className:!M&&N?"has-error":""})}):(0,a.jsx)(o.TextControl,{value:D,onChange:F,placeholder:(0,t.__)("https://www.documentcloud.org/documents/…","documentcloud"),className:!M&&D?"has-error":""}),(0,a.jsx)(o.Button,{variant:"primary",type:"submit",children:(0,t.__)("Embed","documentcloud")})]})]})})]})})]})},save:function({attributes:e}){const{embeddedHtml:t}=e,o=n.useBlockProps.save();return t?(0,a.jsx)("div",{...o,children:(0,a.jsx)("div",{className:"documentcloud-embed",dangerouslySetInnerHTML:{__html:t}})}):(0,a.jsx)("div",{...o})}})})(); \ No newline at end of file diff --git a/src/documentcloud/blocks/src/documentcloud/block.json b/src/documentcloud/blocks/src/documentcloud/block.json index 7ec621c..4920be5 100644 --- a/src/documentcloud/blocks/src/documentcloud/block.json +++ b/src/documentcloud/blocks/src/documentcloud/block.json @@ -44,6 +44,10 @@ "type": "boolean", "default": null }, + "mode": { + "type": "string", + "default": "document" + }, "embeddedHtml": { "type": "string", "default": "" diff --git a/src/documentcloud/blocks/src/documentcloud/edit.js b/src/documentcloud/blocks/src/documentcloud/edit.js index 9f2ebc4..4a7e960 100644 --- a/src/documentcloud/blocks/src/documentcloud/edit.js +++ b/src/documentcloud/blocks/src/documentcloud/edit.js @@ -8,6 +8,7 @@ import { PanelRow, TextControl, ToggleControl, + SelectControl, Placeholder, Button, Notice, @@ -66,6 +67,7 @@ export default function Edit( { attributes, setAttributes } ) { fullscreen, onlyshoworg, pdf, + mode, embeddedHtml, } = attributes; @@ -284,6 +286,7 @@ export default function Edit( { attributes, setAttributes } ) { fullscreen, onlyshoworg, pdf, + mode, width: tempDimensions.width, height: tempDimensions.height, } ); @@ -295,6 +298,7 @@ export default function Edit( { attributes, setAttributes } ) { fullscreen, onlyshoworg, pdf, + mode, tempDimensions, ] ); @@ -490,6 +494,41 @@ export default function Edit( { attributes, setAttributes } ) { title={ __( 'Display Options', 'documentcloud' ) } initialOpen={ true } > + { /* Mode Selector */ } + + + setAttributes( { mode: value } ) + } + help={ __( + 'Select which view to show by default.', + 'documentcloud' + ) } + /> + + { /* Title Toggle */ } + ) } diff --git a/src/documentcloud/blocks/src/documentcloud/utils/utils.js b/src/documentcloud/blocks/src/documentcloud/utils/utils.js index 99ce6a1..85e9272 100644 --- a/src/documentcloud/blocks/src/documentcloud/utils/utils.js +++ b/src/documentcloud/blocks/src/documentcloud/utils/utils.js @@ -1,5 +1,21 @@ import { PATTERN_CONFIGS } from './constants'; +/** + * Validate mode parameter value. + * + * @param {string} mode The mode value to validate. + * @return {string|null} The valid mode value or null if invalid. + */ +export function validateMode( mode ) { + const validModes = [ 'document', 'notes', 'text', 'grid' ]; + + if ( validModes.includes( mode ) ) { + return mode; + } + + return null; +} + /** * Get the type of DocumentCloud URL. * @@ -45,6 +61,7 @@ export function getDocumentCloudUrlType( url ) { * @param {boolean} params.onlyshoworg - Whether to only show organization. * @param {boolean} params.pdf - Whether to show PDF download link. * @param {string} params.style - Custom CSS style. + * @param {string} params.mode - Display mode (document, notes, text, grid). * @return {string} The generated embed URL. */ export const getEmbedUrl = ( { @@ -56,6 +73,7 @@ export const getEmbedUrl = ( { onlyshoworg, pdf, style, + mode, } ) => { if ( ! ( useDocumentId ? documentId : url ) ) { return ''; @@ -111,6 +129,9 @@ export const getEmbedUrl = ( { fullscreen = true; } + // Validate mode parameter + const validatedMode = validateMode( mode ); + // For regular document URLs, add the query parameters const params = { embed: 1, @@ -121,6 +142,11 @@ export const getEmbedUrl = ( { style: style || '', }; + // Add mode parameter only if it's valid + if ( validatedMode ) { + params.mode = validatedMode; + } + const queryString = Object.entries( params ) .filter( ( [ , value ] ) => value !== '' ) .map( ( [ key, value ] ) => { diff --git a/src/documentcloud/documentcloud.php b/src/documentcloud/documentcloud.php index f814d97..aad3819 100644 --- a/src/documentcloud/documentcloud.php +++ b/src/documentcloud/documentcloud.php @@ -187,6 +187,7 @@ public function get_default_atts() { 'onlyshoworg' => 0, 'title' => null, 'fullscreen' => 1, + 'mode' => null, // The following defaults match the existing plugin, except // `height/width` are prefixed `max*` per the oEmbed spec. // You can still use `height/width` for backwards @@ -203,6 +204,22 @@ public function get_default_atts() { ); } + /** + * Validate mode parameter value. + * + * @param string $mode The mode value to validate. + * @return string|null The valid mode value or null if invalid. + */ + public function validate_mode( $mode ) { + $valid_modes = array( 'document', 'notes', 'text', 'grid' ); + + if ( in_array( $mode, $valid_modes, true ) ) { + return $mode; + } + + return null; + } + /** * Prepare the oEmbed fetch URL. * @@ -238,6 +255,16 @@ public function prepare_oembed_fetch( $provider, $url, $args ) { $atts = wp_parse_args( $args, $default_atts ); + // Validate mode parameter and remove it if invalid. + if ( isset( $atts['mode'] ) ) { + $validated_mode = $this->validate_mode( $atts['mode'] ); + if ( null === $validated_mode ) { + unset( $atts['mode'] ); + } else { + $atts['mode'] = $validated_mode; + } + } + // Some resources (like notes) have multiple possible // user-facing URLs. We recompose them into a single form. $url = $this->clean_dc_url( $url ); diff --git a/src/documentcloud/readme.txt b/src/documentcloud/readme.txt index 27de0bc..108c7ac 100644 --- a/src/documentcloud/readme.txt +++ b/src/documentcloud/readme.txt @@ -43,6 +43,12 @@ To embed a note, use any note-specific URL. Notes ignore `width/height` and alwa [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html#document/p1/a53674"] +To control which view is displayed by default, use the `mode` parameter: + + [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html" mode="notes"] + [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html" mode="text"] + [documentcloud url="https://www.documentcloud.org/documents/282753-lefler-thesis.html" mode="grid"] + Here's the full list of embed options you can pass via shortcode attributes; some are specific to the type of resource you're embedding. **All resources:** @@ -62,6 +68,7 @@ Here's the full list of embed options you can pass via shortcode attributes; som - `pdf` (boolean): Hide or show link to download original PDF. - `text` (boolean): Hide or show text tab. - `zoom` (boolean): Hide or show zoom slider. +- `mode` (string): Display mode for the document viewer. Valid values: `document`, `notes`, `text`, `grid`. Controls which view is shown by default. - `format` (string): Indicate to the theme that this is a wide asset by setting this to `wide`. Defaults `normal`. Or as a Gutenberg Block: @@ -98,6 +105,7 @@ You can read more about publishing and embedding DocumentCloud resources on http * Removes the `responsive` URL parameter option. All embeds are rendered responsively, so this option is now deprecated. The height and width of the embed can still be controlled with their respective options. +* Add `mode` parameter to control document viewer display mode. Valid values: `document`, `notes`, `text`, `grid`. = 0.6.0 = * Add Gutenberg block for embedding DocumentCloud documents resonating a functionality similar to the shortcode. diff --git a/tests/Test_WP_DocumentCloud.php b/tests/Test_WP_DocumentCloud.php index 3e0448d..c9197c4 100644 --- a/tests/Test_WP_DocumentCloud.php +++ b/tests/Test_WP_DocumentCloud.php @@ -233,4 +233,66 @@ public function test_parse_dc_url() { $this->assertEquals( 'www.documentcloud.org', $result['dc_host'] ); $this->assertEquals( '24475232-2024-03-08-rcfp-letter-to-nj-leg-re-sb-2930', $result['document_slug'] ); } + + /** + * Test the process_dc_shortcode method with mode parameter. + * + * Ensures valid mode values are included in the embed URL. + */ + public function test_process_dc_shortcode_with_valid_mode() { + $valid_modes = array( 'document', 'notes', 'text', 'grid' ); + + foreach ( $valid_modes as $mode ) { + $atts = array( + 'url' => 'https://www.documentcloud.org/documents/24475232-2024-03-08-rcfp-letter-to-nj-leg-re-sb-2930', + 'mode' => $mode, + ); + + $result = $this->dc->process_dc_shortcode( $atts ); + + // Assert that the result contains the mode parameter. + $this->assertStringContainsString( "mode={$mode}", $result, "Mode '{$mode}' should be included in embed URL" ); + } + } + + /** + * Test the process_dc_shortcode method with invalid mode parameter. + * + * Ensures invalid mode values are not included in the embed URL. + */ + public function test_process_dc_shortcode_with_invalid_mode() { + $invalid_modes = array( 'invalid', 'foo', 'bar', '', null ); + + foreach ( $invalid_modes as $mode ) { + $atts = array( + 'url' => 'https://www.documentcloud.org/documents/24475232-2024-03-08-rcfp-letter-to-nj-leg-re-sb-2930', + 'mode' => $mode, + ); + + $result = $this->dc->process_dc_shortcode( $atts ); + + // Assert that the result does not contain an invalid mode parameter. + if ( ! empty( $mode ) ) { + $this->assertStringNotContainsString( "mode={$mode}", $result, "Invalid mode '{$mode}' should not be included in embed URL" ); + } + // Also check that no mode parameter is present at all for invalid values. + $this->assertStringNotContainsString( 'mode=', $result, "No mode parameter should be present for invalid value" ); + } + } + + /** + * Test the process_dc_shortcode method without mode parameter. + * + * Ensures that when no mode is specified, no mode parameter is added to the URL. + */ + public function test_process_dc_shortcode_without_mode() { + $atts = array( + 'url' => 'https://www.documentcloud.org/documents/24475232-2024-03-08-rcfp-letter-to-nj-leg-re-sb-2930', + ); + + $result = $this->dc->process_dc_shortcode( $atts ); + + // Assert that no mode parameter is present. + $this->assertStringNotContainsString( 'mode=', $result, "No mode parameter should be present when not specified" ); + } } From 11a658b8de4e4eff0e57b53cbc51e36b0922b440 Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Thu, 18 Sep 2025 13:36:29 -0400 Subject: [PATCH 4/6] Apply automatic formatting --- src/documentcloud/blocks/.eslintrc.json | 20 +++++++++---------- .../blocks/__tests__/utils.test.js | 18 +++++++++++++++-- .../blocks/src/documentcloud/block.json | 4 ++-- .../blocks/src/documentcloud/edit.js | 11 +++++++--- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/documentcloud/blocks/.eslintrc.json b/src/documentcloud/blocks/.eslintrc.json index e4451cc..ae27986 100644 --- a/src/documentcloud/blocks/.eslintrc.json +++ b/src/documentcloud/blocks/.eslintrc.json @@ -1,19 +1,17 @@ { - "extends": [ - "plugin:@wordpress/eslint-plugin/recommended" -], + "extends": [ "plugin:@wordpress/eslint-plugin/recommended" ], "parserOptions": { - "ecmaVersion": 2021, + "ecmaVersion": 2021, "sourceType": "module", "ecmaFeatures": { - "jsx": true - } -}, + "jsx": true + } + }, "env": { - "browser": true, + "browser": true, "es6": true -}, + }, "rules": { - // Any custom rules you want to add or override -} + // Any custom rules you want to add or override + } } diff --git a/src/documentcloud/blocks/__tests__/utils.test.js b/src/documentcloud/blocks/__tests__/utils.test.js index 711e94e..9f3f97c 100644 --- a/src/documentcloud/blocks/__tests__/utils.test.js +++ b/src/documentcloud/blocks/__tests__/utils.test.js @@ -101,7 +101,14 @@ describe( 'DocumentCloud Utils', () => { it( 'should exclude invalid mode parameter from embed URL', () => { // Validates that invalid mode values are not included in the embed URL - const invalidModes = [ 'invalid', 'foo', 'bar', '', null, undefined ]; + const invalidModes = [ + 'invalid', + 'foo', + 'bar', + '', + null, + undefined, + ]; invalidModes.forEach( ( mode ) => { const params = { @@ -201,7 +208,14 @@ describe( 'DocumentCloud Utils', () => { it( 'should return null for invalid mode values', () => { // Tests that invalid mode values return null - const invalidModes = [ 'invalid', 'foo', 'bar', '', null, undefined ]; + const invalidModes = [ + 'invalid', + 'foo', + 'bar', + '', + null, + undefined, + ]; invalidModes.forEach( ( mode ) => { expect( validateMode( mode ) ).toBeNull(); } ); diff --git a/src/documentcloud/blocks/src/documentcloud/block.json b/src/documentcloud/blocks/src/documentcloud/block.json index 4920be5..c1981dd 100644 --- a/src/documentcloud/blocks/src/documentcloud/block.json +++ b/src/documentcloud/blocks/src/documentcloud/block.json @@ -12,11 +12,11 @@ "type": "string", "default": "" }, - "documentId" : { + "documentId": { "type": "string", "default": "" }, - "useDocumentId" : { + "useDocumentId": { "type": "boolean", "default": false }, diff --git a/src/documentcloud/blocks/src/documentcloud/edit.js b/src/documentcloud/blocks/src/documentcloud/edit.js index 4a7e960..8ed0096 100644 --- a/src/documentcloud/blocks/src/documentcloud/edit.js +++ b/src/documentcloud/blocks/src/documentcloud/edit.js @@ -499,11 +499,17 @@ export default function Edit( { attributes, setAttributes } ) { - ) } From 98aabbead73bb9f0a91d685a940de4d748eb13a4 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Mon, 22 Sep 2025 11:34:58 -0400 Subject: [PATCH 5/6] All oembeds go to the current API --- .gitignore | 1 + src/documentcloud/documentcloud.php | 26 ++++++++------------------ 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 4711d61..28df9b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .svn .DS_Store +node_modules # WordPress Dev Environment src/wordpress diff --git a/src/documentcloud/documentcloud.php b/src/documentcloud/documentcloud.php index aad3819..0b3bcd9 100644 --- a/src/documentcloud/documentcloud.php +++ b/src/documentcloud/documentcloud.php @@ -49,14 +49,11 @@ class WP_DocumentCloud { const CACHING_ENABLED = true, DEFAULT_EMBED_FULL_WIDTH = 940, OEMBED_RESOURCE_DOMAIN = 'www.documentcloud.org', - OEMBED_PROVIDER = 'https://www.documentcloud.org/api/oembed.{format}', + OEMBED_DOMAIN_MATCH = '#https?://(www\.)?(beta|embed).documentcloud.org/.*#i', + OEMBED_PROVIDER = 'https://api.www.documentcloud.org/api/oembed/', DOCUMENT_PATTERN = '^(?Phttps?):\/\/(?P.*documentcloud\.org)\/documents\/(?P[0-9]+-[\p{L}\p{N}%-]+)', CONTAINER_TEMPLATE_START = '
', - CONTAINER_TEMPLATE_END = '
', - BETA_ID_CUTOFF = 20000000, - BETA_OEMBED_RESOURCE_DOMAIN = 'beta.documentcloud.org', - BETA_OEMBED_DOMAIN_MATCH = '#https?://(www\.)?(beta|embed).documentcloud.org/.*#i', - BETA_OEMBED_PROVIDER = 'https://api.beta.documentcloud.org/api/oembed'; + CONTAINER_TEMPLATE_END = '
'; /** * Constructor. */ @@ -138,10 +135,10 @@ public function register_dc_oembed_provider() { wp_oembed_add_provider( 'http://' . $oembed_resource_domain . '/documents/*', $oembed_provider ); wp_oembed_add_provider( 'https://' . $oembed_resource_domain . '/documents/*', $oembed_provider ); - // Add oembed provider for the DocumentCloud beta. + // Add oembed matching for beta and embed subdomains. wp_oembed_add_provider( - self::BETA_OEMBED_DOMAIN_MATCH, - self::BETA_OEMBED_PROVIDER, + self::OEMBED_DOMAIN_MATCH, + $oembed_provider, true ); } @@ -319,15 +316,9 @@ public function process_dc_shortcode( $atts ) { if ( empty( $atts['url'] ) ) { if ( empty( $atts['id'] ) ) { return ''; - // Determine which URL on the basis of the DocumentCloud ID. - } elseif ( intval( $atts['id'] ) >= self::BETA_ID_CUTOFF ) { - // Populate beta URL. - // TODO: use only one URL after the switch. - $url = 'https://' . self::BETA_OEMBED_RESOURCE_DOMAIN . "/documents/{$atts['id']}.html"; - $filtered_atts['url'] = $url; } else { - // Populate legacy URL. - $url = 'https://' . self::OEMBED_RESOURCE_DOMAIN . "/documents/{$atts['id']}.html"; + // Populate a placeholder URL for oembed + $url = 'https://' . self::OEMBED_RESOURCE_DOMAIN . "/documents/{$atts['id']}.html"; $filtered_atts['url'] = $url; } } @@ -408,7 +399,6 @@ public function clean_dc_url( $url ) { } elseif ( isset( $elements['note_id'] ) ) { $url .= "/annotations/{$elements['note_id']}"; } - $url .= '.html'; } return $url; } From c894f0d81cf1fe6e3c0b142914238f0f0dbc4485 Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Tue, 23 Sep 2025 19:10:17 -0400 Subject: [PATCH 6/6] Fix MySQL test certificates (#13) We've had some certificate errors when testing. Since this is a temporary database that's thrown out after tests are over and contain no significant data, it's safe to use an unencrypted connection. This adds the `--skip-ssl` flag to all our test commands in CI. --- .github/workflows/unit_tests.yml | 4 ++-- bin/install-wp-tests.sh | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 0bbceec..d93455d 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -33,7 +33,7 @@ jobs: env: MYSQL_DATABASE: wordpress_test MYSQL_ROOT_PASSWORD: root - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v4 @@ -65,7 +65,7 @@ jobs: - name: Install WP test suite run: | - mysql -u root -proot -h mysql -P 3306 -e "DROP DATABASE IF EXISTS wordpress_test;" + mysql --skip-ssl -u root -proot -h mysql -P 3306 -e "DROP DATABASE IF EXISTS wordpress_test;" bash ./bin/install-wp-tests.sh wordpress_test root 'root' mysql ${{ matrix.wp-version }} - name: Run PHPUnit with coverage diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh index c6f53dc..374ca78 100755 --- a/bin/install-wp-tests.sh +++ b/bin/install-wp-tests.sh @@ -130,7 +130,7 @@ recreate_db() { shopt -s nocasematch if [[ $1 =~ ^(y|yes)$ ]] then - mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA + mysqladmin drop $DB_NAME -f --skip-ssl --user="$DB_USER" --password="$DB_PASS"$EXTRA create_db echo "Recreated the database ($DB_NAME)." else @@ -140,7 +140,7 @@ recreate_db() { } create_db() { - mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA + mysqladmin create $DB_NAME --skip-ssl --user="$DB_USER" --password="$DB_PASS"$EXTRA } install_db() { @@ -166,7 +166,7 @@ install_db() { fi # create database - if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ] + if [ $(mysql --skip-ssl --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ] then echo "Reinstalling will delete the existing test database ($DB_NAME)" read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB