Content Dialog

This feature is available on Beefree SDK paid plans only.

The problem

When designing a message or a landing page with Beefree’s editors, there might be cases in which users of your application insert a merge tag, add a link to an image, or apply a conditional statement.

It’s all good until things scale up. For example…

  • What if you have 400 merge tags? You can feed an array of merge tags to the editor, but that’s not going to cut it.

  • What if it’s a 6,000 product database? How will they locate the right one? Special Links is not the right fit.

  • And what if a display condition needs to be built on-the-fly?

A flexible solution

Since the Beefree builders are used in hundreds of applications, and since each of them is facing different user experience challenges like the examples mentioned above, we decided that this was really a case where one size does not fit all.

So we engineered a solution that puts you in control and provides a large amount of flexibility.

If your users want to insert a merge tag or a display condition, you control how that will happen. You can overlay a window on top of the editor, for example, and display a simple search box, a list of categories to browse, or a complex configurator to build an advanced conditional statement.

We call this feature Content Dialog.

An interactive UI layer

Content Dialog allows you to build user interfaces for your users to locate & insert merge tags, links, conditional statements, and more. It lets you establish an interaction layer between the editor and your application (e.g. you show a pop-up window) that allows your users to locate/build/insert specific content (merge tags, links, conditional statements, etc.). And you’re in full control of the UI.

For example, imagine you want your customers to be able to quickly locate a link to a product page and assign that link to a button, image, or text. Content Dialog will let you build the right user experience.

Here is a visual example of what you could accomplish in that find a product link scenario.

The user experience in this interaction layer is entirely up to you. In the example above, the user clicked on “Find a product” (or alike) in the editor, and a modal window was shown, with a search box in it. Since you decide what the user experience will be like, you are fully in control of how users will select and insert:

For each type of content, you can define the action that will be triggered in your application (e.g. display a modal window), and the text that will be displayed in the Beefree SDK editor’s UI to trigger that action (e.g. “Locate a merge tag”), keeping a consistent UX with other areas of your application.

What it does

Content Dialog introduces new call-to-actions in the editor UI.

Depending on the type of content, the call-to-action will be rendered as a button, a link, or a drop-down choice (see below a detailed list of UI changes).

The text for the action is defined by the host application, so you can use your own wording to provide a better experience.

An example of a possible workflow when the user clicks on a content dialog action:

  1. The editor will start waiting mode (same as when the save action is triggered)

    • This mode prevents users from further editing and keeps the focus on the user selection

    • The waiting mode is interrupted if the host application cancels the action

  2. The host application will display to the user a UI element to select or define a content item

  3. When the selection is done, the host application closes the UI and passes it to the editor

  4. The editor receives from the host application the selected content and exits waiting mode

  5. The content is applied to the selected item

The same example applied to special links (link to a product) in a text selection:

  1. The editor starts waiting mode

  2. The host application displays an overlay that hides the editor and lists the categories of products to link. The user browses them to find the desired product and selects it.

  3. The editor receives the link and exits waiting mode

  4. The link is applied to the selected text

How it works

To set up content dialogs you will need to add the contentDialog object to beeConfig:



contentDialog: {
	specialLinks: {
		label: 'Custom text for links',
		handler: function(resolve, reject) {
			// Your function
		}
	},
	mergeTags: {
		label: 'Custom text for merge tags',
		handler: function(resolve, reject) {
			// Your function
		}
	},
	mergeContents: {
		label: 'Custom text for merge contents',
		handler: function(resolve, reject) {
			// Your function
		}
	},
	rowDisplayConditions: {
		label: 'Custom text for display conditions',
		handler: function(resolve, reject, currentCondition) {
			// Your function
		}
	},
	externalContentURLs: {
            label: 'Custom text for custom rows',
            handler: function(resolve, reject) {
                // Your function
        }
    },
	saveRow: {
    	handler: function (resolve, reject, args) {
        	// Your function
    	}
	},
    editSyncedRow: {
	    label: 'Custom text for synced rows',
        description: 'Custom description for synced rows',
	    notPermittedDescription: 'Custom description for synced rows when not permitted',
        handler: function (resolve, reject, args) => {
        	// Your function
    	}
    }

}

