Skip to main content

Deck-wide editing

This feature allows authorised users to edit the copy and images of a deck for all presos created from that point on. Its primary function is to remove the need for clients to commission content developers for simple stats updates or minor copy changes. This guide will go through the steps required to activate, implement and test this feature, as well as detail various gotchas to watch out for.

image

Deck-wide (aka. Companywide) editable works by looking for data-companywide-... tags on DOM elements, and applying logic based on the type of tag (see [companywide reference] in for a full list of tags). These tags dictate how PresoManager and the app interact with editable elements, and are the primary tool for developers in implementing Companywide editable in a deck.

info

A companywide field needs to be present in the slide's index.html file for it to become editable in PresoManager. If the field needs to be added to the DOM after the slide's HTML is loaded, we can use a placeholder read-only field in the index.html then inject the editable field later. See Injecting companywide edited copy for the steps involved in this process.

Read on to learn how to set up your project for companywide editable.

Making copy editable

This guide is all about text. In here you'll learn how to make a copy element editable, a trick to deal with formatting, and a few useful CSS properties to keep your slides working properly.

Usage

Tagging an element as editable is as simple as adding an attribute to the HTML. For copy, that attribute is data-companywide-editable. Due to what happens in the background to make it editable, this attribute needs to be added directly to the element that will contain the text, like this:

<div data-companywide-editable="{key}">
<!-- initial text here -->
</div>

Note the use of the {key} being assigned to the attribute. This is used by the app to determine what text belongs to each element, and is required to make the feature work. In most cases this key will be unique across the entire deck, although it is possible for multiple elements to use the same key (see linking for more info).

At the simplest level, this is all that's required to make text editable using this feature. However, things become a bit more complicated when you're dealing with more complex HTML structures. Below we'll detail a few things to look out for and how to get around them.

warning

Due to the way companywide editable works, any HTML tags inside an editable element that are not associated to a declared rich-text option will get stripped after you edit it. This means you can't have nested HTML inside a companywide editable field, such as <strong> and <ul>, unless the style and list toolbar options have been specified.

Read the formatting & rich text section below to find out more about what rich-text options are available.

Formatting & rich text

image

By default, an editable text area won't have any formatting options; it'll just be a plain text box with undo and redo buttons. If you include the data-toolbar attribute, however, and add the appropriate values, you can define different toolbars for each text area in your deck.

<div data-companywide-editable="{key}" data-toolbar="format style color">
<!-- initial text here -->
</div>

Toolbar options

Include one or more of the following in the data-toolbar attribute (space separated) to customise your toolbar. Tool sets are displayed in the order you write them.

  • format - dropdown with block-level formats (ie. normal, heading1, monospace etc. see below about customising options)
  • list - unordered list and ordered list
  • style - Bold and Italic buttons
  • color - text color selection (see below about customising options)
  • superscript - superscript and subscript options for raised and lowered smaller text
  • align - horizontal text alignment
  • link - "Insert/edit link" button and "Remove link" button
  • removeformat - clear format button
info

The order in which toolbar options are declared is the order they will be rendered in. For consistency across your content, the same order should be used for each toolbar instance you declare.

We recommend the following order:

format list style color superscript align link removeformat

Customising colours and formats

You can define the colours and block formats available for your deck by adding the content_editors text attribute to your project.yaml file.

These options are shared by every toolbar in the deck. It's not currently possible to have different colour palettes for each text area.

companywide_editable: true
contenteditable: true
content_editors:
text:
colors:
- color: "000000"
title: "Black"
- color: "FF0000"
title: "Red"
- color: "00FF00"
title: "Blue"
- color: "0000FF"
title: "Green"
formats:
- block: "p"
title: "Normal"
- block: "h1"
title: "Heading 1"
- block: "h2"
title: "Heading 2"
- block: "h3"
title: "Heading 3"
- block: "blockquote"
title: "Blockquote"
- block: "pre"
title: "Monospace"

