Sunday, February 19, 2023

Advanced Techniques for Including JavaScript and CSS Files in Sitecore Content Hub


Just as a chef needs to add different ingredients to create a delicious dish, as a developer, you may need to include custom JavaScript and CSS files in your Sitecore Content Hub implementation. These files may contain functions, styles, or other code that you want to use across multiple pages or components.

In this article, we'll show you how to include these essential ingredients in your Sitecore Content Hub dishes and determine the position to inject them in the page header. This approach will help you keep your recipe organized, reduce duplication, and make it easier to maintain your custom code.

Step 1: Upload your files as assets

The first step is to upload your custom JavaScript and CSS files as assets in Sitecore Content Hub. You can do this by navigating to the Digital Asset Management section of your Content Hub instance and creating a new asset. Upload your JavaScript or CSS file, add any metadata or tags as needed, and save the asset.

Make a note of the asset ID for each file. You'll use this ID to fetch the asset and include it in your pages.

Step 2: Include your files in your pages

To include your JavaScript and CSS files in your pages, you'll need to use the getAsset function. This function fetches the asset by its ID, creates a new script or link element with the appropriate attributes, and inserts the element into the page header.

Here's an example of how to include a JavaScript file in your page:

const jsAssetId = "976160"; // replace with your asset ID
const position = 1; // replace with the desired position in the header, or remove for default position

$(document).ready(function() {
if (!jsAssetId || jsAssetId.length === 0) {
return;
}
getAsset(`/api/entities/${jsAssetId}`, 'downloadOriginal',position, type);
});


This example fetches the asset by its ID using the getAsset function, creates a new script element with the src attribute set to the asset URL, and inserts the element into the page header. The position parameter specifies the position to insert the element, or leave it undefined for the default position at the end of the header.

Here's an example of how to include a CSS file in your page:

const cssAssetId = "976169"; // replace with your asset ID
const position = 1; // replace with the desired position in the header, or remove for default position

$(document).ready(function() {
if (!cssAssetId || cssAssetId.length === 0) {
return;
}
getAsset(`/api/entities/${cssAssetId}`, 'downloadOriginal',position, type);
});

getAsset function

We have extended the getAsset function described in this blog post read blog post to handle the injection of JavaScript and CSS files. 


window.getAsset = async function getAsset(endpoint, rendition, position, type) {
try {
const response = await $.ajax({
url: endpoint,
method: 'GET',
});
let href = null;
if (response[rendition] && response[rendition][0] && response[rendition][0].href) {
href = response[rendition][0].href;
} else if (response.renditions && response.renditions[rendition] && response.renditions[rendition][0] && response.renditions[rendition][0].href) {
href = response.renditions[rendition][0].href;
} else if (response.original && response.original[0] && response.original[0].href && !type) {
// Use the default rendition if the requested rendition is not found and the type is not specified
href = response.original[0].href;
}
console.log("Include: " + href);
if (href && type) {
let asset = null;
if (type === "css") {
asset = document.createElement("link");
asset.rel = "stylesheet";
asset.href = href;
} else if (type === "js") {
asset = document.createElement("script");
asset.src = href;
}
const head = document.getElementsByTagName("head")[0];

if (position !== undefined) {
const existingElement = head.children[position];
head.insertBefore(asset, existingElement);
} else {
head.appendChild(asset);
}
}
return href;
} catch (error) {
console.error(`An error occurred while fetching the asset from '${endpoint}': ${error}`);
return null;
}
}

window.getAsset is a way of defining a function that is accessible from anywhere in your code, regardless of the scope in which it was defined.

In JavaScript, the global window object is always present in the browser environment and provides a way to define properties and functions that are accessible throughout your code. By defining getAsset as a property of the window object (window.getAsset), you are essentially making it a global function that can be called from anywhere in your code, even if it's defined within a smaller, more contained scope.

Using window.getAsset can be useful in situations where you need to define a function that needs to be accessed from multiple places in your codebase or across different files. It can also help to make your code more modular and easier to maintain, as it allows you to keep related functions and variables grouped together in logical, self-contained units.

Conclusion

By following this approach, you can include custom JavaScript and CSS files in your Sitecore Content Hub implementation and determine the position to insert them in the page header. This can help you keep your code organized, reduce duplication, and make it easier to maintain your custom code.

Make sure to upload your files as assets in the Digital Asset Management section of your Content Hub instance and make a note of the asset IDs. Then, use the getAsset function to fetch and include the assets in your pages. You can specify the position to insert the elements in the header, or leave it undefined for the default position at the end of the header.

We hope this article helps you include custom JavaScript and CSS files in your Sitecore Content Hub implementation. Let us know if you have any questions or feedback.

From SDL Tridion to Sitecore Content Hub DAM: Our Chef's Journey of Challenges and Rewards


Making a career transition is never easy, but sometimes it's the best thing you can do to advance your career and expand your skill set. This was the case for Our Chef, who spent 10 years working with SDL Tridion CMS before making the switch to Sitecore Content Hub DAM 1.5 years ago. In this blog post, we'll explore Our Chef's journey, the challenges he faced, and the rewards he's experienced as a Sitecore Content Hub DAM developer.

