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/.gitignore b/.gitignore
index 291381c..28df9b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
.svn
.DS_Store
+node_modules
# WordPress Dev Environment
src/wordpress
@@ -9,4 +10,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..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.
@@ -55,10 +61,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.
@@ -67,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 :
@@ -153,7 +158,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
@@ -171,6 +176,12 @@ 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.
+* 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.
* Update the shortcode to support the following attributes
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
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/__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 (
+
{ 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 eef784e..9f3f97c 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', () => {
@@ -59,10 +60,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,12 +77,63 @@ 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'
);
} );
+
+ 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 +195,30 @@ 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..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
},
@@ -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 441d423..8ed0096 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;
@@ -272,15 +274,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,
@@ -289,9 +286,9 @@ export default function Edit( { attributes, setAttributes } ) {
fullscreen,
onlyshoworg,
pdf,
+ mode,
width: tempDimensions.width,
height: tempDimensions.height,
- responsive,
} );
}, [
useDocumentId,
@@ -301,6 +298,7 @@ export default function Edit( { attributes, setAttributes } ) {
fullscreen,
onlyshoworg,
pdf,
+ mode,
tempDimensions,
] );
@@ -496,6 +494,47 @@ 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 */ }
{
if ( ! ( useDocumentId ? documentId : url ) ) {
return '';
@@ -113,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,9 +140,13 @@ export const getEmbedUrl = ( {
onlyshoworg: onlyshoworg ? 1 : 0,
pdf: pdf ? 1 : 0,
style: style || '',
- responsive: responsive ? 1 : 0,
};
+ // 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 2cfa1c4..0b3bcd9 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
@@ -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
);
}
@@ -177,18 +174,17 @@ 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,
'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
@@ -205,6 +201,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.
*
@@ -236,14 +248,20 @@ 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 );
+ // 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 );
@@ -298,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;
}
}
@@ -319,15 +331,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'] ) {
@@ -396,7 +399,6 @@ public function clean_dc_url( $url ) {
} elseif ( isset( $elements['note_id'] ) ) {
$url .= "/annotations/{$elements['note_id']}";
}
- $url .= '.html';
}
return $url;
}
@@ -414,14 +416,10 @@ public function add_options_page() {
* Render the DocumentCloud options page.
*/
public function render_options_page() {
- // TODO: remove the responsive warning after the switch.
?>