For rowDisplayConditions, there is a third parameter called currentCondition. Use this parameter to return a row's current display condition. This parameter returns an object with the following format:

{
    label: '',
    description: '',
    before: '',
    after: '',
    type: 'BEE_CUSTOM_DISPLAY_CONDITION'
}

Note: You do not have to name the parameter currentCondition. You can use any name that works best for your application and workflow.

You can add all the dialogs, some of them or only one. Is up to your application to create them for all the users or a segment, as there are no related server-side settings, you can customize them for each editor start.

All the dialogs use the same pattern, but the returned object must match the element pattern (described in the following section).

label

Defines the text displayed in the editor UI.

handler

Is a function with a Promise-like signature. This function lets you use your own logic to retrieve the desired value. Once the value is available, you must call the resolve(value) function to pass it to the editor. In case you want to cancel the operation, call the reject() function.

A resolve or reject call is mandatory. If you miss this step, the editor will remain in waiting mode. Error management on the host application must call the reject function to unblock the editor.

Examples



contentDialog: {
  specialLinks: {
    label: 'Add an Example Link',
    handler: function(resolve, reject) {
      resolve({
        type: 'custom',
        label: 'external special link',
        link: 'http://www.example.com'
      })
    }
  },
}

A very simple example of how to apply a Special link.

When the user clicks on Add an Example Link, the URL http://www.example.com is applied to the selection (a button, an image or a text).

The waiting mode will not be perceived, and there is no cancel action.



contentDialog: {
  specialLinks: {
    label: 'Add an Example Link after 2 seconds',
    handler: function(resolve, reject) {
      setTimeout(function() {
        resolve({
          type: 'custom',
          label: 'external special link',
          link: 'http://www.example.com'
        })
      }, 2000)
    }
  },
}

Same as the previous example, but the waiting mode will display for two seconds before applying the URL.

Opening a dialog UI element



contentDialog: {
  specialLinks: {
    label: 'Custom text for links',
    handler: function(resolve, reject) {
      openMySpecialLinkDialog() // Replace this with your application function
        .then(specialLink => resolve(specialLink))
        .catch(() => reject())
    }
  },
},

In this example the openMySpecialLinkDialog() should be replaced with a function that opens a modal window (or other element) of the host application, where the user can select or build a link.

The selection is then returned as the value of specialLink to the resolve() function.

A cancel action will trigger the reject() function instead.

Returned value syntax

Values must use the same pattern used in the beeConfig object.

The returned object is validated against the expected format.

If the validation fails, an error will be returned in the browser console:

E.g., Error getting content rowDisplayConditions, the item is malformed.

These errors will not trigger any visible notification in the UI.

Configuration



contentDialog: {
	mergeTags: {
		label: 'Apply dynamic syntax',
		handler: function(resolve, reject) {
			//your function goes here
		}
	},
},

You can add a new action, available in the text toolbar, and associated with the merge tag element:

Most common use cases:

  • Your application has a high number of placeholders and needs to provide a categorization or search form

  • Placeholder availability depends on options that the user can select while building the message

  • You want to display the same UI your users already know and use in your application

  • You need to separate merge tags from other text placeholders

Value

{
	name: 'Placeholder name', // Will not be shown
	value: '{{ syntax }}' // Text string that will be added
}

The name parameter may be later displayed if the user selection is saved and loaded in beeConfig on subsequent requests.

Configuration


contentDialog: {
	specialLinks: {
		label: 'Search a post link',
		handler: function(resolve, reject) {
			//your function goes here
		}
	},
},

Links are applied to different contents, so, when you define a link dialog action, it will be displayed in:

The text-toolbar, as happens with merge tags

An image or button action