Our Chef was initially apprehensive about the move from SDL Tridion CMS to Sitecore Content Hub DAM. He was used to working with a content management system that had a narrow focus, while Sitecore Content Hub DAM required him to develop a more holistic understanding of how digital asset management fits into the broader context of content strategy and marketing.

At first, it was a bit overwhelming for Our Chef to have to learn new technology and processes, but with time and effort, he quickly adapted to the new environment. He discovered that Sitecore Content Hub DAM offered him a more comprehensive set of tools to work with, which allowed him to be more creative and efficient in his work. He found that Sitecore Content Hub DAM made it easier to collaborate with other teams, as the platform provided a centralized location for all digital assets and a streamlined process for asset review and approval.

One of the biggest challenges of the transition was adjusting to the level of automation that Sitecore Content Hub DAM provides. Compared to SDL Tridion CMS, Sitecore Content Hub DAM is more automated, which meant that Our Chef had to learn how to write automated tests and work with APIs. He also had to learn new programming languages and how to use the latest web development tools.

Despite the challenges, the transition to Sitecore Content Hub DAM has been a rewarding one for Our Chef. He's been able to work on more complex projects that require a higher level of technical expertise, which has helped him grow professionally. He's also been able to collaborate with other teams and departments, which has given him a broader perspective on how digital assets fit into the larger picture of content strategy and marketing.

Conclusion

Making the transition from SDL Tridion CMS to Sitecore Content Hub DAM requires hard work and dedication, but it's a journey that can lead to great rewards. For Our Chef, the switch has provided new challenges and opportunities to grow and develop professionally.

If you're considering a similar transition, don't be afraid to take the leap and explore the exciting possibilities that Sitecore Content Hub DAM can offer.


Thursday, February 16, 2023

From Code to Cuisine: A Day in the Life of a Sitecore Content Hub DAM Chef


Imagine you're a Sitecore Content Hub DAM developer, and your latest project involves working with the Restaurant of Mistaken Orders. The restaurant has hired you to help manage their digital assets, including the images and videos they use on their website and social media channels. As the restaurant's go-to technology expert, it's your job to ensure that everything runs smoothly and that their online presence is consistent with their brand image.

At 9:00 am, you arrive at your office and start your day with a cup of coffee. You check your email, and there it is: a new requirement from the Restaurant of Mistaken Orders. Their marketing team wants all social media assets to be reviewed and approved by the marketing department before being published. It's your job to make it happen.

At 9:30 am, you dive into the code, creating a new workflow in Sitecore Content Hub DAM that requires the review and approval of social media assets. It's a complex task, but you know that you need to get it right to ensure the success of the restaurant's online presence.

At 11:00 am, you create a custom validation rule that checks for specific brand guidelines. The restaurant's visual identity is critical to their success, so this is an essential step to ensure that all assets meet their branding standards.

At 12:30 pm, it's time for lunch. You could go out to eat with your colleagues or bring your own food from home. But today, you're feeling inspired by the Restaurant of Mistaken Orders, so you decide to order their signature dish: a miso-glazed salmon that's both tasty and satisfying.

At 1:30 pm, you start working on a custom report that provides the marketing team with detailed information on the status of social media assets in the validation process. The report is a crucial component of the workflow, as it helps the team to stay on top of the review process and ensure that assets are published on time and on-brand.

At 3:00 pm, you test the workflow and validation rule that you created. It's always nerve-wracking when you're testing a new system, but you're confident that you've done everything right. Sure enough, everything works as expected, and you're able to sign off on the project with confidence.

At 4:00 pm, you wrap up for the day. You've accomplished a lot, and you're proud of the work you've done for the Restaurant of Mistaken Orders. You're already looking forward to the next challenge that the restaurant will throw your way.

In conclusion, a career as a Sitecore Content Hub DAM developer is an exciting and rewarding opportunity for anyone with a passion for technology, problem-solving, and collaboration. By working closely with stakeholders like the Restaurant of Mistaken Orders, you can help ensure that their digital assets are always on-brand and of high quality. Just like the chefs at the restaurant, you need to pay attention to detail, anticipate problems, and deliver high-quality results to ensure that the digital assets are consistent with the restaurant's image and goals.

Wednesday, February 15, 2023

Get Your Video and Subtitle Fix with Sitecore Content Hub DAM - A Tasty Technical Treat



Welcome to the "Restaurant of Mistaken Orders" blog! Today, we're serving up a technical dish with a side of humor.

Our dish for today is a JavaScript function that can fetch any asset, not just videos and subtitles. It's a generic function that you can reuse in your own recipes.

Let's take a closer look at the ingredients in this code:

function getAsset(endpoint, rendition) {
return $.ajax({
url: endpoint,
method: 'GET',
})
.then(asset => {
if (asset && asset[rendition] && asset[rendition][0] && asset[rendition][0].href) {
return asset[rendition][0].href;
} else if (asset && asset.renditions && asset.renditions[rendition] &&
asset.renditions[rendition][0] && asset.renditions[rendition][0].href) {

return asset.renditions[rendition][0].href;
} else {
return null;
}
})
.catch(error => {
console.error(`An error occurred while fetching the asset from '${endpoint}': ${error}`);
return null;
});
}

