Text with Media
  • 15 Oct 2024
  • 4 Minutes to read

Text with Media


Article summary

One of the simplest and most common use cases for templates is to let the end user type in some text and optionally upload a picture or video.

The Text with Media design pattern is provided as a “best practice” on how to implement templates with:

  • One or more text fields.

  • One media field, which may support both picture and video files.

  • The media may be optional, and the template may use different layouts depending on whether a media file was uploaded or not.

  • If the media file is a video, the template will use the video’s duration. If the media file is a picture, or no media file is provided, the template will use the duration provided by the user (or a default duration).

This design pattern applies equally well to some different variations of the use case:

  • A static background image with text and media on top

  • Media is displayed in full screen with text added on top (a default background could be used if no media is uploaded)

In this article, we present the full code for a sample template of the former variant, i.e with static background image:

Note how the layout changes depending on the media; the text box is wider and starts more to the left when there is no media.

template.json

{
    "name": "Demo Template",
    "contentBasePath": "",
    "application": "template.html",
    "options": {
        "apiVersion": 2,
        "templateVersion": 3,
        "defaultDuration": 10,
        "targetWidth": 1920,
        "targetHeight": 1080,
        "scalePreview": true,
        "scalePlayer": true,
        "allowReuse": false,
        "enableAltMedia": false
    },
    "fields": [
        {
            "type": "text",
            "key": "heading",
            "caption": "Heading",
            "default": "",
            "required": true
        },
        {
            "type": "textarea",
            "key": "body",
            "caption": "Text",
            "default": "",
            "required": false
        },
        {
            "key": "media",
            "caption": "Picture or video",
            "type": "content",
            "required": false,
            "options": [
                {
                    "path": "/Media"
                },
                {
                    "path": "/"
                }
            ]
        }
    ]
}

template.html

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Info</title>
    <link rel="stylesheet" href="css/template.min.css" type="text/css" />
    <script src="template.js"></script>
</head>
<body>
    <div class="text">
        <div id="Heading"></div>
        <div id="Body"></div>
    </div>
    <div id="MediaContainer"></div>
</body>
</html>

Less (compiled to css)

html, body {
    font-family: Arial, Helvetica, sans-serif;
    color: white;
    font-weight: bold;
    display: flex;
}
body {
    background-image: url('../assets/Back.png');
}
.text {
    position: absolute;
    display: flex;
    flex-direction: column;
    left: 442px;
    top: 280px;
    width: 1328px;
    max-width: 1328px;
    height: 1080px - 2 * 280px;
    #Heading {
        color: orange;
        font-size: 60px;
        padding-bottom: 0.25em;
    }
    #Body {
        white-space: pre-wrap;
        font-size: 45px;
    }
}
#MediaContainer {
    position: absolute;
    top: 100px;
    bottom: 100px;
    left: 100px;
    width: 600px;
    overflow: hidden;
    visibility: hidden;
    z-index: 1;
}

@import "../../../templateframework/Media/Media";
    .withMedia {
    #MediaContainer {
        visibility: visible;
    }
    .text {
        left: 800px;
        width: 960px;
        max-width: 960px;
    }
}

TypeScript

interface CMSData {
    heading: string;
    body: string;
    media?: {
        url: string;
    }
}
class View extends Dise.SimpleViewBase {
    async main(helper: Dise.DataHelper): Promise<void> {
        const data: CMSData = helper.content;
        let duration = helper.getDuration(10);
        document.getElementById('Heading').textContent = data.heading ?? null;
        document.getElementById('Body').textContent = data.body ?? null;
        let mediaHandler: Dise.Media.MediaHandler;
        if (data.media?.url) {
            const mediaContainer: HTMLElement = document.getElementById('MediaContainer');
            [mediaHandler, duration] = await Dise.Media.preloadMedia(mediaContainer, {
                url: data.media.url,
                duration: duration,
                aspectMode: Dise.Media.AspectMode.letterbox,
            });
            if (mediaHandler)
                document.body.classList.add('withMedia');
        }
        await this.waitForPlay({
            duration: duration,
            suggestedNextPreload: duration / 2,
        });
        await mediaHandler?.start();
    }
}
const ctrl = new Dise.TemplateController(new View());


Was this article helpful?

What's Next
Changing your password will log you out immediately. Use the new password to log back in.
First name must have atleast 2 characters. Numbers and special characters are not allowed.
Last name must have atleast 1 characters. Numbers and special characters are not allowed.
Enter a valid email
Enter a valid password
Your profile has been successfully updated.