Repository: Plant-for-the-Planet-org/planet-widgets
Pull request #126: generate iframe code
Author: login: norbertschuler
Created: 2025-04-15T16:29:22Z | Merged: 2025-04-25T07:21:14Z

Fixes #

Changes in this pull request:
- added generation of iframe code

@


Diff:
diff --git a/public/iframe.html b/public/iframe.html
index 561a4be..43c26f9 100644
--- a/public/iframe.html
+++ b/public/iframe.html
@@ -51,13 +51,12 @@
           //Convert the array of entries into an object
           // e.g., { type: "tree-map", user: "John-doe", ... }
           const paramObject = Object.fromEntries(entries);
-
           const widgetType = paramObject.type;
           const user = paramObject.user;
           const tenantKey = paramObject.tenantKey || "ten_NxJq55pm"; // Use default tenant if none provided
           const theme = paramObject.theme || "default";
-          const primarycolor = paramObject.primarycolor || "#68b030";
-          const circlebgcolor = paramObject.circlebgcolor || "";
+          let primarycolor = paramObject.primarycolor || "#68b030";
+          let circlebgcolor = paramObject.circlebgcolor || "";
           const community = paramObject.community || "true";
           const locale = paramObject.locale || "en";
           const refresh = paramObject.refresh || "none";
@@ -78,6 +77,14 @@
             );
             return;
           }
