Lucit Designer Formatting Functions Guide¶
Overview¶
The most powerful JavaScript functions in the Lucit Template Designer are Designer Formatting Functions.
These functions are executed during the template rendering process and can operate on one or multiple elements at the same time.
They also receive more data than standard text formatting functions and can apply to text, image, video, object, and SVG elements.
How Designer Formatting Functions Work¶
During rendering, any Designer Formatting Functions that have been registered with registerDesignerFormattingFunction on the JS tab of the Code Editor are executed.
These functions are applied to elements based on the CSS selector provided when the function is registered. Lucit calls your function once for each element that matches the selector.
Creating a Designer Formatting Function¶
To create Designer Formatting Functions, add them in the JS (JavaScript) tab in the Code Editor at Templates → {Template} → Canvas → Action Bar → <>.
To register a Designer Formatting Function, use registerDesignerFormattingFunction with the following three arguments:
name– A name for the function. Use alphanumeric and_characters only; no spaces or special characters other than_.fn– The callback function that will be executed on each element matched by the selector. It accepts up to four parameters:el– The element that the function is being applied to.dataValue– The value of thedata-valueattribute after macro replacements (or thex-placeholdervalue when macros have not been replaced). For example, ifdata-valueis{item.price}, thendataValuewill be the resolved numeric price.dataObject– IfdataValueis serialized JSON, this will contain the parsed object version of that JSON; otherwise it simply contains an object like{ "value": dataValue }.elementSettings– If the element hasx-element-settingsand the user has configured it to producex-element-setting-values, thenelementSettingscontains a JSON object of key/value pairs for each setting value, or the placeholder if the placeholder was defined for the key inx-element-settings.selector– The CSS selector used to select one or more elements to apply this function to.
Data flow overview
- You set a
data-valueattribute on your element (for example,data-value="{item.price}"). - Lucit replaces any macros in
data-valuewith their actual values. - The resulting value is passed as
dataValueto your function. - If
dataValueis JSON, Lucit parses it and passes the parsed object asdataObject. Otherwise,dataObjectis{ value: dataValue }.
Example – Format price fields in red
In this example, we select by the object code and then format the field in red if the price is less than 30,000.
registerDesignerFormattingFunction(
"makeCheapVehiclesRed",
(el, dataValue) => {
const price = parseFloat(dataValue);
if( price < 30000 ){
el.innerHTML = '<span style="color:red">' + el.innerHTML + "</span>";
}
},
'[x-objectcode="item_price"]'
);
Note that this function does not use dataObject or elementSettings, but it expects that a dynamic element with x-objectcode="item_price" has been added to the template.
Example – Monthly Payment Calculator
This is an example of a configurable monthly payment calculator element.
In this particular case, the {{item.price}} macro is embedded in the JavaScript and not in the HTML of the element.
This shows the power of these functions, as you can embed macros anywhere in the HTML, CSS, or JavaScript as needed.
Also Note, that when uysing macros in JavaScript, we MUST use the double curly brace format like this {{item.price}} not like this {item.price}
The x-element-settings attribute is used by the user editing this template. They can right-click on the element on the canvas, choose Edit Settings, and then configure the values for each one.
<div
id="obj_monthly_payment_123mo_sbhpqzfq"
title="Monthly Payment : $123/Mo"
class="lc_ut_designer lc_dt_element lc_dt_text lc_dt_text_editable lc_format_fit_text"
x-element-settings='{"fields":[{"key":"months","name":"No. of Months","type":"int","placeholder":"60"},{"key":"rate","name":"Interest Rate","type":"float","placeholder":"6.5"},{"key":"prefix","name":"Prefix","type":"text","placeholder":"&#36;"},{"key":"suffix","name":"Suffix","type":"text","placeholder":"\/Month"}]}'
x-fieldname="monthly_payment_123mo"
x-optional-field="false"
x-element-setting-values='{"months":"60","rate":"4.5","prefix":"$","suffix":"/Month"}'
x-placeholder="monthly_payment_123mo">
$123/Mo
</div>
registerDesignerFormattingFunction(
"format_obj_monthly_payment_123mo_sbhpqzfq",
(el, dataValue, dataObject, elementSettings) => {
// At render time, {{item.price}} will be replaced with the numeric item price
const priceRaw = "{{item.price}}";
const price = parseFloat(priceRaw);
const months = isNaN(parseInt(elementSettings?.months))
? 60
: parseInt(elementSettings?.months);
const rate = isNaN(parseFloat(elementSettings?.rate))
? 6.5
: parseFloat(elementSettings?.rate);
const suffix = elementSettings?.suffix ?? "";
const prefix = elementSettings?.prefix ?? "";
if (months <= 0) {
throw new Error("Number of months must be greater than zero.");
}
if (!priceRaw || isNaN(price)) {
return; //No price, so, display placeholder
}
const monthlyRate = rate / 100 / 12;
// If the interest rate is 0%, simple division
if (monthlyRate === 0) {
el.innerHTML =
prefix + Math.floor(price / months).toLocaleString() + suffix;
}
// Formula: M = P * (r(1 + r)^n) / ((1 + r)^n - 1)
const numerator = price * monthlyRate * Math.pow(1 + monthlyRate, months);
const denominator = Math.pow(1 + monthlyRate, months) - 1;
const monthlyPayment = Math.floor(numerator / denominator).toLocaleString();
el.innerHTML = prefix + monthlyPayment + suffix;
},
'[id="obj_monthly_payment_123mo_sbhpqzfq"]'
);
More Complete Example – On Sale Items
In this example, we have a feed that provides a price and an original price.
We use these values to either display or hide both the "on sale" SVG element and the "on sale" text. The item is considered on sale only when item.original_price is greater than item.price.
<div
id="rectangle_default_bg"
title=""
x-objectcode="rectangle"
class="lc_ut_designer lc_dt_object lc_dt_default_background"
x-fieldname="rectangle"
x-optional-field="false"
x-element-settings="{}"
x-element-setting-values="{}"></div>
<div
id="obj_award_1_ae341t49"
title="Award 1"
x-objectcode="award_1"
class="lc_ut_designer lc_dt_element lc_dt_object lc_dt_object_svg on_sale"
style=""
x-fieldname="award_1"
x-optional-field="false"
x-element-settings="{}"
x-element-setting-values="{}">
<svg
width="100%"
height="100%"
viewBox="0 0 1080 1080"
preserveAspectRatio="none"
pointer-events="none">
<path
d="m275.69,171.64c.26-23.01-8.72-48.32,8.82-60.97,23.18-16.71,43.56,5.66,60.46,18.84,46.13,35.96,
67.23,16.72,78.33-31.41,4.54-19.68,5.85-45.81,27.94-50.42,22.22-4.64,35.95,18.58,45.16,35.54,27.48,50.6,
52.62,56.85,82.56,2.32,9.52-17.34,20.53-40.44,43.33-38.45,25.64,2.24,24.46,28.84,28.64,48,10.53,48.27,32.08,
67.86,78.24,33.53,55.3-41.12,77.07-23.23,69.88,41.43-6.02,54.16,20.63,59.63,64.63,47.23,18.07-5.09,40.63-18.91,
57.49-.32,17.74,19.56.91,39.31-9.42,55.23-32.33,49.77-17.9,72.83,38.94,76.59,63.67,4.22,71.8,30.29,24.45,
71.24-46.11,39.89-27.14,61.45,17.43,80.84,18.11,7.88,44.95,12.78,47.22,34.33,3.08,29.2-28.37,32.42-47.66,
41.06-44.74,20.04-62.68,40.74-17.41,81.15,41.76,37.27,48.13,69.57-23.36,71.34-60.14,1.49-60.99,31.16-39.13,
74.66,29.46,58.61,8.48,76.17-49.76,57.67-57.44-18.25-66.88,10.7-63.22,58.1,1.51,19.54,9.43,45.1-10.22,
56.84-21.79,13.02-37.26-10.93-51.64-23.01-46.59-39.13-75.02-33.18-86.67,29.23-3.63,19.46-3.71,45.78-27.36,
50.13-23.43,4.31-34.38-19.87-43.55-36.89-34.55-64.12-61.04-42.34-88.38,5.45-8.55,14.95-19.06,34.97-39.14,
31.78-19.96-3.17-23.71-24.64-26.96-42.1-10.56-56.89-34.04-76.44-86.46-35.66-46.27,36-71.95,21.95-62.62-36.18,
10.64-66.29-14.71-75.22-71.02-56.19-47.06,15.91-71.86,4.45-44.56-50,25.55-50.97,
17.6-81.11-47.08-84.95-66.55-3.95-49.46-38.47-16.41-65.91,50.43-41.87,
42.28-66.42-15.95-86.81-17.95-6.28-43.83-13.12-41.02-38.41,2.47-22.22,26.14-30.99,44.99-36.53,63.22-18.6,
53.67-44.08,12.57-80.11-49.87-43.71-33.1-66.59,26.88-71.3,47-3.69,73.97-17.97,
42.49-70.87-10.59-17.8-31.67-40.36-10.59-61.96,16.33-16.73,39.9-3.84,57.79,2.37,49.54,17.19,75.43,10,61.34-46.47Z"></path>
</svg>
</div>
<div
id="obj_your_new_text_24mnfppl"
title="Your New Text"
x-objectcode="your_new_text"
class="lc_ut_designer lc_dt_element lc_dt_text lc_dt_text_editable lc_format_fit_text on_sale"
style=""
x-fieldname="your_new_text"
x-optional-field="false"
x-element-settings="{}"
x-element-setting-values="{}">
ON SALE NOW!!!
</div>
<div
id="data_source_text_kaxxxzfo"
title=""
x-objectcode="item_title"
class="lc_ut_designer lc_dt_data lc_dt_text lc_format_fit_text"
x-placeholder="Your Caption"
x-optional-field="false"
x-fieldname="Title"
data-value="{item.title}"
x-element-settings="{}"
x-element-setting-values="{}">
{item.title}
</div>
<div
id="data_source_text_yov3y11r"
title=""
x-objectcode="item_price"
class="lc_ut_designer lc_dt_data lc_dt_text lc_format_fit_text lc_format_price_us"
x-placeholder="25968"
x-optional-field="false"
x-fieldname="Price"
data-value="{item.price}"
x-element-settings="{}"
x-element-setting-values="{}">
{item.price}
</div>
registerDesignerFormattingFunction(
"show_on_sale_only_when_discounted",
(el, dataValue, dataObject, elementSettings) => {
// Macros will be replaced at render time with the numeric values
const priceRaw = "{{item.price}}";
const originalPriceRaw = "{{item.original_price}}";
const price = parseFloat(priceRaw);
const originalPrice = parseFloat(originalPriceRaw);
// If we can't parse either value, leave the element visible
if (isNaN(price) || isNaN(originalPrice)) {
return;
}
// Item is considered ON SALE only if original_price > price
const isOnSale = originalPrice > price;
// We hide the .on_sale element when the item is NOT on sale
if (!isOnSale) {
el.style.visibility = "hidden";
}
// If isOnSale is true, we leave it visible as-is
},
".on_sale"
);