/* global SCS, SCSRenderAPI, process */ import query from './query.mjs'; import { isUtmValueAcceptable } from './utils.mjs'; const _CARD_LAYOUT_3 = 'col-xs-12 col-sm-4 col-md-4 column-break layout-3-column'; const _CARD_LAYOUT_4 = 'col-xs-12 col-sm-4 col-md-3 column-break layout-4-column'; /** * Represents an item in the dictionary. * * @typedef {Object} DictionaryItem * @property {string} id - The ID of the item. * @property {string} name - The name of the item. * @property {string} createdDate - The creation date of the item. * @property {string} language - The language of the item. * @property {string} type - The type of the item. * @property {Object} fields - The fields of the item. */ /** * Represents the dictionary data. * * @typedef {Object} DictionaryData * @property {Object} getItems - The "getItems" property. */ /** * Represents the JSDoc type for the provided JSON data. * * @typedef {{ data: DictionaryData }} GlobalDictionariesGraphQL */ export default class { /** * @typedef {Object} CommonArgs * @property {Object} contentClient * @property {string} noPermissionToView * @property {Object} modules * @property {Object} scsData * @property {Object} utils * @property {Object} [SCSCompileAPI] * @param {CommonArgs} args */ constructor(args) { this.contentClient = args.contentClient; this.noPermissionToView = args.noPermissionToView || 'You do not have permission to view this asset'; this.libs = this.contentClient.getLibs() || {}; this.marked = this.libs.marked || window.marked; this.isCompilation = !!args.SCSCompileAPI; this.SCSCompileAPI = args.SCSCompileAPI; this.localUtils = args.utils; this.scsData = args.scsData; this.initializeModules(args.modules); /** @type {DictionaryItem | undefined} */ this.globalDictionary = undefined; } /** Created for render.mjs only */ async getProductHotspotModule() { this.productHotspotPath = SCSRenderAPI.getThemeUrlPrefix() + '/assets/js/productHotspot/productHotspot.mjs'; const ProductHotspotModule = await import(this.productHotspotPath); return ProductHotspotModule; } initializeModules(modules) { if (this.isCompilation) { this.localizationPath = '../../../themes/IR-Standard-Master-Theme/assets/js/localization/localization.mjs'; this.productHotspotPath = '../../../themes/IR-Standard-Master-Theme/assets/js/productHotspot/productHotspot.mjs'; this.importCardsName = '../../../themes/IR-Standard-Master-Theme/assets/js/cards/cards.mjs'; if (modules && modules.productHotspotModule) { this.productHotspotModule = modules.productHotspotModule; } if (modules && modules.localizationModule) { this.localization = modules.localizationModule; } this.ImageRenditionFormats = modules.ImageRenditionFormats; this.ImageRenditionTypes = modules.ImageRenditionTypes; } else { this.productHotspotPath = SCSRenderAPI.getThemeUrlPrefix() + '/assets/js/productHotspot/productHotspot.mjs'; this.importCardsName = SCSRenderAPI.getThemeUrlPrefix() + '/assets/js/cards/cards.mjs'; import(this.productHotspotPath) .then((moduleProductHotspot) => { this.productHotspotModule = moduleProductHotspot.default.prototype; }) .catch((err) => { console.log('PRODUCTPAGE:HOTSPOT:MODULE:NOT:INITIALIZED:', err); }); this.localizationPath = SCSRenderAPI.getThemeUrlPrefix() + '/assets/js/localization/localization.mjs'; import(this.localizationPath) .then((moduleLocalization) => { this.localization = new moduleLocalization.default({ SCSCompileAPI: this.SCSCompileAPI, SiteUtils: this.localUtils, }); }) .catch((err) => { console.log('PRODUCTPAGE:LOCALIZATION:MODULE:NOT:INITIALIZED:', err); }); } } async getCardsModule() { return await import(this.importCardsName); } getRefItems(ids) { if (ids.length === 0) { return Promise.resolve({}); } else { return this.contentClient.getItems({ ids: ids, }); } } findReferenceFieldIds(referencedItems, fields) { const referencedIds = []; referencedItems.forEach((referencedItem) => { if (fields[referencedItem]) { (Array.isArray(fields[referencedItem]) ? fields[referencedItem] : [fields[referencedItem]]).forEach( (entry) => { if (entry) { if (!entry.reference || entry.reference.isAccessible) { referencedIds.push(entry.id); } else { entry.referenceInaccessible = this.noPermissionToView; } } } ); } }); return referencedIds; } updateDigitalAssetURLs(digitalAssetFields, fields) { digitalAssetFields.forEach((digitalAssetField) => { if (fields[digitalAssetField]) { if (digitalAssetField == 'pdf_generate') { fields[digitalAssetField] = this.contentClient.getRenditionURL({ id: fields[digitalAssetField], }); } else { (Array.isArray(fields[digitalAssetField]) ? fields[digitalAssetField] : [fields[digitalAssetField]] ).forEach((entry) => { if (entry) { if (!entry.reference || entry.reference.isAccessible) { if (entry.type === 'Video' || entry.type === 'File') { entry.showName = true; } else { entry.url = this.contentClient.getRenditionURL({ id: entry.id, }); } } else { entry.referenceInaccessible = this.noPermissionToView; } } }); } } }); } updateMarkdownFields(markdownFields, fields) { const parseMarkdown = (mdText) => { if (mdText && /^\n\r/i.test(mdText)) { mdText = mdText.replace('\n\r', ''); mdText = this.marked(mdText); } return mdText; }; markdownFields.forEach((markdownField) => { if (fields[markdownField]) { if (Array.isArray(fields[markdownField])) { fields[markdownField] = fields[markdownField].map((entry) => { return parseMarkdown(this.contentClient.expandMacros(entry)); }); } else { fields[markdownField] = parseMarkdown(this.contentClient.expandMacros(fields[markdownField])); } } }); } updateRichTextFields(richTextFields, fields) { richTextFields.forEach((richTextField) => { if (fields[richTextField]) { if (Array.isArray(fields[richTextField])) { fields[richTextField] = fields[richTextField].map((entry) => { return this.contentClient.expandMacros(entry); }); } else { fields[richTextField] = this.contentClient.expandMacros(fields[richTextField]); } } }); } updateDateTimeFields(dateTimeFields, fields) { const dateToMDY = (date) => { if (!date) { return ''; } const dateObj = new Date(date); const options = { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', }; const formattedDate = dateObj.toLocaleDateString('en-US', options); return formattedDate; }; dateTimeFields.forEach((dateTimeField) => { if (fields[dateTimeField]) { if (Array.isArray(fields[dateTimeField])) { fields[dateTimeField] = fields[dateTimeField].map((entry) => { return (entry.formatted = dateToMDY(entry.value)); }); } else { fields[dateTimeField].formatted = dateToMDY(fields[dateTimeField].value); } } }); } addReferencedItems(referencedItems, results, fields) { ((results && results.items) || []).forEach((item) => { referencedItems.forEach((referencedItem) => { (Array.isArray(fields[referencedItem]) ? fields[referencedItem] : [fields[referencedItem]]).forEach( (entry) => { if (entry && entry.id === item.id) { entry.contentItem = item; const digitalAssetFields = Object.keys(item.fields).filter((key) => { const field = item.fields[key]; return field && typeof field === 'object' && field.typeCategory === 'DigitalAssetType'; }); this.updateDigitalAssetURLs(digitalAssetFields, item.fields); } } ); }); }); } async getLocalizationModule() { if (this.localization) { return this.localization; } else { const moduleLocalization = await import(this.localizationPath).then((moduleLocalization) => { return moduleLocalization; }); this.localization = new moduleLocalization.default({ SCSCompileAPI: this.SCSCompileAPI, SiteUtils: this.localUtils, }); return this.localization; } } getCountryCodeFromLocale(locale) { let countryCode = ''; const localeSplit = locale.split('-'); if (localeSplit.length > 1) { countryCode = localeSplit[localeSplit.length - 1].toLowerCase(); } else { countryCode = ''; } return countryCode; } /** * Returns fallback language - the param raw converts to OCM system language * * @param {any} languageCode * @param {true | false} raw * @returns */ getLanguageFallback(languageCode, raw) { let languageFallback = undefined; if (this.isCompilation) { languageFallback = this.SCSCompileAPI.siteInfo.properties.localeFallbacks && this.SCSCompileAPI.siteInfo.properties.localeFallbacks[languageCode]; } else { languageFallback = SCSRenderAPI.siteInfo.properties.localeFallbacks && SCSRenderAPI.siteInfo.properties.localeFallbacks[languageCode]; } if (raw) { // languageFallback can arrive as en-IT but we need to recode as en-x-IT //below code transforms where needed en-IT into en-x-IT if (this.isCompilation) { languageFallback = this.SCSCompileAPI.siteInfo.properties.localeAliases[languageFallback] || languageFallback; } else { languageFallback = SCS.siteInfo.properties.localeAliases[languageFallback] || languageFallback; } } return languageFallback || 'en'; } /** * @param {IR | RAW | ISO} mode * @returns IR: lg-rg, RAW: lg-x-RG|lg-RG, ISO: lg-RG */ getPageLanguageCode(mode = 'ND') { let localCode = 'en'; if (this.isCompilation) { localCode = this.SCSCompileAPI.pageLocale || localCode; } else { localCode = (SCSRenderAPI && SCSRenderAPI.getPageLocaleAlias()) || SCS.localeAlias || SCS.pageLanguageCode || localCode; } mode = mode.toUpperCase(); if (mode == 'IR') { localCode = localCode.toLowerCase(); } if (mode == 'RAW') { if (this.isCompilation) { localCode = this.SCSCompileAPI.siteInfo.properties.localeAliases[localCode] || localCode; } else { localCode = SCS.siteInfo.properties.localeAliases[localCode] || localCode; } } if (mode == 'ISO') { if (this.isCompilation) { localCode = this.SCSCompileAPI.siteInfo.properties.localeAliases[localCode] || localCode; } else { localCode = SCS.siteInfo.properties.localeAliases[localCode] || localCode; } if (localCode.indexOf('-x-') > -1) { const ls = localCode.split('-x-'); if (ls.length > 0) { localCode = ls[0] + '-' + ls[ls.length - 1].toUpperCase(); } } } return localCode; } async checkFallback(contentItemData) { console.log('PRODUCTPAGE:CHECKFALLBACKS'); if (contentItemData === undefined || contentItemData == null || contentItemData.length <= 0) { console.log('PRODUCTPAGE:CHECKFALLBACKS:EMPTY:OBJECT'); return contentItemData; } const localization = await this.getLocalizationModule(); return localization.checkFallback(contentItemData); } getIndexFromUrl() { let index = 1; if (!this.isCompilation) { const items = window.location.href.split('#'); items?.forEach((item) => { if (item.indexOf('menu') > -1) { const menu = item.split('menu'); if (menu && menu[1] && !Number.isNaN(menu[1])) { // eslint-disable-next-line prefer-destructuring index = menu[1]; } } }); } return index; } setCookie(cname, cvalue, exdays) { let expires = ''; if (exdays) { const d = new Date(); d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000); expires = 'expires=' + d.toUTCString(); } document.cookie = cname + '=' + cvalue + ';' + (expires ? expires + ';path=/' : ''); } getCookie(cname) { const name = cname + '='; const decodedCookie = decodeURIComponent(document.cookie); const ca = decodedCookie.split(';'); for (let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ''; } updateCtaLinks(referencedItems, fields, localUtils) { (fields[referencedItems] || []).forEach((ctaLink) => { const fields = ctaLink.fields; if (fields) { let fullLinkFromMedia = ''; this.updateDigitalAssetURLs(['media'], fields); if (fields?.media_file || fields?.mediaFile) { this.updateDigitalAssetURLs(['media_file', 'mediaFile'], fields); fullLinkFromMedia = fields.media_file.fields.file.url || fields?.mediaFile.fields.file.url; } this.updateMarkdownFields(['link'], fields); if (this.isCompilation) { ctaLink = localUtils.formatCtaLinks(this.SCSCompileAPI, ctaLink); } else { ctaLink = localUtils.formatCtaLinks(ctaLink); } fields['full_link'] = fields['full_link'] || fullLinkFromMedia || ''; } }); } /** * @param {string} [id] * @param {string} [className] * @param {string} [src] * @param {string} [alt] * @param {Object} [attrs] * @returns {string} */ getImageTemplate({ className, id, src, alt, attrs = {} }) { return ` `${key}="${value}"`) .join(' ')} >`; } formatSection(section, localUtils) { const fields = section.fields; if (fields) { let formattedSection = '
'; const section_title = localUtils.getTextValue(section.fields.section_title); this.updateMarkdownFields(['html_content'], section.fields); let html_content = localUtils.getHtmlValue(section.fields.html_content); section.fields.title = localUtils.getTextValue(section.fields.title); html_content = html_content.replace( '

 

', '

' + section.fields.title + '

' ); const media = section.fields.section_media ? section.fields.section_media : null; let media_position = section.fields.section_media_position ? section.fields.section_media_position : 'left'; if ( media_position && ['left', 'right', 'center', 'left50', 'right50', 'image_center'].indexOf(media_position.toLowerCase()) < 0 ) { media_position = 'left'; } let caption = localUtils.getTextValue(section.fields.section_media_caption); this.updateCtaLinks('cta_links', section.fields, localUtils); const ctalinks = section.fields.cta_links ? section.fields.cta_links : []; (Array.isArray(ctalinks) ? ctalinks : []).forEach((ctalink) => { const fields = ctalink.fields; if (fields) { const full_link = fields.full_link; const _data_gtm = fields.data_gtm; const format_cl = 'industrial-btn brandbackground'; const link_title = fields.link_title; html_content = html_content + '
' + '' + link_title + ''; } }); if (media && media_position == 'left') { const url = media?.fields?.smallImg?.file?.url; const image = this.getImageTemplate({ className: 'img-responsive cx__sez_img_dim_360', src: url, alt: media?.fields?.imageAlt, }); formattedSection = formattedSection + '
' + '
' + '
' + image + '
' + caption + '
' + '
' + '
' + '
' + '

' + section_title + '

' + '

' + html_content + '

' + '
' + '
' + '
' + '
'; } else if (media && media_position == 'right') { const url = media.fields.smallImg.file.url; const image = this.getImageTemplate({ className: 'img-responsive cx__sez_img_dim_360', src: url, alt: media?.fields?.imageAlt, }); formattedSection = formattedSection + '
' + '
' + '
' + '
' + '

' + section_title + '

' + '

' + html_content + '

' + '
' + '
' + '
' + image + '
' + caption + '
' + '
' + '
' + '
'; } else if (media && media_position == 'center') { const url = media.fields.smallImg.file.url; const image = this.getImageTemplate({ className: 'img-responsive cx__sez_img_dim_360 center-aligned', src: url, alt: media?.fields?.imageAlt, attrs: { loading: 'lazy', 'data-was-processed': '', }, }); caption = caption != '' ? '
' + caption + '
' : ''; formattedSection = formattedSection + '
' + '
' + '

' + section_title + '

' + html_content + '

' + '
' + '' + image + '' + caption + '
'; } else if (media && media_position == 'left50') { const url = media.fields.smallImg.file.url; const image = this.getImageTemplate({ className: 'img-responsive', src: url, alt: media?.fields?.imageAlt, }); formattedSection = formattedSection + '
' + '
' + '
' + image + '
' + caption + '
' + '
' + '
' + '
' + '

' + section_title + '

' + '

' + html_content + '

' + '
' + '
' + '
' + '
'; } else if (media && media_position == 'right50') { const url = media.fields.smallImg.file.url; const image = this.getImageTemplate({ className: 'img-responsive', src: url, alt: media?.fields?.imageAlt, }); formattedSection = formattedSection + '
' + '
' + '
' + '
' + '

' + section_title + '

' + '

' + html_content + '

' + '
' + '
' + '
' + image + '
' + caption + '
' + '
' + '
' + '
'; } else if (media && media_position == 'image_center') { const url = media.fields.smallImg.file.url; const image = this.getImageTemplate({ className: 'img-responsive img-responsive center-aligned', src: url, alt: media?.fields?.imageAlt, }); formattedSection = formattedSection + '
' + '
' + '
' + '

' + section_title + '

' + '' + image + '' + '

' + html_content + '

' + '
' + '
' + '
'; } else { formattedSection = '
' + '
' + '
' + '

' + section_title + '

' + html_content + '

' + '
' + '
'; } let ytbIframe = ''; if (section.fields.youtube_embed_link) { if ( section.fields.youtube_embed_link.indexOf('embed') > -1 && section.fields.youtube_embed_link.indexOf('youtube') > -1 ) { ytbIframe = '
' + '
' + '
' + '
' + '
' + '' + '
' + '
' + '
' + '
' + '
'; } else if ( section.fields.youtube_embed_link.indexOf('watch') > -1 && section.fields.youtube_embed_link.indexOf('youtube') > -1 ) { const url = section.fields.youtube_embed_link; const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; const match_ = url.match(regExp); if (match_ && match_[2]) { ytbIframe = '
' + '
' + '
' + '
' + '
' + '' + '
' + '
' + '
' + '
' + '
'; } } } let cards = ''; if (section.fields.cards && section.fields.cards.length > 0) { this.updateCtaLinks('cards', section.fields, localUtils); const columnsToString = { 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six' }; section.fields.layout_cards = columnsToString[section.fields.columns] || columnsToString[4]; cards = '
'; if (section.fields.title) { cards += '
' + '
' + '

' + section.fields.title + '

' + '
' + '
'; } cards += '
'; if (this.cards) { const pageLocale = this.isCompilation ? this.SCSCompileAPI.pageLocale : SCSRenderAPI.getPageLocaleAlias(); cards += this.cards.getCardsHtml(section.fields.cards, pageLocale); } cards += '
'; } formattedSection = formattedSection + ytbIframe + cards + '
'; return formattedSection; } } async asyncForEach(array, callback) { for (let index = 0; index < array.length; index++) { await callback(array[index], index, array); } } queryRelatedItems(content) { console.log('PRODUCTPAGE:TABRELATEDITEMS:INPROGRESS'); return new Promise((resolve, reject) => { const fields = content.fields; if (fields && fields.tabs && fields.tabs.length > 0 && Array.isArray(fields.tabs)) { //(content.fields.tabs || []).forEach(async (tab, index, array) => { this.asyncForEach(content.fields.tabs || [], async (tab, index, array) => { tab.fields.cards = []; const ri_API = this.localUtils.getTaxonomyRoot() + 'ri-' + tab.name; console.log('PRODUCTPAGE:TABRELATEDITEMS:QUERYING:', ri_API); try { const result = await this.queryContent('relatedItems', ri_API); let items = result?.data?.getItems?.items || []; if (items.length > 0) { if (this.isCompilation) { items = this.localUtils.removeDuplicates( this.getPageLanguageCode('raw'), items, 'name' ); } else { items = this.localUtils.removeDuplicates(items, 'name'); } (Array.isArray(items) ? items : []).forEach((tabRelatedItem) => { tab.fields.cards.push(tabRelatedItem); }); } console.log('PRODUCTPAGE:TABRELATEDITEMS:QUERIED:OK:', ri_API, items.length); } catch (Err) { console.log('PRODUCTPAGE:TABRELATEDITEMS:QUERIED:ERROR:', ri_API); reject(Err); } if (index === array.length - 1) { console.log('PRODUCTPAGE:TABRELATEDITEMS:RESOLVED'); resolve(content.fields.tabs); } }); } else { resolve(content); } }).then(() => { console.log('PRODUCTPAGE:TABRELATEDITEMS:COMPLETED'); return content; }); } queryContent(type, apiName, contentItemData) { return new Promise((resolve, reject) => { const ccInfo = this.contentClient.getInfo(); const channelToken = ccInfo.channelToken; //const requestModeGraphQl = ccInfo.contentType === 'draft' ? 'preview' : 'published'; const languageCode = this.getPageLanguageCode('raw'); const languageFallback = this.getLanguageFallback(languageCode, true); const langsQuery = `OR :[ {language: {op: EQUALS, value: "${languageCode}"}}, ${languageFallback !== languageCode ? `{language: {op: EQUALS, value: "${languageFallback}"}},` : ''}]`; let graphQLQuery = ''; if (type === 'productPage') { const contentId = contentItemData.id; graphQLQuery = query.getProductPage .replace('CHANNEL_TOKEN', channelToken) .replace('CONTENT_ID', contentId); } if (type === 'relatedItems') { graphQLQuery = query.getRelatedItems .replace('CHANNEL_TOKEN', channelToken) .replace('LANGUAGE_QUERY', langsQuery) .replace('API_NAME', apiName); } if (type === 'labels') { graphQLQuery = query.getLabels .replace('CHANNEL_TOKEN', channelToken) .replace('LANGUAGE_QUERY', langsQuery); } this.contentClient .graphql({ query: graphQLQuery, }) .then((response) => { resolve(response); }) .catch((err) => { const resp = this.manageQueryErr(type, apiName, contentItemData, err); if (resp.throwErr) { reject(resp.errMessage); } else { console.warn(resp.errMessage); resolve(resp.result); } }); }); } manageQueryErr(type, apiName, contentItemData, err) { const errMessage = 'PRODUCTPAGE:GRAPHQL:QUERY:CRITICAL:FAILURE'; const emptyResultSet = { data: { getItems: { items: [], }, }, }; const resp = { throwErr: false, result: emptyResultSet, errMessage: errMessage }; if (type === 'productPage') { resp.errMessage = resp.errMessage + ':PAGE:' + contentItemData.id; } if (type === 'relatedItems') { resp.errMessage = resp.errMessage + ':RELATED ITEM:' + apiName; } if (type === 'labels') { resp.errMessage = resp.errMessage + ':LABELS:'; } if (err.statusCode) { resp.errMessage = resp.errMessage + ':STATUS:CODE:' + err.statusCode + ':MSG:' + err.statusMessage; } if (this.isCompilation) { resp.errMessage = resp.errMessage + ':CURRENT:PAGE:' + this.SCSCompileAPI.navigationCurr + ':LANGUAGE:' + this.SCSCompileAPI.pageLocale; const ignoreErrors = !!process.argv.find((arg) => arg === '--ignoreErrors' || arg === '-i'); if (ignoreErrors) { resp.throwErr = false; } else { resp.throwErr = true; } } return resp; } modelSettings(model) { let contentType; let customSettings; // If used with CECS Sites, Sites will pass in context information via the scsData property. if (this.scsData) { model = Object.assign(model, { scsData: this.scsData, }); contentType = model.scsData.showPublishedContent === true ? 'published' : 'draft'; customSettings = model.scsData.customSettingsData || {}; } model.contentType = contentType; model.customSettings = customSettings; return model; } modelSetLabels(model) { const modelFields = model.fields; if (modelFields && modelFields.dictionary) { if (this.content.fields.dictionary) { const dictionaryFields = modelFields.dictionary.fields; (Array.isArray(dictionaryFields.labels.list) ? dictionaryFields.labels.list : []).forEach((label) => { if (label.value == 'shareThePageLabel') { modelFields.shareThePageLabel = label.label; } if (label.value == 'backToProductListLabel') { modelFields.backToProductListLabel = label.label; } if (label.value == 'learnMoreLabel') { modelFields.learnMoreLabel = label.label; } }); } } return model; } modelSetHorizontalDivs(model) { const fields = model.fields; if (fields) { fields.horizontal_sections_width = ''; if (fields.horizontal_sections) { fields.horizontal_sections_width = 'col-md-' + 12 / fields.horizontal_sections.length; } } return model; } getParentPageUrl() { const HOMEPAGEID = 12; let parentPageId = HOMEPAGEID; let parentPageUrl = ''; if (this.isCompilation) { const currentPageId = this.SCSCompileAPI.navigationCurr; const node = this.SCSCompileAPI.structureMap[currentPageId]; if (node.parentId) { parentPageId = node.parentId; } } else { const currentPageId = SCSRenderAPI.getPageId(); const node = SCS.structureMap[currentPageId]; if (node.parentId) { parentPageId = node.parentId; } } if (this.isCompilation) { const pname = this.SCSCompileAPI.structureMap[parentPageId || HOMEPAGEID].name; parentPageUrl = this.localUtils.getPageUrlRelative(this.SCSCompileAPI, { name: pname }); } else { const _pageLinkData = SCSRenderAPI.getPageLinkData(parentPageId || HOMEPAGEID); parentPageUrl = _pageLinkData.href; } return parentPageUrl; } modelSetBackUrl(model) { const fields = model.fields; if (fields) { if (this.isCompilation) { fields.back_url = ''; } else { fields.back_url = document.referrer; } } return model; } hydrateContent(content) { const hydrateData = {}; hydrateData['addPriceSpider'] = false; hydrateData['redirect'] = content['redirect']; hydrateData['language'] = content['language']; hydrateData['productHotspot'] = content['productHotspot']; if (content.productHotspot && content.productHotspot.exist) { hydrateData['productHotspot_exist'] = content.productHotspot.exist; hydrateData['productHotspot_background_color'] = content.productHotspot.background_color; } if (content.addPriceSpider) { hydrateData['addPriceSpider'] = true; } const fields = content.fields; if (fields) { hydrateData['shareLink'] = fields.shareLink; hydrateData['bottom_cta_links'] = fields.bottom_cta_links; hydrateData['meta_title'] = fields.meta_title; hydrateData['pageLocaleAlias'] = content.pageLocaleAlias; if (fields.addPriceSpider) { hydrateData['addPriceSpider'] = true; } if (fields.tabs) { hydrateData['tabsPresent'] = true; } else { hydrateData['tabsPresent'] = false; } hydrateData['gallery'] = fields.gallery; hydrateData['switchOffZoom'] = fields.switchOffZoom; } hydrateData.productSKU = this.productSKU; return hydrateData; } transformTabs(model) { if (model.fields.tabs) { model.fields.containerClass = 'container'; if (model.fields?.full_width) { model.fields.containerClass = 'container-max-width'; } model.tabsPresent = true; (Array.isArray(model.fields.tabs) ? model.fields.tabs : []).forEach((tab, index) => { const tab_formatted_sections = []; tab['index'] = index + 1; if (tab['index'] == this.getIndexFromUrl()) { tab['active'] = 'active'; } else { tab['active'] = ''; } if (tab.fields.mediaItems) { let layout = _CARD_LAYOUT_4; if (tab.fields.layout == '3 column') { layout = _CARD_LAYOUT_3; } tab.fields.mediaItems = this.transformMediaItems(tab.fields.mediaItems, layout); } // RelatedItems if (tab.fields.cards && tab.fields.cards.length > 0) { tab.fields.cards = this.transformRelatedItems(tab.fields.cards, model); const formatted_section_cards = this.formatSection(tab, this.localUtils); tab_formatted_sections.push(formatted_section_cards); } (Array.isArray(tab.fields.contentItem) ? tab.fields.contentItem : []).forEach((item) => { if (item?.fields?.cards) { item.fields.cards.priceSpiderActive = model.ps_key && item.fields.priceSpiderActive; if (item.fields.cards.priceSpiderActive) { model.addPriceSpider = true; } item.fields.cards.pageLocaleAlias = model.pageLocaleAlias; item.fields.cards = this.transformCards(item.fields.cards, model); } let formatted_section = ''; const sectionType = item?.type; if (sectionType && sectionType.indexOf('Hotspot') > -1) { item = this.transformCategoriesHotspot(item); if (this.productHotspotModule) { formatted_section = this.productHotspotModule.formatSectionProductHotspot(item); this.content.productHotspot.exist = true; this.content.productHotspot.background_color = item.fields.backgroundColor ? item.fields.backgroundColor : this.content.productHotspot.background_color; } else { console('PRODUCT:PAGE:COMMON:NO:MODULE:HOTSPOT'); } } else { formatted_section = this.formatSection(item, this.localUtils); } tab_formatted_sections.push(formatted_section); if (item.fields?.subTabs) { item.fields.hasTabs = item.fields.subTabs.length > 0 ? true : false; item.fields.subTabs = this.transformSubTabs(item.fields.subTabs, model); } }); tab.fields.formatted_sections = ''; tab_formatted_sections.forEach((section) => { tab.fields.formatted_sections += section; }); }); } else { model.tabsPresent = false; } return model; } regionalizeTabs(modal) { return new Promise((resolve, reject) => { const fields = modal.fields; if (fields && fields.tabs && fields.tabs.length > 0 && Array.isArray(fields.tabs)) { this.asyncForEach(modal.fields.tabs || [], async (tab, index, array) => { try { if (tab.fields.mediaItems) { const mediaItems = await this.localUtils.regionalizeItems(tab.fields.mediaItems); tab.fields.mediaItems = mediaItems; } // RelatedItems if (tab.fields.cards && tab.fields.cards.length > 0) { const relatedItems = await this.localUtils.regionalizeItems(tab.fields.cards); tab.fields.cards = relatedItems; } this.asyncForEach(tab.fields.contentItem || [], async (item) => { if (item?.fields?.cards) { const cards = await this.localUtils.regionalizeItems(item.fields.cards); item.fields.cards = cards; } }); } catch (Err) { reject(Err); } if (index === array.length - 1) { resolve(modal.fields.tabs); } }); } else { resolve(modal); } }).then(() => { return modal; }); } transformCards(cards, model) { (Array.isArray(cards) ? cards : []).forEach((card) => { if (card.fields) { const learnMoreLabel = model?.labels?.learnMoreLabel || ''; card.fields.learnMoreLabel = cards?.fields?.learnMoreLabel || learnMoreLabel; } this.updateDigitalAssetURLs(['media', 'media_file'], card.fields); this.updateMarkdownFields(['link'], card.fields); if (cards?.priceSpiderActive) { this.handlePriceSpider(card, cards?.pageLocaleAlias); } card = this.handleCardLink(card); if ( card.fields.full_link == '' && card?.type?.indexOf('Card') > -1 && card?.fields?.card_type?.indexOf('File') > -1 ) { card.fields.full_link = card.fields.media_file ? card.fields.media_file.url : ''; } card.fields.sublinksSection = card.fields?.sublinks_section || card.fields?.associatedPages; if (card.fields?.sublinksSection?.length > 0) { card.fields?.sublinksSection.forEach((sublink) => { sublink.fields && this.handleCardLink(sublink); }); } }); return cards; } handleCardLink(card) { return this.isCompilation ? this.localUtils.formatCtaLinks(this.SCSCompileAPI, card) : this.localUtils.formatCtaLinks(card); } handlePriceSpider(card, pageLocaleAlias = '') { let sku = ''; if (card.fields.skus) { card.fields.skus?.list.forEach((skuItem) => { sku = skuItem.value2 && skuItem.value2.toLowerCase() === pageLocaleAlias.toLowerCase() ? skuItem.value1 : sku; }); } if (sku) { card.fields.addPriceSpider = true; card.fields.sku = sku; } } transformRelatedItems(related_items, model) { const customSettings = model.customSettings; const learnMoreLabel = model.fields.learnMoreLabel; let chooseRICTALabel = ''; if (customSettings && customSettings['chooseRICTALabel']) { chooseRICTALabel = customSettings['chooseRICTALabel']; } (Array.isArray(related_items) ? related_items : []).forEach((related_item) => { const fields = related_item.fields; if (fields) { if (fields.teaser_media) { this.updateDigitalAssetURLs(['teaser_media'], fields); } related_item['full_link'] = this.localUtils.getPageLink(related_item); fields.teaser_title = fields.teaser_title || ''; fields.teaser_summary = fields.teaser_summary || ''; fields.sublinksSection = fields?.sublinks_section || fields?.associatedPages; if (fields?.sublinksSection?.length > 0) { fields?.sublinksSection.forEach((sublink) => { sublink.fields && this.handleCardLink(sublink); }); } if (chooseRICTALabel && chooseRICTALabel == 'Detail') { fields.learnMoreLabel = learnMoreLabel; } else if (chooseRICTALabel && chooseRICTALabel == 'Detail_Custom_CTA') { fields.learnMoreLabel = fields.learnMoreLabel || learnMoreLabel; } else if (chooseRICTALabel && chooseRICTALabel == 'Detail_Hidden_CTA') { fields.learnMoreLabel = ''; } else { fields.learnMoreLabel = fields.learnMoreLabel || learnMoreLabel || model?.labels?.learnMoreLabel || ''; } } }); return related_items; } transformMediaItems(mediaItems, layout) { (Array.isArray(mediaItems) ? mediaItems : []).forEach((mediaItem) => { mediaItem.fields.items_per_row = layout; mediaItem.fields.file_name = this.localUtils.getTextValue(mediaItem.fields.fileName); let first_page_img = undefined; try { first_page_img = mediaItem.fields.rendition.file.url; } catch (error) { first_page_img = undefined; } if (mediaItem.fields.flagUsePdfFirstPage && first_page_img) { mediaItem.fields.pdf_image = first_page_img; } else { mediaItem.fields.pdf_image = this.localUtils.getSiteCSSImage('download-red-ir.png'); } let media_link = mediaItem.fields.file.url; let siteDomain = undefined; if (this.isCompilation) { siteDomain = this.SCSCompileAPI.siteInfo.properties.customProperties.SITE_DOMAIN; } else { siteDomain = SCS.siteInfo.properties.customProperties.SITE_DOMAIN; } if (siteDomain && media_link) { media_link = media_link.split(siteDomain)[1]; } mediaItem.fields.media_link = media_link; }); return mediaItems; } transformSubTabs(subTabs, model) { this.asyncForEach(subTabs || [], async (subTab, index) => { const sub_tab_formatted_sections = []; subTab['subTabIndex'] = index + 1; if (subTab['subTabIndex'] == this.getIndexFromUrl()) { subTab['subTabActive'] = 'active'; } else { subTab['subTabActive'] = ''; } if (subTab.fields.mediaItems) { const mediaItems = await this.localUtils.regionalizeItems(subTab.fields.mediaItems); subTab.fields.mediaItems = mediaItems; let layoutSubtab = _CARD_LAYOUT_4; if (subTab.fields.layout == '3 column') { layoutSubtab = _CARD_LAYOUT_3; } subTab.fields.mediaItems = this.transformMediaItems(subTab.fields.mediaItems, layoutSubtab); } (Array.isArray(subTab.fields.contentItem) ? subTab.fields.contentItem : []).forEach((item) => { if (!(Object.keys(item).length === 0 && item.constructor === Object)) { if (item?.fields?.cards) { item.fields.cards.priceSpiderActive = model.ps_key && item.fields.priceSpiderActive; if (item.fields.cards.priceSpiderActive) { model.addPriceSpider = true; } item.fields.cards.pageLocaleAlias = model.pageLocaleAlias; item.fields.cards = this.transformCards(item.fields.cards, model); } let formatted_sub_section = ''; if (item.type.indexOf('Hotspot') > -1) { item = this.transformCategoriesHotspot(item); formatted_sub_section = this.productHotspot.formatSectionProductHotspot(item); this.content.productHotspot.exist = item.type.indexOf('Hotspot') > -1 ? true : this.content.productHotspot.exist; this.content.productHotspot.background_color = item.fields.backgroundColor ? item.fields.backgroundColor : this.content.productHotspot.background_color; } else { formatted_sub_section = this.formatSection(item, this.localUtils); } sub_tab_formatted_sections.push(formatted_sub_section); } }); subTab.fields.formatted_sub_section = ''; sub_tab_formatted_sections.forEach((section) => { subTab.fields.formatted_sub_section += section; }); }); return subTabs; } transformCategoriesHotspot(item) { let categories = []; (Array.isArray(item.fields?.hotspotsFields) ? item.fields.hotspotsFields : []).forEach((item) => { categories.push(item.fields.category); const parentId = item.id; (Array.isArray(item.fields?.sections) ? item.fields.sections : []).forEach((section) => { section['parentId'] = parentId; }); }); categories = [...new Set(categories)]; item.fields['categories'] = []; categories.forEach((category, index) => { item.fields.categories.push({ name: category, active: index === 0 ? 'active' : '', }); }); item.fields.categories = item.fields.categories.map((category) => { const translatedCategoryName = this.globalDictionary?.fields.labels.list.find( (item) => item.value.toLowerCase() === category.name.toLowerCase() )?.label; return { ...category, name: translatedCategoryName || category.name, }; }); item.fields.hotspotsFields = item.fields.hotspotsFields.map((hotspot) => { const translatedHotspotName = this.globalDictionary?.fields.labels.list.find( (item) => item.value.toLowerCase() === hotspot.fields.category.toLowerCase() )?.label; return { ...hotspot, fields: { ...hotspot.fields, category: translatedHotspotName || hotspot.fields.category, }, }; }); return item; } /** @param {GlobalDictionariesGraphQL} dictionariesRes */ setGlobalDictionary(dictionariesRes) { const dictionaries = /** @type {DictionaryItem[]} */ (dictionariesRes?.data?.getItems?.items || []); const userLangDictionary = dictionaries.find((item) => item.language === this.getPageLanguageCode('raw')); const defaultLangDictionary = dictionaries.find((item) => item.language === this.getLanguageFallback()); this.globalDictionary = userLangDictionary || defaultLangDictionary; } async createModel(query, dictionary) { const content = query || this.contentItemData; this.content = Object.assign({}, content); this.content.labels = {}; this.initLabels(this.content, dictionary); this.setGlobalDictionary(dictionary); await this.getCardsModule().then((cards) => { this.cards = cards; }); this.content = await this.transformModel(this.content); return this.content; } async transformModel(model) { model.pageLocaleAlias = this.getPageLanguageCode('ir'); model.pageLanguage = this.getPageLanguageCode('raw'); model.ps_key = this.getPriceSpiderKey(); model.addPriceSpider = false; model.site_taxonomy = this.getSiteTaxonomy(); model.productHotspot = { exist: false, background_color: '' }; model.clickToEnlargeLabel = model.labels?.clickToEnlargeLabel; model.backToProductListLabel = model.labels?.backToProductListLabel; model.shareThePageLabel = model.labels?.shareThePageLabel; model = this.modelSettings(model); model = this.modelSetHorizontalDivs(model); model = this.setBackUrl(model); model = await this.regionalizeTabs(model); model = await this.regionalizeMainSection(model); model = this.transformMainSection(model); model = this.transformTabs(model); const fields = model.fields; if (fields && fields.switchOffZoom) { model.switchOffZoom = fields.switchOffZoom; } return model; } /** * Returns array of UTM parameters * * @example * // returns ['productCategory=category', 'technology=technology', 'model=model', 'utm_campaign=campaign', 'utm_source=source', 'utm_medium=medium', 'utm_term=term', 'utm_content=content'] * const parameters = this.getParameters(model); * * @param {any} model * @returns {string[]} */ getParameters(model) { const utmFields = { technology: model?.fields?.technology, productCategory: model?.fields?.productCategory, model: model?.fields?.model, utm_campaign: model?.fields?.utmCampaign, utm_source: model?.fields?.utmSource, utm_medium: model?.fields?.utmMedium, utm_term: model?.fields?.utmTerm, utm_content: model?.fields?.utmContent, }; const parameters = Object.entries(utmFields) .filter(([, utmValue]) => isUtmValueAcceptable(utmValue)) .map(([utmKey, utmValue]) => `${utmKey}=${encodeURIComponent(utmValue)}`); return parameters; } async regionalizeMainSection(model) { const gallery = model.fields.gallery; const cta_links = model.fields.cta_links; if (gallery) { model.fields.gallery = await this.localUtils.regionalizeItems(gallery); } if (cta_links) { model.fields.cta_links = await this.localUtils.regionalizeItems(cta_links); } return model; } initLabels(model, queryDictionary) { const dictionary = this.getItemsFromGraphQL(queryDictionary); (dictionary || []).forEach((item) => { (item?.fields?.labels && Array.isArray(item.fields.labels.list) ? item.fields.labels.list : []).forEach( (label) => { if (label.value === 'learnMoreLabel') { model.labels.learnMoreLabel = label.label || item.learnMore; } if (label.value === 'clickToEnlargeLabel') { model.labels.clickToEnlargeLabel = label.label; } if (label.value == 'shareThePageLabel') { model.labels.shareThePageLabel = label.label; } if (label.value == 'backToProductListLabel') { model.labels.backToProductListLabel = label.label; } } ); }); } getItemsFromGraphQL(queryResult) { let items = queryResult?.data?.getItems?.items || []; if (this.isCompilation) { items = this.localUtils.removeDuplicates(this.SCSCompileAPI.pageLocale, items, 'name'); } else { items = this.localUtils.removeDuplicates(items, 'name'); } return items || []; } getPriceSpiderKey() { if (this.isCompilation) { return this.SCSCompileAPI.getCustomSiteProperty('PS_KEY') || ''; } else { return SCSRenderAPI.getCustomSiteProperty('PS_KEY') || ''; } } getSiteTaxonomy() { if (this.isCompilation) { return this.SCSCompileAPI.getCustomSiteProperty('SITE_ROOT_TAXONOMY') || ''; } else { return SCSRenderAPI.getCustomSiteProperty('SITE_ROOT_TAXONOMY') || ''; } } setBackUrl(model) { if (this.isCompilation) { model.fields.back_url = ''; if (this.scsData) { const currentPageId = this.SCSCompileAPI.navigationCurr; const node = this.SCSCompileAPI.structureMap[currentPageId]; if (node.parentId) { const pNode = this.SCSCompileAPI.structureMap[node.parentId]; model.fields.back_url = this.localUtils.getPageUrlRelative(this.SCSCompileAPI.structureMap, pNode); } } } else { model.fields.back_url = document.referrer; if (this.scsData) { const currentPageId = SCSRenderAPI.getPageId(); const node = SCS.structureMap[currentPageId]; if (node.parentId) { const pNode = SCS.structureMap[node.parentId]; model.fields.back_url = this.localUtils.getPageUrl(pNode.pageUrl); } } } return model; } setShareLink(model) { const fields = model.fields; if (this.isCompilation) { fields.shareLink = ''; } else { fields.shareLink = window.location.href; if (window.location.hash) { fields.shareLink = window.location.href.split(window.location.hash)[0]; } } } transformMainSection(model) { const parameters = this.getParameters(model); this.setShareLink(model); const fields = model.fields; if (fields) { this.updateMarkdownFields(['html_content'], fields); this.updateDigitalAssetURLs(['pdf_generate'], fields); if (fields.gallery) { for (let img = 0; img < fields.gallery.length; img++) { const imgAsset = fields.gallery[img]; imgAsset['data-imageid'] = img; if (this.isCompilation && this.ImageRenditionTypes && this.ImageRenditionFormats) { imgAsset.renditionUrl = this.localUtils.getRenditionURL( { id: imgAsset.id, type: this.ImageRenditionTypes.medium, format: this.ImageRenditionFormats.webp, nativeFormat: imgAsset.fileExtension, }, this.contentClient ); imgAsset.thumbnailUrl = this.localUtils.getRenditionURL( { id: imgAsset.id, type: this.ImageRenditionTypes.thumbnail, format: this.ImageRenditionFormats.webp, nativeFormat: imgAsset.fileExtension, }, this.contentClient ); } } model.gallery = model.fields.gallery; } if (fields.cta_links) { this.updateCtaLinks('cta_links', fields, this.localUtils); fields.top_cta_links_buyNow = []; fields.top_cta_links = []; fields.bottom_cta_links = []; (Array.isArray(fields.cta_links) ? fields.cta_links : []).forEach((ctalink) => { let param = true; parameters.forEach((item) => { if (item && param) { param = false; ctalink.fields.full_link = ctalink.fields.full_link + '?'; } if (item) { ctalink.fields.full_link = ctalink.fields.full_link + item + '&'; } }); if (ctalink.fields.full_link.endsWith('&')) { ctalink.fields.full_link = ctalink.fields.full_link.replace(/.$/, ''); } if (ctalink.name.toLowerCase().indexOf('contact') > -1) { fields.top_cta_links.push(ctalink); } else if ( ctalink.name.toLowerCase().indexOf('buy') > -1 || ctalink.fields.linkType == 'Price Spider' ) { fields.top_cta_links_buyNow.push(ctalink); } else { fields.bottom_cta_links.push(ctalink); } }); let sku = ''; if (fields.top_cta_links_buyNow && fields.top_cta_links_buyNow.length > 0) { fields.top_cta_links_buyNow.top_cta_links = fields.top_cta_links ? fields.top_cta_links : []; if (fields.skus) { fields.skus.list.forEach((skuItem) => { sku = skuItem.value2 && skuItem.value2.toLowerCase() == model.pageLocaleAlias.toLowerCase() ? skuItem.value1 : sku; }); } fields.top_cta_links_buyNow[0].sku = sku; fields.top_cta_links_buyNow[0].ps_key = 'ps-' + model.ps_key.split('-')[1]; if (sku) { model.addPriceSpider = true; } else { fields.top_cta_links_buyNow = false; } } } model.lastMarginID = fields.bottom_cta_links && Array.isArray(fields.bottom_cta_links) && fields.bottom_cta_links.length > 0 ? fields.bottom_cta_links[fields.bottom_cta_links.length - 1].id : ''; } return model; } redirect(data) { if (data.redirect && data.redirect.flag == true) { this.getLocalizationModule().then((localizationModule) => { localizationModule.redirect(data); }); return 1; } return 0; } }