Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions .eleventy.js
Original file line number Diff line number Diff line change
Expand Up @@ -656,26 +656,6 @@ module.exports = function(eleventyConfig) {
}
});

eleventyConfig.addShortcode("hubspotForm", function(formId, cta, reference, functionName = 'displayHubSpotForm') {
return `
<script>
function ${functionName}() {
hbspt.forms.create({
region: "eu1",
portalId: "26586079",
formId: "${formId}",
onFormSubmit: function ($form) {
capture('${cta}', {
'page': '${reference}'
})
}
});
}
</script>
<script async type="text/javascript" charset="utf-8" src="//js-eu1.hsforms.net/forms/embed/v2.js" onload="${functionName}()" onerror="hsFallback(this)"></script>
`;
});

eleventyConfig.addPairedShortcode("navoption", function(content, label, link, depth, icon, iconSolid, addClasses) {
let svg, iconSvg = '', classes, chevron
if (icon) {
Expand Down
98 changes: 91 additions & 7 deletions src/_includes/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,100 @@ document.createElement = function(...args) {

function hsFallback (element) {
if (element && element.parentNode) {
const existingFallback = element.parentNode.querySelector('.ff-hubspot-consent-fallback')
if (existingFallback) {
existingFallback.classList.remove('hidden')
return
}

const errorSection = document.createElement('section');
errorSection.classList.add('text-center', 'border', 'border-indigo-300', 'rounded-lg', 'bg-white', 'px-4');
errorSection.classList.add('ff-hubspot-consent-fallback');
errorSection.innerHTML = `
<p style="color: #6366f1;"><strong>Hmm… there was supposed to be a form here.</strong></p>
<p>
It might be blocked by your browser or privacy settings. Try
<button onclick="if(window.CookieConsent){CookieConsent.showPreferences()}" style="background:none;border:none;color:#6366f1;cursor:pointer;padding:0;font-size:inherit;text-decoration:underline;">updating your cookie preferences</button>,
adjusting your privacy settings, or switching browsers to continue.
</p>
<p><strong>Unable to load HubSpot content.</strong></p>
`;
element.parentNode.insertBefore(errorSection, element.nextSibling);
}
}

function loadHubSpotFormsScript () {
if (window.hbspt?.forms?.create) {
return Promise.resolve(window.hbspt)
}

if (window._ffHubSpotFormsPromise) {
return window._ffHubSpotFormsPromise
}

window._ffHubSpotFormsPromise = new Promise((resolve, reject) => {
const existing = document.getElementById('ff-hs-forms-script')

if (existing) {
existing.addEventListener('load', () => resolve(window.hbspt), { once: true })
existing.addEventListener('error', () => reject(new Error('HubSpot forms script failed to load')), { once: true })
return
}

const script = document.createElement('script')
script.id = 'ff-hs-forms-script'
script.async = true
script.charset = 'utf-8'
script.src = 'https://js-eu1.hsforms.net/forms/embed/v2.js'
script.onload = () => resolve(window.hbspt)
script.onerror = () => reject(new Error('HubSpot forms script failed to load'))
document.head.appendChild(script)
}).catch((err) => {
window._ffHubSpotFormsPromise = null
throw err
})

return window._ffHubSpotFormsPromise
}

function ffCreateHubSpotForm (config) {
if (!config || !config.formId) {
return
}

const targetElement = config.target ? document.querySelector(config.target) : null
const fallbackElement = config.fallbackSelector ? document.querySelector(config.fallbackSelector) : null
if (config.target && !targetElement) {
return
}

if (targetElement?.dataset.ffHsFormLoaded === 'true') {
return
}

if (targetElement && targetElement.querySelector('iframe, form, .hbspt-form')) {
targetElement.dataset.ffHsFormLoaded = 'true'
return
}

loadHubSpotFormsScript().then(() => {
if (!window.hbspt?.forms?.create) {
if (fallbackElement) {
fallbackElement.classList.remove('hidden')
} else if (targetElement) {
hsFallback(targetElement)
}
return
}
// Keep local helper-only keys out of HubSpot's context object.
const { fallbackSelector, ...hubspotConfig } = config
window.hbspt.forms.create(hubspotConfig)
if (targetElement) {
targetElement.dataset.ffHsFormLoaded = 'true'
}
if (fallbackElement) {
fallbackElement.classList.add('hidden')
}
}).catch(() => {
if (fallbackElement) {
fallbackElement.classList.remove('hidden')
} else if (targetElement) {
hsFallback(targetElement)
}
})
}

window.ffCreateHubSpotForm = ffCreateHubSpotForm
8 changes: 6 additions & 2 deletions src/_includes/blog/blog-posts.njk
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
<div class="w-full px-2 pt-2 pb-2 mb-2 flex flex-col border-t-2 border-b-2">
<a id="sign-up"></a>
<h5 class="mb-0">Sign up for our monthly email updates:</h5>
{% include "hubspot/hs-newsletter.njk" %}
{% set formId = "159c173d-dd95-49bd-922b-ff3ef243e90c" %}
{% set cta = "cta-blog-subscribe" %}
{% set reference = "blog" %}
{% set targetId = "hs-form-newsletter-blog" %}
{% include "hubspot/hs-form.njk" %}
</div>
{% else %}
<li class="w-full md:w-1/3 my-2 px-2 pb-6 border-b">
Expand All @@ -58,4 +62,4 @@
</div>
</a>
</li>
{% endif %}
{% endif %}
24 changes: 24 additions & 0 deletions src/_includes/hubspot/consent-fallback.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div id="{{ fallbackId }}" class="ff-hubspot-consent-fallback text-center border bg-red-50/25 border-red-300 rounded-lg px-4 py-6">
<p class="text-red-400"><strong>Hmm… there was supposed to be a {{ contentType }} here</strong></p>
{% if contentType == 'form' %}
<p class="text-gray-600">
If this form does not load, try adjusting your privacy settings or switching browsers.
</p>
{% else %}
<p class="text-gray-600">
To load this {{ contentType }}, please accept <strong>Analytics cookies</strong>.
If that doesn't work, try adjusting your privacy settings, or switching browsers.
</p>
<p class="mt-4">
<button
onclick="if(window.CookieConsent){CookieConsent.showPreferences()}"
class="inline-block ff-btn ff-btn--primary-outlined uppercase"
>
Open cookie settings
</button>
</p>
<p class="mt-2 text-gray-600">
Alternatively, you can send us a message through our <a href="/contact-us/">contact form</a>.
</p>
{% endif %}
</div>
20 changes: 5 additions & 15 deletions src/_includes/hubspot/hs-book-meeting.njk
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
<div id="meetings-consent-placeholder" class="text-center border border-indigo-300 rounded-lg bg-white px-4 py-10">
<p style="color: #6366f1;"><strong>Enable cookies to book a meeting</strong></p>
<p class="text-gray-600">To load the booking calendar, please accept <strong>Analytics cookies</strong>.</p>
<p class="mt-4">
<button
onclick="CookieConsent.showPreferences()"
class="inline-block px-4 py-2 rounded-lg border border-indigo-400 text-indigo-600 hover:bg-indigo-50 transition-colors cursor-pointer bg-transparent text-sm font-medium"
>
Open cookie settings
</button>
</p>
</div>
{% set fallbackId = 'meetings-consent-placeholder' %}
{% set contentType = 'meeting calendar' %}
{% include "hubspot/consent-fallback.njk" %}
<script>
window._ffLoadMeetings = function () {
var placeholder = document.getElementById('meetings-consent-placeholder');
Expand All @@ -24,10 +15,9 @@

var script = document.createElement('script');
script.src = 'https://static.hsappstatic.net/MeetingsEmbed/ex/MeetingsEmbedCode.js';
script.onerror = function () { hsFallback(script); };
script.onload = function () { placeholder.remove(); };
script.onerror = function () { hsFallback(placeholder); };
parent.insertBefore(script, placeholder);

placeholder.remove();
window._ffLoadMeetings = null;
};
</script>
42 changes: 29 additions & 13 deletions src/_includes/hubspot/hs-form.njk
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
{% set hubspotData = hubspot or {} %}
{% set hubspotFormId = formId or hubspotData.formId %}
{% set formTargetId = targetId or ('hs-form-' + (hubspotFormId | replace('-', ''))) %}
{% set fallbackId = formTargetId + '-fallback' %}
{% set contentType = 'form' %}
{% set hubspotRegion = region or hubspotData.region or 'eu1' %}
{% set hubspotPortalId = portalId or hubspotData.portalId or '26586079' %}
{% set onFormSubmittedHandler = onFormSubmitted or hubspotData.onFormSubmitted %}
{% set ctaValue = cta or hubspotData.cta %}
{% set referenceValue = hubspotData.reference or title %}

<div id="{{ formTargetId }}"></div>
{% include "hubspot/consent-fallback.njk" %}
<script>
function displayHubSpotForm() {
hbspt.forms.create({
region: "eu1",
portalId: "26586079",
formId: "{{ formId or hubspot.formId }}",
onFormSubmit: function ($form) {
capture('{{ cta or hubspot.cta }}', {
'page': '{{ hubspot.reference or title }}'
})
}
});
}
window.ffCreateHubSpotForm({
target: '#{{ formTargetId }}',
fallbackSelector: '#{{ fallbackId }}',
region: "{{ hubspotRegion }}",
portalId: "{{ hubspotPortalId }}",
formId: "{{ hubspotFormId }}",
{% if onFormSubmittedHandler %}
onFormSubmitted: {{ onFormSubmittedHandler | safe }},
{% elif ctaValue %}
onFormSubmit: function () {
capture('{{ ctaValue }}', {
'page': '{{ referenceValue }}'
});
},
{% endif %}
});
</script>
<script async type="text/javascript" charset="utf-8" src="//js-eu1.hsforms.net/forms/embed/v2.js" onload="displayHubSpotForm()" onerror="hsFallback(this);"></script>
13 changes: 0 additions & 13 deletions src/_includes/hubspot/hs-newsletter.njk

This file was deleted.

19 changes: 5 additions & 14 deletions src/_includes/migration.njk
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
</div>
<a id="dashboard-2-download" style="display:none"></a>
</div>
<div id="hs-user-form">

<div>
{% set formId = "968a9ab6-3dd8-45b2-991c-3f055dc18787" %}
{% set targetId = "hs-user-form" %}
{% set onFormSubmitted = "function () { migrateFile(); }" %}
{% include "hubspot/hs-form.njk" %}
</div>
</div>
</div>
Expand Down Expand Up @@ -113,16 +116,4 @@
event.preventDefault();
}

function displayHubSpotForm() {
hbspt.forms.create({
target: '#hs-user-form',
region: "eu1",
portalId: "26586079",
formId:"968a9ab6-3dd8-45b2-991c-3f055dc18787",
onFormSubmitted: function ($form) {
migrateFile()
}
});
}
</script>
<script async type="text/javascript" charset="utf-8" src="//js-eu1.hsforms.net/forms/embed/v2.js" onload="displayHubSpotForm()" onerror="hsFallback(this)"></script>
17 changes: 9 additions & 8 deletions src/blog/2025/07/certified-nodes-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
title: "Curated Node-RED Integrations: FlowFuse Certified Nodes 2.0"
subtitle: "FlowFuse Unveils Certified Nodes Program to Reward Quality and Ensure Long-Term Support"
description: "FlowFuse announces Certified Nodes v2.0 - connecting enterprises with the highest quality Node-RED nodes, built and maintained by recognized experts in their fields."
templateEngineOverride: njk,md
date: 2025-07-01
authors: ["zeger-jan-van-de-weg"]
image: blog/2025/07/images/certified-nodes-v2.png
certificationHubspot:
formId: "6e02fe34-13c3-442b-8c27-9a12e72bba37"
targetId: "hs-form-certified-nodes-contact"
tags:
- flowfuse
- node-red
Expand Down Expand Up @@ -81,11 +85,8 @@ industry's leading experts.

### Contact us to discuss your node certification

<script charset="utf-8" type="text/javascript" src="//js-eu1.hsforms.net/forms/embed/v2.js"></script>
<script>
hbspt.forms.create({
portalId: "26586079",
formId: "6e02fe34-13c3-442b-8c27-9a12e72bba37",
region: "eu1"
});
</script>
{% set formId = certificationHubspot.formId %}
{% set targetId = certificationHubspot.targetId %}
{% set cta = "cta-certified-nodes-contact" %}
{% set reference = "certified-nodes-v2" %}
{% include "hubspot/hs-form.njk" %}
6 changes: 3 additions & 3 deletions src/js/cookieconsent-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ CookieConsent.run({
en: {
consentModal: {
title: "This site uses cookies",
description: "We use cookies to ensure this site works properly and, with your permission, to improve your experience and enable features like analytics and live chat support.",
description: "We use cookies to ensure this site works properly, forms render properly, and, with your permission, to improve your experience and enable features like analytics and <span class=\"font-medium text-indigo-600\">live chat support</span>.",
acceptAllBtn: "Accept all",
showPreferencesBtn: "Settings",
footer: "<a href=\"/privacy-policy/\">Privacy Policy</a>\n"
Expand All @@ -238,7 +238,7 @@ CookieConsent.run({
},
{
title: "Strictly Necessary Cookies <span class=\"pm__badge\">Always Enabled</span>",
description: "Essential cookies are crucial for the basic functionality of our website. Without these cookies, our website could not function properly.",
description: "Essential cookies are crucial for core website functionality, including security, anti-spam protection (Google reCAPTCHA), and technical form delivery. Without these cookies, key features of the website, such as secure contact forms, could not function properly.",
linkedCategory: "necessary"
},
{
Expand All @@ -248,7 +248,7 @@ CookieConsent.run({
},
{
title: "Analytics Cookies",
description: "We use tools including Google Analytics, HubSpot, PostHog, and warmly.ai to understand how visitors interact with our website. This category also enables HubSpot meeting embeds and the chat widget.",
description: "We use tools including Google Analytics, HubSpot tracking, PostHog, and warmly.ai to understand how visitors interact with our website. This category enables HubSpot tracking, meeting embeds, and the chat widget.",
linkedCategory: "analytics"
},
{
Expand Down
16 changes: 14 additions & 2 deletions src/pricing/index.njk
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,13 @@ hubspot:
To learn more about our plans, discuss your specific needs, or get advice on the best fit for your project, please fill out the form and we will get back to you as soon as possible.
</p>
</div>
{% hubspotForm hubspot.cloud.formId, hubspot.cloud.cta, hubspot.reference, 'contactUsForm' %}
<div>
{% set formId = hubspot.cloud.formId %}
{% set cta = hubspot.cloud.cta %}
{% set reference = hubspot.reference %}
{% set targetId = 'hs-form-pricing-cloud-contact-us' %}
{% include "hubspot/hs-form.njk" %}
</div>
</div>
</div>
</div>
Expand All @@ -320,7 +326,13 @@ hubspot:
Unlock the complete potential of FlowFuse with a complimentary 30-day Enterprise license. This trial gives you the chance to explore all the features and functionalities of FlowFuse in your own environment. To start your trial, simply fill out the form. Our sales team will reach out to you to discuss your needs and provide the license.
</p>
</div>
{% hubspotForm hubspot.selfHosted.formId, hubspot.selfHosted.cta, hubspot.reference, 'trialLicenseForm' %}
<div>
{% set formId = hubspot.selfHosted.formId %}
{% set cta = hubspot.selfHosted.cta %}
{% set reference = hubspot.reference %}
{% set targetId = 'hs-form-pricing-self-hosted-trial-license' %}
{% include "hubspot/hs-form.njk" %}
</div>
</div>
</div>
</div>
Expand Down