The getAsset function takes two parameters: endpoint and rendition. The endpoint is the URL of the asset you want to fetch, and the rendition is the specific format of the asset, such as video_mp4 or webvtt.

The function uses the $.ajax method to fetch the asset from the endpoint. The $.ajax method returns a Promise that resolves to the asset data.

Once the asset is fetched, the function checks if the asset has a rendition property and if it has a href property. If it does, the function returns the href property, which is the public URL of the asset. If the asset doesn't have the required properties, the function returns null.

In case of an error while fetching the asset, the function logs an error message to the console and returns null.

Next, we have the following code:

var currentUrl = window.location.href;
var assetId = currentUrl.split("/").pop().split("?")[0];

$(document).ready(async function() {
if (!assetId || assetId.length === 0) {
return;
}

const videoHref = await getAsset(`/api/entities/${assetId}`, 'video_mp4');
if (videoHref) {
console.log(`Video URL: ${videoHref}`);
}

const relationHref = await getAsset(`/api/entities/${assetId}/relations/AssetToSubtitleAsset`, 'children');
if (relationHref) {
const subtitleAssetId = relationHref.split("/").pop().split("?")[0];
if (subtitleAssetId && subtitleAssetId.length > 0) {
const subtitleHref = await getAsset(`/api/entities/${subtitleAssetId}`, 'webvtt');
if (subtitleHref) {
console.log(`Subtitle URL: ${subtitleHref}`);
}
}
}
});

The `currentUrl` variable holds the current URL of the page, and the `assetId` variable is the ID of the asset we want to fetch. 

The code inside the `$(document).ready` function is executed when the document is ready. The function first checks if the `assetId` variable is set and if it's not empty. If it's not set or empty, the function returns without doing anything. 

Next, the function uses the `getAsset` function to fetch the video asset and the subtitle asset. The `videoHref` variable holds the public URL of the video asset, and the `subtitleHref` variable holds the public URL of the subtitle asset. If the URLs are set, the function logs the URLs to the console. 

And that's it! With this code, you can easily get the public URL of any asset in Sitecore Content Hub DAM. 

So, the next time you receive an order for a video with subtitles, don't worry! Just whip up this code and serve it up like a pro! 

Bon appétit!

Sunday, February 12, 2023


Welcome to the "Restaurant of Mistaken Orders", where our Chef serves up the finest code snippets for developers. Today, the Chef is proud to present a new creation that's been a lifesaver for many developers, and it's called waitForElm.

Let's take a closer look at the waitForElm recipe created by our Chef and see how it works under the hood.

The function starts by returning a Promise, which is a key ingredient in handling asynchronous operations in JavaScript. Promises are used to represent the eventual completion or failure of an asynchronous operation. In this case, the Promise represents the completion of finding the element we're looking for.

The Promise constructor takes in a function as an argument, which will be executed immediately. This function is called a resolver, and its purpose is to determine when the Promise should resolve. In our case, the resolver checks if the element we're looking for is already present in the document. If it is, the Promise resolves immediately with the element.

If the element is not found, we create a MutationObserver, which is an object that can be used to observe changes in the DOM (Document Object Model). The observer is passed a callback function that will be called whenever a mutation occurs in the document. In our case, the callback function checks if the element we're looking for is present in the document. If it is, the Promise resolves with the element, and the observer is disconnected.

A breakdown of the code:

// Use the function to wait for the external component to load

waitForElm('.component-container').then(elm => {
        console.log('Cook up some delicious code with the component');
});

//waitForElem function

function waitForElm(selector) {

    return new Promise(resolve => {

        // Check if the element is already present in the document

        if (document.querySelector(selector)) {

            return resolve(document.querySelector(selector));

        }

        // Create a MutationObserver to continuously monitor the document

        const observer = new MutationObserver(mutations => {

            // Check if the element is present in the document

            if (document.querySelector(selector)) {

                // Resolve the Promise with the element

                resolve(document.querySelector(selector));

                // Disconnect the observer

                observer.disconnect();

            }

        });

        // Start observing the document
        observer.observe(document.body, {
            childList: true,
            subtree: true

        });
    });
}

The observe method takes in two arguments: the target node to observe and an options object. In this case, we're observing the document.body node and setting the childList and subtree options to true. This means that the observer will be notified of changes to the body of the document, including changes to its children and descendants.

So, now you have a better understanding of how the waitForElm recipe works. It's a simple but powerful tool that can help you write more efficient and reliable code when working with dynamic web pages and external components.

In conclusion, the waitForElm function is a must-have recipe in every developer's kitchen. Whether you're working with Sitecore Content Hub or any other dynamic web platform, this function can save you time and effort by ensuring that you can interact with elements only when they are ready. So, next time you're working on a project that requires waiting for elements to load, remember the waitForElm function created by our Chef, and avoid the frustration of mistaken orders!