Most common use cases:

  • Apply links to products or news using a categories pattern, a search form, or a visual browser

  • Apply special parameters or configuration to certain links with a wizard or form

  • You want to display the same UI your users already know and use in your application

Value

{
    type: 'A link type', // will not be shown
    label: 'Text', // Will be used as default text when text is not selected
	link: 'http://...' // The URL that will be applied. Placeholders can be used
}

The type parameter may be lately displayed if the user selection is saved and loaded in beeConfig on later requests.

Merge contents

Configuration


contentDialog: {
	mergeContents: {
		label: 'Set up a new product recommendation',
		handler: function(resolve, reject) {
			//your function goes here
		}
	},
},

The content dialog adds a button to the merge content list:

Most common use cases:

  • Set up the content and/or layout for a product recommendation

  • Set up the content and/or layout for a dynamic advertising

  • Set up the content and/or layout for another type of targeted content

Notice that, to display the Dynamic content tile in the contents panel, you must configure mergeContents in beeConfig with at least one predefined item.

Value


{
	name: 'Content name', // Will be displayed in the editor UI and in the message
	value: '{{ syntax }}' // Text string that will be added to the HTML output (will be show in the preview)
}

Display conditions

Configuration

contentDialog: {
	rowDisplayConditions: {
		label: 'Open builder',
        handler: function(resolve, reject) {
			//your function goes here
        }
    },
},

A new button will be available in the display condition widget. In this example, the button says “Open builder”, which is the label shown in the JSON configuration file shown above.

Most common use cases:

  • Display a condition builder or form to target a segment of recipients

  • Display a form to create a loop with the row dynamic contents, as product recommendations

Value

{
	type: 'A category for this condition', // Will not be shown
	label: 'Condition', // Will be displayed as the condition name
	description: 'Small text describing what the condition does', // Will be displayed in the editor UI to identify the condition action
	before: '{% if something == \'Condition\' %}', // Will be added before the selected row
	after: '{% endif %}', // Will be added after the selected row
}

The type parameter may be later displayed if the user selection is saved and loaded in beeConfig on subsequent requests.

An example

In this example, a window is shown to users when they click on the button to open the builder.

The UI is entirely up to the hosting application. Here, the developer decided to offer some fields at the top where the Display Condition can be named and described, an area below it where parameters, values, and operators can be selected, and a preview on the right.

When users click on “Confirm”, the information is passed back to the editor and shown in the properties panel.

Of course, it can be edited in the editor like any other Display condition, if the user has the rights to do so.

Reference our Advanced Permissions documentation to learn more about managing the visibility of the Add Condition and Edit Condition buttons.

Custom rows

Configuration

contentDialog: {
    externalContentURLs: {
            label: 'Search products',
            handler: function(resolve, reject) {
                // Your function
        }
    }
}

The content dialog adds a new item, using your text label, in the Rows drop-down:

Most common use cases:

  • Import a set of products or news, as custom rows, using a categories pattern, a search form, or a visual browser

  • Set up the row layout for a set of predefined contents

  • Set up rows with dynamic content to build dynamic sections that provide product recommendations, QR or bar codes, advertising content, etc.

Value

{
    "name":"Results name", // Will be added as a new choice in the rows drop-down
    "value":"https://..." // Will be used to get the list of rows
}

This response will:

  1. Create a new drop-down choice with the provided name

  2. Display the rows provided by the URL in the rows panel

Notice that in the rows list, names returned by the content dialog display as highlighted elements to give them further visibility over starting choices.

The content dialog can be used as many times as the user needs and, depending on the response, the behavior may change:

1. Returning the same name

This overwrites the existing results, keeping the same name in the drop-down. This behavior perfectly matches our example above, where the host application returns “Your search results” every time the content dialog is resolved.

2. Returning a new name

This creates a new drop-down choice, keeping the previous results as selectable elements. Previous results are available directly in the drop-down. Usage example:

Synced Rows

Configuration