+
+          if (primarycolor && !primarycolor.includes("#")) {
+            primarycolor = `#${primarycolor}`;
+          }
+          if (circlebgcolor && !circlebgcolor.includes("#")) {
+            circlebgcolor = `#${circlebgcolor}`;
+          }
+
           // Create the widget element first
           const widget = document.createElement(widgetType);
           const attributes = {
diff --git a/public/index.html b/public/index.html
index a6fce3a..b6f85bc 100644
--- a/public/index.html
+++ b/public/index.html
@@ -521,9 +521,17 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 					<button
 						id="treeMapCopyButton"
 						class="copyCodeButton"
-						onClick="copyToClipboard('treeMap'); return false"
+						onClick="copyToClipboard('treeMap', false); return false"
 					>
-						Copy Code
+						Copy code
+					</button>
+					<div id="treeMapIframe" class="code-container"></div>
+					<button
+						id="treeMapIframeButton"
+						class="copyCodeButton"
+						onClick="copyToClipboard('treeMap', true); return false"
+					>
+						Copy iframe link
 					</button>
 				</div>
 				<div id="treeProfileWidget">
@@ -540,9 +548,17 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 					<button
 						id="treeProfileCopyButton"
 						class="copyCodeButton"
-						onClick="copyToClipboard('treeProfile'); return false"
+						onClick="copyToClipboard('treeProfile', false); return false"
 					>
-						Copy Code
+						Copy code
+					</button>
+					<div id="treeProfileIframe" class="code-container"></div>
+					<button
+						id="treeProfileIframeButton"
+						class="copyCodeButton"
+						onClick="copyToClipboard('treeProfile', true); return false"
+					>
+						Copy iframe link
 					</button>
 				</div>
 				<div id="treeTenantCounterWidget">
@@ -560,7 +576,7 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 						class="copyCodeButton"
 						onClick="copyToClipboard('treeTenantCounter'); return false"
 					>
-						Copy Code
+						Copy code
 					</button>
 				</div>
 				<div id="treeTenantLeaderboardWidget">
@@ -577,7 +593,7 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 						class="copyCodeButton"
 						onClick="copyToClipboard('treeTenantLeaderboard'); return false"
 					>
-						Copy Code
+						Copy code
 					</button>
 				</div>
 			</div>
@@ -644,6 +660,7 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 
 			function updateCode(id) {
 				var widgetCode = document.getElementById(id + 'Code');
+				var widgetIframe = document.getElementById(id + 'Iframe');
 				var widgetNode = document.getElementById(id + 'Script');
 				widgetNode.src =
 					`${window.location.origin}/build/` + widgetNode.src.split('/')[4];
@@ -655,16 +672,61 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 					'</br>' +
 					document.getElementById(id).outerHTML.replace(/</g, '&lt;') +
 					'</code>';
+				if (widgetIframe) {
+					let circlebgcolor = "";
+          			let primarycolor = "";
+          				if (document.getElementById(id).circlebgcolor) {
+            				circlebgcolor = document.getElementById(id).circlebgcolor.replace("#", "");
+         				 }
+          				if (document.getElementById(id).primarycolor) {
+           					primarycolor = document.getElementById(id).primarycolor.replace("#", "");
+						}
+					let queryParams = [];
+					queryParams.push(`type=${document.getElementById(id).nodeName.toLowerCase()}`)
+					if(document.getElementById(id).user){
+						queryParams.push(`user=${document.getElementById(id).user}`)
+					}
+
+					if(document.getElementById(id).tenantkey){
+						queryParams.push(`tenantkey=${document.getElementById(id).tenantkey}`)
+					}
+					if(document.getElementById(id).theme){
+						queryParams.push(`theme=${document.getElementById(id).theme}`)
+					}
+					if(primarycolor){
+						queryParams.push(`primarycolor=${primarycolor}`)
+					}
+					if(circlebgcolor){
+						queryParams.push(`circlebgcolor=${circlebgcolor}`)
+					}
+					if(document.getElementById(id).community){
+						queryParams.push(`community=${document.getElementById(id).community}`)
+					}
+					if(document.getElementById(id).locale){
+						queryParams.push(`locale=${document.getElementById(id).locale}`)
+					}
+					if(document.getElementById(id).forestname){
+						queryParams.push(`forestname=${document.getElementById(id).forestname}`)
+					}
+					if(document.getElementById(id).project){
+						queryParams.push(`project=${document.getElementById(id).project}`)
+					}
+    
+					widgetIframe.innerHTML =
+					'<code>' +
+					encodeURI(window.location.origin + '/iframe.html?' + queryParams.join("&")).replace(/#/g, '%23') +
+					'</code>';
+				}
 			}
 
-			function copyToClipboard(id) {
+			function copyToClipboard(id, copyIframe) {
 				window.getSelection().removeAllRanges();
 				let range = document.createRange();
-				range.selectNode(document.getElementById(id + 'Code'));
+				range.selectNode(document.getElementById(id + (copyIframe?'Iframe':'Code')));
 				window.getSelection().addRange(range);
 				document.execCommand('copy');
 				window.getSelection().removeAllRanges();
-				let button = document.getElementById(id + 'CopyButton');
+				let button = document.getElementById(id + (copyIframe? 'IframeButton':'CopyButton'));
 				const buttonText = button.innerHTML;
 				button.innerHTML = 'Copied!';
 				setTimeout(function () {


Reviews:
user: login: sunilsabatp
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T10:01:34Z
user: login: mariahosfeld
body: Only the part after src is needed for this part.
Button should be relabeled with iframe-link (or something along these lines).
Also leave out following params (no option to set them via interface):

- [ ] refresh
- [ ] goal

state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T08:20:16Z
user: login: mariahosfeld
body: Looks good to me.
One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T06:57:11Z
user: login: mohitb35
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T11:40:38Z
user: login: mohitb35
body: @sunilsabatp @mariahosfeld I think this looks good.

Have left one minor comment, once that's taken care of this can go out.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-24T11:41:48Z
user: login: sunilsabatp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T12:22:34Z
user: login: mohitb35
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-24T12:32:45Z
user: login: mariahosfeld
body: The circlebgcolor parameter is not yet working correctly, same behavior as for primarycolor needs to be applied.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T13:40:47Z
user: login: norbertschuler
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-24T17:16:54Z
user: login: sunilsabatp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T02:59:06Z
user: login: mariahosfeld
body: LGTM!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T07:20:45Z

Review comments:
diff_hunk: @@ -655,16 +672,43 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 					'</br>' +
 					document.getElementById(id).outerHTML.replace(/</g, '&lt;') +
 					'</code>';
+				if (widgetIframe) {
+					let circlebgcolor = "";
+          			let primarycolor = "";
+          				if (document.getElementById(id).circlebgcolor) {
+            				circlebgcolor = document.getElementById(id).circlebgcolor.replace("#", "");
+         				 }
+          				if (document.getElementById(id).primarycolor) {
+           					primarycolor = document.getElementById(id).primarycolor.replace("#", "");
+    }
+					widgetIframe.innerHTML =
+					'<code>' +
+					encodeURI(window.location.origin + '/iframe' +
+					'?type=' + document.getElementById(id).nodeName.toLowerCase() +
+					'&user=' + document.getElementById(id).user +
+					'&tenantkey=' + document.getElementById(id).tenantkey +
+					'&theme=' + document.getElementById(id).theme +
+					'&primarycolor=' + primarycolor +
+					'&circlebgcolor=' + circlebgcolor +
+					'&community=' + document.getElementById(id).community +
+					'&locale=' + document.getElementById(id).locale +
+					//'&refresh=' + document.getElementById(id).refresh +
+					'&forestname=' + (document.getElementById(id).forestname || '') +
+					'&project=' + (document.getElementById(id).project || '') // +
+					//'&goal=' + (document.getElementById(id).goal || '')
+					).replace(/#/g, '%23') +
+					'</code>';
path: public/index.html
user: login: mohitb35
body: Looks mostly fine. It would be good to avoid keeping empty query parameters in the url though. Can that be done?
created_at: 2025-04-24T11:40:37Z
author_association: MEMBER
diff_hunk: @@ -655,16 +672,43 @@ <h5 class="widgetSubTitle" style="margin-bottom: 20px">
 					'</br>' +
 					document.getElementById(id).outerHTML.replace(/</g, '&lt;') +
 					'</code>';
+				if (widgetIframe) {
+					let circlebgcolor = "";
+          			let primarycolor = "";
+          				if (document.getElementById(id).circlebgcolor) {
+            				circlebgcolor = document.getElementById(id).circlebgcolor.replace("#", "");
+         				 }
+          				if (document.getElementById(id).primarycolor) {
+           					primarycolor = document.getElementById(id).primarycolor.replace("#", "");
+    }
+					widgetIframe.innerHTML =
+					'<code>' +
+					encodeURI(window.location.origin + '/iframe' +
+					'?type=' + document.getElementById(id).nodeName.toLowerCase() +
+					'&user=' + document.getElementById(id).user +
+					'&tenantkey=' + document.getElementById(id).tenantkey +
+					'&theme=' + document.getElementById(id).theme +
+					'&primarycolor=' + primarycolor +
+					'&circlebgcolor=' + circlebgcolor +
+					'&community=' + document.getElementById(id).community +
+					'&locale=' + document.getElementById(id).locale +
+					//'&refresh=' + document.getElementById(id).refresh +
+					'&forestname=' + (document.getElementById(id).forestname || '') +
+					'&project=' + (document.getElementById(id).project || '') // +
+					//'&goal=' + (document.getElementById(id).goal || '')
+					).replace(/#/g, '%23') +
+					'</code>';
path: public/index.html
user: login: sunilsabatp
body: https://github.com/Plant-for-the-Planet-org/planet-widgets/pull/126/commits/093cfad8f61abb23342eafcbf87b8fa21949f8d8
created_at: 2025-04-24T12:22:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,6 +77,14 @@
             );
             return;
           }
+
+          if (primarycolor && !primarycolor.includes("#")) {
+            primarycolor = `#${primarycolor}`;
+          }
+          if (circlebgcolor && !primarycolor.includes("#")) {
path: public/iframe.html
user: login: norbertschuler
body: `primarycolor` is wrong here. 
created_at: 2025-04-24T17:13:44Z
author_association: COLLABORATOR
diff_hunk: @@ -78,6 +77,14 @@
             );
             return;
           }
+
+          if (primarycolor && !primarycolor.includes("#")) {
+            primarycolor = `#${primarycolor}`;
+          }
+          if (circlebgcolor && !primarycolor.includes("#")) {
path: public/iframe.html
user: login: sunilsabatp
body: Thanks for pointing it out.
created_at: 2025-04-25T02:59:06Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-04-15T16:29:27Z
body: [vc]: #0f9A1d5G25nU6AUp3yX+dMt2ph/8jfePudt/CTXQCgo=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJwbGFuZXQtd2lkZ2V0cyIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJwbGFuZXQtd2lkZ2V0cy1naXQtZ2VuZXJhdGUtaWZyYW1lLWNvZGUtcGxhbmV0YXBwLnZlcmNlbC5hcHAifSwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3BsYW5ldGFwcC9wbGFuZXQtd2lkZ2V0cy9Da1J0TG5yVXViUkRjaVlwVTdiQ0paOE5BRktaIiwicHJldmlld1VybCI6InBsYW5ldC13aWRnZXRzLWdpdC1nZW5lcmF0ZS1pZnJhbWUtY29kZS1wbGFuZXRhcHAudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsInJvb3REaXJlY3RvcnkiOm51bGx9XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **planet-widgets** | ✅ Ready ([Inspect](https://vercel.com/planetapp/planet-widgets/CkRtLnrUubRDciYpU7bCJZ8NAFKZ)) | [Visit Preview](https://planet-widgets-git-generate-iframe-code-planetapp.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/planet-widgets-git-generate-iframe-code-planetapp.vercel.app?via=pr-comment-feedback-link) | Apr 25, 2025 3:12am |


author_association: NONE
user: login: cloudflare-workers-and-pages[bot]
created_at: 2025-04-15T16:42:09Z
body: ## Deploying planet-widgets with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>17637a2</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>&nbsp;✅&nbsp; Deploy successful!</td></tr>
<tr><td><strong>Preview URL:</strong></td><td>
<a href='https://e5f96e75.planet-widgets.pages.dev'>https://e5f96e75.planet-widgets.pages.dev</a>
</td></tr>
<tr><td><strong>Branch Preview URL:</strong></td><td>
<a href='https://generate-iframe-code.planet-widgets.pages.dev'>https://generate-iframe-code.planet-widgets.pages.dev</a>
</td></tr>
</table>

[View logs](https://dash.cloudflare.com/55ec0970cd4f05ba1dd3ba55cbc93224/pages/view/planet-widgets/e5f96e75-54ce-468b-b614-61ced54b8185)

author_association: NONE
user: login: norbertschuler
created_at: 2025-04-23T08:49:44Z
body: > Looks good to me. One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler

I do not know why the url is redirected from `iframe.html` to `iframe` (locally it does not happen). As it work well without `.html` I removed it now.
author_association: COLLABORATOR
user: login: norbertschuler
created_at: 2025-04-23T08:54:14Z
body: > > Looks good to me. One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler
> 
> I do not know why the url is redirected from `iframe.html` to `iframe` (locally it does not happen). As it work well without `.html` I removed it now.

For some reason the new deployment does not work with `iframe` now in the way I see the widget builder form page again instead of the iframe using https://planet-widgets-fusequpn2-planetapp.vercel.app/iframe?type=tree-map&user=sagar-aryal&tenantkey=ten_NxJq55pm&theme=forest&primarycolor=%2368b030&circlebgcolor=&community=true&locale=en&forestname=&project= - is this only me or others as well?
author_association: COLLABORATOR
user: login: sunilsabatp
created_at: 2025-04-24T05:05:08Z
body: > > > Looks good to me. One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler
> > 
> > 
> > I do not know why the url is redirected from `iframe.html` to `iframe` (locally it does not happen). As it work well without `.html` I removed it now.
> 
> For some reason the new deployment does not work with `iframe` now in the way I see the widget builder form page again instead of the iframe using https://planet-widgets-fusequpn2-planetapp.vercel.app/iframe?type=tree-map&user=sagar-aryal&tenantkey=ten_NxJq55pm&theme=forest&primarycolor=%2368b030&circlebgcolor=&community=true&locale=en&forestname=&project= - is this only me or others as well?

I'm also experiencing the same issue. might be On Vercel, if  we are deploying a static site, Vercel will only serve files that exist explicitly, like /iframe.html, and will not automatically resolve` /iframe `to` /iframe.html.`
author_association: CONTRIBUTOR
user: login: norbertschuler
created_at: 2025-04-24T06:43:13Z
body: @sunilsabatp as after your commit d22080dbcbee62137bfc318074fb597697d08714 one cannot see the real changes in `index.html` any more, I won't check this pull request any longer and hand it over to you.
author_association: COLLABORATOR
user: login: norbertschuler
created_at: 2025-04-24T17:16:06Z
body: > > > > Looks good to me. One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler
> 
> > > 
> 
> > > 
> 
> > > I do not know why the url is redirected from `iframe.html` to `iframe` (locally it does not happen). As it work well without `.html` I removed it now.
> 
> > 
> 
> > For some reason the new deployment does not work with `iframe` now in the way I see the widget builder form page again instead of the iframe using https://planet-widgets-fusequpn2-planetapp.vercel.app/iframe?type=tree-map&user=sagar-aryal&tenantkey=ten_NxJq55pm&theme=forest&primarycolor=%2368b030&circlebgcolor=&community=true&locale=en&forestname=&project= - is this only me or others as well?
> 
> 
> 
> I'm also experiencing the same issue. might be On Vercel, if  we are deploying a static site, Vercel will only serve files that exist explicitly, like /iframe.html, and will not automatically resolve` /iframe `to` /iframe.html.`

So should this be reverted again to adding `.html`?
author_association: COLLABORATOR
user: login: sunilsabatp
created_at: 2025-04-25T03:05:41Z
body: > > > > > Looks good to me. One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler
> > 
> > 
> > > >
> > 
> > 
> > > >
> > 
> > 
> > > > I do not know why the url is redirected from `iframe.html` to `iframe` (locally it does not happen). As it work well without `.html` I removed it now.
> > 
> > 
> > > 
> > 
> > 
> > > For some reason the new deployment does not work with `iframe` now in the way I see the widget builder form page again instead of the iframe using https://planet-widgets-fusequpn2-planetapp.vercel.app/iframe?type=tree-map&user=sagar-aryal&tenantkey=ten_NxJq55pm&theme=forest&primarycolor=%2368b030&circlebgcolor=&community=true&locale=en&forestname=&project= - is this only me or others as well?
> > 
> > 
> > I'm also experiencing the same issue. might be On Vercel, if  we are deploying a static site, Vercel will only serve files that exist explicitly, like /iframe.html, and will not automatically resolve`/iframe`to` /iframe.html.`
> 
> So should this be reverted again to adding `.html`?



> > > > > Looks good to me. One question though: When I copy and open the link for the iframe, the ".html" part is automatically removed. Would it be better if we already exclude it in the link, to avoid any potential issues when included in a bigger context? @norbertschuler
> > 
> > 
> > > >
> > 
> > 
> > > >
> > 
> > 
> > > > I do not know why the url is redirected from `iframe.html` to `iframe` (locally it does not happen). As it work well without `.html` I removed it now.
> > 
> > 
> > > 
> > 
> > 
> > > For some reason the new deployment does not work with `iframe` now in the way I see the widget builder form page again instead of the iframe using https://planet-widgets-fusequpn2-planetapp.vercel.app/iframe?type=tree-map&user=sagar-aryal&tenantkey=ten_NxJq55pm&theme=forest&primarycolor=%2368b030&circlebgcolor=&community=true&locale=en&forestname=&project= - is this only me or others as well?
> > 
> > 
> > I'm also experiencing the same issue. might be On Vercel, if  we are deploying a static site, Vercel will only serve files that exist explicitly, like /iframe.html, and will not automatically resolve`/iframe`to` /iframe.html.`
> 
> So should this be reverted again to adding `.html`?

Yes, I've reverted back to .html.
author_association: CONTRIBUTOR