Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,16 @@
var PageMgr = require('dw/experience/PageMgr');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter please move all require statements to local scope

var HashMap = require('dw/util/HashMap');
var cloudinaryApi = require('*/cartridge/scripts/cloudinary/cloudinaryApi');
var URLUtils = require('dw/web/URLUtils');
var URLAction = require('dw/web/URLAction');
var CSRF = require('dw/web/CSRFProtection');

module.exports.init = function (editor) {
var conf = new HashMap();
var csrf = new HashMap();
csrf.put(CSRF.getTokenName(), CSRF.generateToken());
var linkUrlAct = URLUtils.abs('Links-url').toString();
editor.configuration.put('linkBuilderUrl', linkUrlAct);
editor.configuration.put('csrf', csrf);
conf.put('type', 'image');
editor.configuration.put('cloudName', cloudinaryApi.data.getCloudName());
editor.configuration.put('cname', cloudinaryApi.data.getCloudinaryCNAME());
editor.configuration.put('globalTrans', cloudinaryApi.globalTransform());
editor.configuration.put('iFrameEnv', cloudinaryApi.data.getIframeEnv());
var videoSelector = PageMgr.getCustomEditor('cloudinary.mediaSelector', conf);
var adv = PageMgr.getCustomEditor('cloudinary.advancedImageForm', conf);
editor.dependencies.put('advBreakout', adv);
editor.dependencies.put('breakout', videoSelector);

var conf = new HashMap();
conf.put('type', 'image');
var mediaPicker = PageMgr.getCustomEditor('cloudinary.mediaSelector', conf);
editor.dependencies.put('mediaPicker', mediaPicker);

var studioWidget = PageMgr.getCustomEditor('cloudinary.studioWidget', new HashMap());
editor.dependencies.put('studioWidget', studioWidget);
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@

{
"name": "Cloudinary Image Config Form",
"description": "Configure Image",
"resources": {
"scripts": [
"https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.2.10/iframeResizer.min.js",
"/experience/editors/cloudinary/utils.js",
"/experience/editors/cloudinary/imageForm.js"
"https://media-library.cloudinary.com/global/all.js",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be fetched dynamically from the BM?

"/experience/editors/cloudinary/imageFormWidget.js"
],
"styles": [
"/experience/editors/cloudinary/form.css"
"/experience/editors/cloudinary/videoFormWidget.css"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

var cloudinaryApi = require('*/cartridge/scripts/cloudinary/cloudinaryApi');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter please move all require statements to local scope


module.exports.init = function (editor) {
editor.configuration.put('cloudName', cloudinaryApi.data.getCloudName());
editor.configuration.put('apiKey', cloudinaryApi.data.getAPIKey());
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "Cloudinary Studio Widget",
"description": "Advanced image editor via Cloudinary Studio Widget",
"resources": {
"scripts": [
"https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.2.10/iframeResizer.contentWindow.min.js",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace with "open-iframe-resizer" https://github.com/Lemick/open-iframe-resizer

"https://studio-widget.cloudinary.com/latest/all.js",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be fetched dynamically from the BM?

"/experience/editors/cloudinary/studioWidget.js"
],
"styles": [
"/experience/editors/cloudinary/studioWidget.css"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@ var HashMap = require('dw/util/HashMap');
var cloudinaryApi = require('*/cartridge/scripts/cloudinary/cloudinaryApi');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter please move all require statements to local scope


module.exports.init = function (editor) {
var conf = new HashMap();
conf.put('type', 'video');
editor.configuration.put('cloudName', cloudinaryApi.data.getCloudName());
editor.configuration.put('cname', cloudinaryApi.data.getCloudinaryCNAME());
var videoSelector = PageMgr.getCustomEditor('cloudinary.mediaSelector', conf);
var adv = PageMgr.getCustomEditor('cloudinary.advancedVideoForm', conf);
editor.dependencies.put('advBreakout', adv);
editor.dependencies.put('breakout', videoSelector);
editor.configuration.put('iFrameEnv', cloudinaryApi.data.getIframeEnv());

// Pass default player option values from site preference to the widget
var currentSite = require('dw/system/Site').getCurrent();
var playerOptionsRaw = currentSite.getCustomPreferenceValue('CloudinaryPageDesignerVideoPlayerOptions');
var playerOptions = { autoplay: false, muted: false, loop: false, controls: true };
if (playerOptionsRaw) {
try {
var parsed = JSON.parse(playerOptionsRaw);
var keys = ['autoplay', 'muted', 'loop', 'controls'];
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
if (k in parsed) {
playerOptions[k] = !!parsed[k];
}
}
} catch (e) { /* keep defaults on parse error */ }
}
editor.configuration.put('playerOptions', JSON.stringify(playerOptions));

var conf = new HashMap();
conf.put('type', 'video');
var mediaPicker = PageMgr.getCustomEditor('cloudinary.mediaSelector', conf);
editor.dependencies.put('mediaPicker', mediaPicker);

var advancedConfig = PageMgr.getCustomEditor('cloudinary.advancedVideoForm', new HashMap());
editor.dependencies.put('advancedConfig', advancedConfig);
};
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@

{
"name": "Cloudinary Image Config Form",
"description": "Configure Image",
"name": "Cloudinary Video Config Form",
"description": "Configure Video",
"resources": {
"scripts": [
"https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.2.10/iframeResizer.min.js",
"/experience/editors/cloudinary/utils.js",
"/experience/editors/cloudinary/videoForm.js"
"https://media-library.cloudinary.com/global/all.js",
"/experience/editors/cloudinary/videoFormWidget.js"
],
"styles": [
"/experience/editors/cloudinary/form.css"
"/experience/editors/cloudinary/videoFormWidget.css"
]
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,89 @@
/**
* When the parent editor uses the new per-form-factor format
* ({ formValues: { desktop, mobile, tablet }, posterMode, playerOptions, transformationOverride })
* the iframe still expects formValues.video.asset.public_id to render its preview.
*
* cldUtils.cleanValue (called inside dehydrate) strips every top-level key except
* "formValues" and "breakpoints", so anything outside formValues is lost.
* We therefore map the resolved asset back into formValues.video.asset which is
* exactly what the iframe reads.
*/
function normalizeValueForIframe(value) {
if (!value || !value.formValues) return value;
var fv = value.formValues;

// Already in the old format – nothing to do

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter please use ascii dashes

if (fv.video && fv.video.asset) return value;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter please use the optional chain expression .?


// Resolve current asset from the new per-form-factor format
var entry = fv.desktop || fv.tablet || fv.mobile;
if (!entry || !entry.asset) return value;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional chain expression


var asset = entry.asset;

// If a full Advanced config was previously saved, restore it directly.
// This preserves every overlay field (font family, size, position, colour,
// text content, image overlay, player customisations, etc.) so the iframe
// can repopulate its UI exactly as the user left it.
if (value.advancedConfig) {
var restored = JSON.parse(JSON.stringify(value.advancedConfig));

// Always sync the asset to the current selection in case the user
// changed the video between Advanced sessions.
if (!restored.formValues) restored.formValues = {};
if (!restored.formValues.video) restored.formValues.video = {};
restored.formValues.video.asset = {
public_id: asset.public_id,
format: asset.format || '',
derived: asset.derived || []
};

// Ensure formValues.video.transStr is populated for the iframe preview.
// New saves already have it set (injected in the 'done' handler).
// For old saves (made before that fix), playerConf was stripped by SFCC
// storage so it won't be present here — fall back to the widget-level

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace to ascii dash

// transformationOverride which is preserved in the parent value.
if (!restored.formValues.video.transStr) {
if (restored.playerConf) {
try {
var pc = JSON.parse(restored.playerConf);
if (pc.transStr) {
restored.formValues.video.transStr = pc.transStr;
}
} catch (e) { /* keep empty if playerConf is unparseable */ }
}
if (!restored.formValues.video.transStr && value.transformationOverride) {
restored.formValues.video.transStr = value.transformationOverride;
}
}

return restored;
}

// First-time open – no previous Advanced config, start from scratch.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace to ascii dash

return {
formValues: {
video: {
asset: {
public_id: asset.public_id,
format: asset.format || '',
derived: asset.derived || []
},
transStr: value.transformationOverride || ''
}
}
};
}

(() => {
subscribe('sfcc:ready', async ({ value, config }) => {
console.log('[CLD AdvancedVideo] sfcc:ready raw value:', JSON.stringify(value));
let iFrame = document.createElement('iframe');
let val = encodeURIComponent(JSON.stringify(cldUtils.dehydrate(value)));
let iframeValue = normalizeValueForIframe(value);
console.log('[CLD AdvancedVideo] iframeValue (before dehydrate):', JSON.stringify(iframeValue));
let dehydrated = cldUtils.dehydrate(iframeValue);
console.log('[CLD AdvancedVideo] dehydrated (goes into URL):', JSON.stringify(dehydrated));
let val = encodeURIComponent(JSON.stringify(dehydrated));
iFrame.src = config.iFrameEnv + '/video?cloudName=' + config.cloudName + '&value=' + val;
iFrame.id = 'video-form';
iFrame.setAttribute('frameborder', 0);
Expand All @@ -14,7 +96,9 @@
let ifrm = document.querySelector('iframe');
window.addEventListener('message', (event) => {
if (event.origin === config.iFrameEnv) {
handleIframeMessage(event.data, ifrm, value, config);
// Pass iframeValue (old-format shape) so the 'ready' handler
// posts back data the iframe can actually parse for its UI.
handleIframeMessage(event.data, ifrm, iframeValue, config);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter handleIframeMessage is defined with the first 3 params only

}
});
parentIFrame.getPageInfo((i) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asad-rafter use Number.parseFloat instead of parseFloat

Expand Down Expand Up @@ -45,11 +129,29 @@ const handleIframeMessage = (message, ifrm, value = null) => {
break;
case 'ready':
value.origin = 'ready';
console.log('[CLD AdvancedVideo] posting ready value to iframe:', JSON.stringify(value));
ifrm.contentWindow.postMessage(value, '*');
break;
case 'done':
delete message.action;
var val = Object.assign({}, message);
// playerConf.transStr is the authoritative transformation string.
// formValues.video.transStr is always empty in the iframe's done
// payload. SFCC strips every top-level key except formValues/
// breakpoints before delivering the value to the parent breakout
// callback, so playerConf itself disappears after storage.
// Inject transStr into formValues.video NOW, while playerConf is
// still available locally, so it survives the round-trip.
if (val.playerConf) {
try {
var doneConf = JSON.parse(val.playerConf);
if (doneConf.transStr) {
if (!val.formValues) val.formValues = {};
if (!val.formValues.video) val.formValues.video = {};
val.formValues.video.transStr = doneConf.transStr;
}
} catch (e) { /* keep as-is on parse error */ }
}
emit({
type: 'sfcc:value',
payload: val
Expand Down
Loading