contentDialog: {
    editSyncedRow: {
		label: 'Edit synced rows',
		description: `This row is used in other designs.
					  You can decide to update all the designs or transform this single row into a regular one`,
		notPermittedDescription: `This row is used in other designs.
                                  Your plan does not permit you to edit it. Please contact your account administrator`,
        handler: function (resolve, reject, args) => {
        	resolve(false) // the boolean will be the value of  'Label of the sidebar button that triggers the contentDialog'`synced`
                           // if false the row will be un-synced, if true nothing will happen.
    	}
    }
}

The label, description and notPermittedDescription fields handle the wording related to the “Edit synced row” call-to-action/button. Here’s how and where they are used:

  • label: Label related to the sidebar button that triggers the content dialog

  • description: Description of the action on top of the button

  • notPermittedDescription: Description of the action when the button is hidden from the dedicated advanced permission

Here’s an example of what label and description would look like:

And here’s an example of what notPermittedDescription would look like:

Save rows

Configuration

contentDialog: {
    saveRow: {
        handler: function (resolve, reject, args) {
            // Your function
        }
    }
}

Unlike the rest of content dialog configurations, Save rows doesn’t use the label parameter as the UI element is a save icon displayed on the selected row (and in the row’s properties panel):

The Save rows content dialog is a mandatory step in the Save rows workflow.

The resolve function must return metadata for the selected row. The metadata section of the rows schema allows you to keep track of row-specific information.

The args object in the handler function returns to the host application metadata already applied to the selected row.

Value



{
    "name":"Row name", // Mandatory metadata
    "Category":"A row category" // If you provide category management for saved rows
    "...":"..." // You can add as metadata as your application needs
}

This response will provide metadata that is added to the row in the asset (email, page, popup) before it’s provided through the Save Rows callback.

The row name is the only required metadata and it’s displayed as the row title in the Rows panel:

  • A string of plain text that identifies the row.

  • Displayed in the row card when the row is shown in the Rows panel.

  • Used for text searches within the Rows panel

Check the Saved rows metadata section for further details on recommended metadata.

Forms

Configuration

manageForm: {
	label: 'Edit form',
	handler: async (resolve, reject, args) => { 
		// Your function
	} 
},

If you want to have total control on the forms that a Beefree application displays and renders, you can use this forms Content Dialog rather than passing a single form to the Beefree application.

The forms Content Dialog works the same way as the previous Content Dialog for the saved rows – but in this case, the resolve function should return the structure for the desired form.

The args object in the handler function returns to the host application the form object already applied. With this information, the application can decide what to display to the user (e.g., edit the current form, suggest a similar form, etc.).

To understand how this data is structured, refer to the form structure page on this website.

Custom attributes

Configuration

        customAttribute: {
          label: 'Search Attributes',
          handler: (resolve, reject) => {
            resolve({
              key: '2783f0ea-f6af-44f3-856e-d7a01cd87714',
              name: '100% Custom',
              value: 'My custom value',
              target: 'link',
            })
          }
        },

If your end users need to apply custom attributes to the links and images in their content, you can completely customize the user experience and workflow for adding those attributes with a Content Dialog that will take over the editor’s UI. The dialog will need to return the attribute to apply.

Custom video

Configuration

addVideo: {
  label: 'Choose a video',
  handler: async (resolve, reject) => {
    resolve({
      videoSrc: 'https://link.to.your.custom.video', // mandatory
      thumbSrc: 'https://my.beautifulimages.com/thebest.jpg', // mandatory
      thumbAlt: 'The title of my custom video!', // optional
    })
  }
}

It is possible to leverage the Content Dialog method to add videos from custom sources – other than YouTube and Vimeo.

You can use the addVideo Content Dialog modal, which will take over the builder’s UI. The video will be added as a thumbnail in the content area.

The user must fill out the video URL from a custom source, the image used as a thumbnail, and an alt text/title by implementing a custom modal window (optional). When the user clicks on the video thumbnail, it will open videoSrc in a new tab/window.

Last updated

Logo

© Bee Content Design, Inc. San Francisco, CA | Part of Growens