You can define up to 25 custom colours, but formats are limited to a subset of ["p", "h1", "h2", "h3", "h4", "h5", "h6", "pre", "monospace", "blockquote"]

We recommend setting the colours list to the colour palette already used in the deck, and the formats to only those that you have defined css styles for.

Caveats

Having powerful rich-text editing means inserting and altering HTML as you type. With this in mind, There are a few things to be aware of when writing stylesheets for this content

Paragraphs vs. Line breaks

By default, line breaks are handled with a <br /> tag. If you request block-level toolbar options ("list" and "format") each new line will creat a new <p> tag instead.

Sanitized HTML

When HTML is pasted in from an external source, or when the textarea first loads, we'll sanitize the contents for only those tags, styles and attributes the editor needs (based on the toolbar). This keeps the content free from any bugs or unintended presentation. So if you don't add lists to your toolbar options, <li> tags will be stripped out.

Non-DIV editable fields

While any html tag can be used as an editable field with a toolbar, only <div> tags can have the "list" or "format" options. If you attempt to add these options, they'll be removed, and depending on the development environment, a console error will be thrown.

We recommend only using tags such as <h3>, <p> and <div> for editable text areas. Other HTML elements, like <li> tags, can have limited rich-text-editing functionality.

Injecting companywide edited copy

Companywide fields will self-manage if they are declared in the HTML of a slide, but doing that isn't always feasible. Because injecting HTML is relatively common in the sliderendered or slideready events, we have a step-by-step process below for when you want to make one of these injected elements companywide editable. This process makes use of Bridge.Companywide, so make sure you check it out before continuing.

Step 1 - Create a read-only element in the HTML

The first step is to create a read-only element in the HTML. It will have the same companywide data tag and data key that we will use in our injected field later. This field should be hidden from the user and will remain read-only throughout this process.

Example read-only fields:

<div data-companywide-editable="cwe-text" data-readonly></div>
<div data-companywide-dynamic-image="cwe-image" data-readonly></div>
<div data-companywide-youtube-player="cwe-youtube" data-readonly></div>

Step 2 - Inject our editable field into the DOM

We can use JavaScript to inject a field during the sliderendered or slideready events, or later as a result of user interaction. Our injected field must have the same data tag and key as our read-only field from the previous step. If the user is editing the slide in PresoManager, this field will automatically become editable and it will be given a value if one exists for its data key.

// Read-only field in index.html hidden by CSS
<div data-companywide-editable="cwe-text" data-readonly></div>
...
// Editable field injected later with JS
<div data-companywide-editable="cwe-text">Field value</div>

Step 3 - Retrieve the Companywide values using Bridge

When the slide is loaded outside of PresoManager's edit mode, the injected fields will not be populated automatically. We need to retrieve their saved values and pass them into our injected elements. For that, we can take our field's data key and use Bridge.Companywide.get(key). If a saved value exists, it will be returned in this format:

// Bridge.Companywide.get(key)
[
{
created_date: string,
deck: string,
id: number,
key: string,
mime: string,
modified_date: string,
scope: string,
team: number,
url: string,
user: string,
value: string,
},
];

We can ignore everything other than the value property. The value will be the data that the user has entered in the field in PresoManager's edit mode. All we need to do now is pass the value to our injected element.

Bridge.Companywide.get(key) will always return the latest value for the key's field, even while the user is editing the field. If there is no value for the provided key, either because the key doesn't have a corresponding field or because the user hasn't modified the field in PresoManager yet, Bridge.Companywide.get(key) will return undefined. It is recommended that a default value be provided along with the key to make it easier to handle the instances where no value is returned.

E.g.

var defaultValue = {
value: "Placeholder"
};

var companywideValue = Bridge.Companywide.get(key, defaultValue);

// Now we can use companywideValue.value without checking whether companywideValue exists
var value = companywideValue.value;

Here's an example of what a finished product might end up looking like:

<article id="slide_id">
<section class="content">
<section class="content-body">
<div data-companywide-editable="editable_key" data-readonly></div>
<div class="container"></div>
</section>
</section>
</article>

<script type="text/javascript">
$("#slide_id").on("sliderendered", function () {
var $pageContainer = $("#slide_id");

$pageContainer.on("slideready", function () {
var myKey = "editable_key"; // same key we assigned to 'data-companywide-editable' in the HTML
var cweValue = Bridge.Companywide.get(myKey, {value: "Hello!"});

var $callout = $('<div class="callout" data-companywide-editable="editable_key"></div>');
$callout.text(calloutCWE.value);
$(".container", $pageContainer).append($callout);
});
});
</script>

The output:

<article id="slide_id">
<section class="content">
<section class="content-body">
<div data-companywide-editable="editable_key" data-readonly></div>
<div class="container">
<div class="callout" data-companywide-editable="editable_key">Hello!</div>
</div>
</section>
</section>
</article>

Styling & layout

There are a few styling and layout properties that become much more important once something is editable. Allowing users to alter the content of a slide can be a messy business, and we need to tread the line between letting users do what they want and giving them so much freedom that things start breaking. The main purpose of this feature is to let clients take care of minor copy changes and stats updates, so as a general rule users should not be able to drastically alter or break the layout of a slide by making copy changes. There's a certain amount of user responsibility for ensuring that copy changes look appealing, so as long as the user can't break the slide they should have the freedom to do as they please. There's no one way to achieve this, but a few useful CSS properties to keep in mind are:

  • min-width / max-width
  • min-height / max-height
  • position: absolute / relative

Note that width and height properties can't be set on inline CSS elements. We recommend making your text fields display:block or display:inline-block

User feedback

To help communicate a slide's design limitations to the user, we have made the following tags available:

data-warn-on-overflow

By specifying an element's height/max-height and adding the tag data-warn-on-overflow, the user will be shown the warning message "there's not enough room for what you've typed" if the copy they have entered overflows the field.

image

data-scrollup-on-blur

When a height/max-height has been applied to an editable text area the text within will scroll to keep the up with the user's text cursor. This can give the wrong impression to users, as subsequent visits to the slide will have the text area scrolled to the top again. Tagging the field with this attribute helps to better demonstrate the final design as it will automatically scroll the text back to the top as soon as the user clicks out of the field.

Next up, we'll tackle making images editable!

Making images editable

In this guide we go over how to make an image editable, the different types of editable images and how to make the best use of them.

Usage

Much like an editable text field, to tag an editable image you just add the data-companywide-dynamic-image attribute and assign it an ID. For example:

<div class="image" data-companywide-dynamic-image="{key}"></div>

This will assign new images using the background-image CSS property, so the old image will be overridden by the new one. It will keep any other styles applied to it by the slide/global CSS, so use that to decide how the image should behave.

info

For example, you have an editable image that is the background of a section of the slide, so you need it to always cover the entire section. In this case, you would set the background-size property to cover to ensure that any added images stretch to fill the space.

The data-img attribute

By default, data-companywide-dynamic-image adds new images as a background-image of the element, so each time a new image is uploaded the old one is overridden. However, you can also have new images added as the source of individual <img> elements, which get appended to the tagged element. Used like this, the tagged element becomes more of an image container. All you need to do is add data-img to the attributes of the editable element:

<div
class="image-container"
data-companywide-dynamic-image="{key}"
data-img
></div>

Which results in the following when an image is added:

<div class="image-container" data-companywide-dynamic-image="{key}" data-img>
<img src="imgURL_1" alt="" />
</div>

That's it for images! Next up are editable videos.

Embedding YouTube videos

When people think of finding a video online, they think of YouTube. We've made a handy little shortcut to let developers, as well as marketing managers and content owners, easily embed any YouTube video.

Note that this is not just a YouTube Player, but a way for users to add/change YouTube videos themselves, in the same manner they can edit text or images.

Why YouTube?

We use YouTube to drive our editable videos as their API gives us control over video playback and settings where we need it. For example, pausing and restarting a video when the user opens and closes the slide overlay mid-presentation.

Usage

Similar to the editable text and image fields, add the data-companywide-youtube-player attribute to your chosen element and assign it a key. This element will become a wrapper for the YouTube iFrame that is loaded by the component.

<div data-companywide-youtube-player="{key}"></div>

When viewed in the CDK and LivePreso, it'll look something like this:

image

Accepted inputs

When in use, the video component accepts the following inputs:

  • YouTube video IDs
  • YouTube URLs

Styling & layout

When you first add the widget, the YouTube player may appear too small or have the wrong aspect ratio. Every deck will have different requirements, so we've left the styling up to you.

If you're having trouble getting the video to display how you want consistently, here are some tips:

  • You'll want to add styles to both .youtube-widget as well as its contained iframe.
  • Setting a fixed size, rather than a flex or percentage-based size, is recommended.
  • Remember that LivePreso loads one slide before and after the one you're currently looking at, so be aware that any video rendering code could run prematurely.

Templates

One of the best ways to use this feature is with Templates! create a "YouTube Video" template, and your users can insert a slide with a YouTube video anywhere they like in a deck. See the Building templates guide for more info.

Now you have it! An editable YouTube video component that can be used in both Companywide editable slides and Templates.

Read on to learn all about how to link two or more editable elements together.

Utilities

This section contains information about several helper features available to assist in development and enhance the user experience.

Edit mode

This is a class that gets added to the body when a user opens a slide in PresoManager, similar to other modes that get added (see the preso modes overview). We can use it to apply edit-mode specific logic and styles that we only want to show while a user is editing a slide.

Here's what it looks like:

<body class="edit-mode">
<!-- LivePreso -->
</body>

And here's how you would reference it in the slide:

$("#slide_id").on("sliderendered", function () {
var isEditMode = $("body").hasClass("edit-mode");
if (isEditMode) {
// functionality when in edit-mode
} else {
// normal functionality
}
});
.edit-mode #slideshow article#slide_id {
/* classes to apply in edit-mode */
}

Some common uses for this class are:

  • Adding edit-mode specific styles to the CSS/SCSS
  • Populating the slide with dummy data to show the user a real representation of what the slide will look like in prep/present mode
  • Adding a toggle/dropdown to the slide to allow the user to freely access different states of the slide.

See the use-case example discussed in the PresoManager overview for more detail on the toggle/dropdown example.

info

If you decide to add some sort of toggle or other interactive device to a slide, you'll need to make sure it's active in PresoManager. Find out how in Interactive elements in PresoManager below.

Interactive elements in PresoManager

Since the user needs to be able to click on all the editable elements to edit them, we disable all pointer events on the slide in PresoManager. This ensures that the user won't accidentally activate anything while trying to edit it, and because generally speaking the user won't need to access the general functionality of the slide while editing it.

This causes a bit of a problem when we need the user to be able to interact with something on the slide, so we have an attribute that you can add to anything that needs to keep its pointer events in PresoManager: data-companywide-interactive.

Here's how you might use it with an edit-mode toggle:

<div class="edit-mode-toggle" data-companywide-interactive></div>
warning

Be careful how you use this attribute! If you put it on the parent of an editable element or on something that's too close to an editable element, it will be hard for the user to click on it!

Developer Tools

To save time during development, there's a key generator script that you can use to add the ="{key}" part of the data-companywide-.. attribute. Once you've added the attribute to everything you want to make editable, just run the script and it will find everything tagged as data-companywide-editable or data-companywide-dynamic-image that doesn't have a key already and add one. These keys use the slide's ID with a short randomly generated string at the end.

For anything you want to link together, you'll need to manually add the keys so that they are the same. See linking for more info.

info