: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
outputUp.dataset.unit = outputLow.dataset.unit = u;
wrapper.tfOn('input', e => {
st = t === up ? 'before' : 'after',
lowVal = low.isConnected ? parseFloat(low.value) : '',
ouput = st === 'before' ? outputUp : outputLow,
upVal = parseFloat(up.value),
inputV = st === 'before' ? upVal : lowVal;
cancelAnimationFrame(ref);
ref=requestAnimationFrame(() => {
v = upVal > lowVal ? (lowVal + ',' + upVal) : (upVal + ',' + lowVal);
ouput.dataset['slider_' + st] = inputV;
wr.style.setProperty('--tb_slider_' + st, inputV);
Themify.triggerEvent(inputRange,event);
Themify.triggerEvent(input, event);
const v = !val ? [min, max] : val.split(',');
v[0] = v[0] > max ? max : (v[0] < min ? min : v[0]);
if (v[1] === undefined) {
v[1] = v[1] > max ? max : (v[1] < min ? min : v[1]);
outputLow.dataset.slider_after = low.value = v[0];
outputUp.dataset.slider_before = up.value = v[1];
outputLow.className += ' tb_slider_output_low';
st += v[1] + ';--tb_slider_after:' + v[0];
wrapper.append(low, outputLow);
if (v.toString().includes(',')) {
v = v > max ? max : (v < min ? min : v);
outputUp.dataset.slider_before = up.value = v;
wrapper.className += ' tb_slider_wrapper_single';
if (data.wrap_class !== undefined) {
wrapper.className += ' ' + data.wrap_class;
st += ';--tb_slider_min:' + min;
st += ';--tb_slider_max:' + max;
container.appendChild(fr);
const range = self.getEl(id);
const unit_id = id + '_unit',
unit = self.getEl(unit_id);
if (unit !== null && unit.tagName === 'SELECT') {
unit.value = self.getStyleVal(unit_id)??unit[0].value;
this._setData(range, (unit.selectedIndex !== -1 ? unit[unit.selectedIndex] : unit[0]));
const angle = range.parentNode.tfClass('tb_angle_dot')[0];
angle.style.transform = v === '' ? '' : 'rotate(' + v + 'deg)';
_setMinMax(range, min, max, step) {
let v = parseFloat(range.value.trim());
if(!isNaN(v) && (v > max || v < parseFloat(min))) {
range.value = v > max ? max : min;
const {min,max,increment:step} = item.dataset;
this._setMinMax(range, min, max, step);
_controlChange(range, unit, event) {
const is_select = unit?.tagName === 'SELECT',
range.tfOn('pointerdown', function (e) {
if (!(this.classList.contains('tb_angle_input') && !this.parentNode.tfClass('tb_angle_circle')[0])) {
e.stopImmediatePropagation();
const old_v = this.value,
max = parseFloat(this.max),
min = parseFloat(this.min),
is_increment = step % 1 !== 0,
increment = !is_increment ? ~~step : parseFloat(step),
changeValue = condition => {
let cval = this.value || 0,
val = !is_increment ? ~~cval : parseFloat(cval),
if ('increase' === condition) {
v = val >= max ? max : (val + increment);
v = val <= min ? min : (val - increment);
this.value = +v.toFixed(2);
angle = this.parentNode.tfClass('tb_angle_dot')[0];
angle.style.transform = 'rotate(' + v + 'deg)';
topBodyCl.add('tb_start_animate', 'tb_move_drag');
e.stopImmediatePropagation();
cancelAnimationFrame(timer);
timer = requestAnimationFrame(() => {
Themify.triggerEvent(_this, event);
e.stopImmediatePropagation();
this.tfOff('pointermove', _move, {passive: true})
.tfOff('pointermove', _start, {once: true, passive: true})
.tfOff('lostpointercapture pointerup', _up, {once: true, passive: true});
cancelAnimationFrame(timer);
timer = lastY = angle = null;
if (this.value !== old_v) {
Themify.triggerEvent(this, event);
if (event !== 'change') {//to detect finish
Themify.triggerEvent(this, 'change');
topBodyCl.remove('tb_start_animate', 'tb_move_drag');
this.tfOn('lostpointercapture pointerup', _up, {once: true, passive: true})
.tfOn('pointermove', _start, {once: true, passive: true})
.tfOn('pointermove', _move, {passive: true})
.setPointerCapture(e.pointerId);
if (is_select === true) {
unit.tfOn('change', function () {
_this._setData(range, this.options[ this.selectedIndex ]);
Themify.triggerEvent(range, event);
if (unit !== undefined) {
this._setData(range, is_select ? (unit.selectedIndex !== -1 ? unit[unit.selectedIndex] : unit[0]) : unit);
range.tfOn('change', () => {
this._setMinMax(range, range.min, range.max, range.step);
const wrapper = createElement('','tb_tooltip_container tf_rel'),
range_wrap = createElement('','tb_range_input tf_inline_b tf_rel'),
input = createElement('input',{type:'number',autocomplete:'off',class:'tb_range'}),
let v = data.value ?? self.getStyleVal(data.id) ?? data.default??'',
if (data.wrap_class !== undefined) {
wrapper.className = ' ' + data.wrap_class;
if (data.placeholder !== undefined) {
input.placeholder = data.placeholder;
if (self.is_repeat === true) {
input.className += self.is_sort === true ? ' tb_lb_sort_child' : ' tb_lb_option_child';
input.dataset.inputId = data.id;
input.className += ' tb_lb_option';
if (data.class !== undefined) {
input.className += ' ' + data.class;
range_wrap.appendChild(input);
if (data.tooltip !== undefined) {
range_wrap.appendChild(self.hint(data.tooltip));
wrapper.appendChild(range_wrap);
if (data.deg === true || units === undefined) {
input.min = data.min || 0;
input.max = data.deg === true ? 360 : (data.max || 1500);
input.step = data.increment || 1;
const select_wrap = createElement('','noborder'),
keys = Object.keys(units);
const select_id = data.id + '_unit',
uv = data.unit || self.getStyleVal(select_id) || data.default_unit;
select = createElement('select','tb_unit');
if (self.is_repeat === true) {
select.className += self.is_sort === true ? ' tb_lb_sort_child' : ' tb_lb_option_child';
select.dataset.inputId = select_id;
select.className += ' tb_lb_option';
if (data.select_class !== undefined) {
select.className += ' ' + data.select_class;
let opt = createElement('option',{value:i},i),
input.min = ~~units[i].min;
input.max = ~~units[i].max;
dataset.min = units[i].min;
dataset.max = units[i].max;
dataset.increment = units[i].increment || (i === 'em' || i === 'rem'? .1 : 1);
self._initControl(select, {type: 'select', id: select_id, control: data.control});
select = createElement('span',{class:'tb_unit',id:data.id + '_unit'},unit);
const min=parseFloat(units[unit].min),
max= parseFloat(units[unit].max),
input.step = units[unit].increment !== undefined ? parseFloat(units[unit].increment) : 1;
if (v < min || v > max) {
input.value =v > max?max:min;
dataset.increment = units[unit].increment || (unit === 'em' || unit === 'rem'? .1 : 1);
select_wrap.appendChild(select);
range_wrap.appendChild(select_wrap);
if (data.after !== undefined) {
wrapper.appendChild(self.after(data));
if (data.description !== undefined) {
wrapper.appendChild(self.description(data.description));
if (data.opposite === true) {
select.tfOn('change', function (e) {
self.margin._changeUnit(this, self);
const event = data.event || (self.clicked === 'styling' ? 'keyup' : 'change'),
ndata = api.Helper.cloneObject(data);
this._controlChange(input, select, event);
if (data.opposite === true) {
input.tfOn(event, function (e) {
self.margin._changeOppositive(this);
self._initControl(input, ndata);
const f=createDocumentFragment(),
wr = createElement('','tb_icon_wrap'),
input = createElement('input',{class:'themify_field_icon',type:'text'}),
preview = createElement('span','tf_plus_icon themify_fa_toggle'),
clear = createElement('span', 'tb_clear_input tf_close'),
v = self.getStyleVal(data.id) || data.default;
if (self.is_repeat === true) {
input.className += self.is_sort === true ? ' tb_lb_sort_child' : ' tb_lb_option_child';
input.dataset.inputId = data.id;
input.className += ' tb_lb_option';
if (data.class !== undefined) {
input.className += ' ' + data.class;
if (v !== undefined && v!=='') {
preview.appendChild(api.Helper.getIcon(v));
self.afterRun.push(() => {
preview.className += ' default_icon';
clear.tfOn(_CLICK_, e => {
Themify.triggerEvent(input, 'change');
wr.append(self._initControl(input, data), preview, clear);
if (data.after !== undefined) {
f.appendChild(self.after(data));
if (data.description !== undefined) {
f.appendChild(self.description(data.description));
getMarginPaddingUnits(type, unit) {
min: (type === 'margin' ? -1500 : 0),
min: (type === 'margin' ? -10 : 0),
min: (type === 'margin' ? -100 : 0)
return unit ? units[unit] : units;
createMarginPadding(type, data) {
const options = data.options || [
ul = createElement('ul','tb_seperate_items tb_has_opposite'),
isBorderRadius = type === 'border_radius',
range = api.Helper.cloneObject(data);
range.units = data.units ?? this.getMarginPaddingUnits(type);
if (isBorderRadius === true) {
ul.dataset.toptext = options[0].label;
let len = options.length,
d = createDocumentFragment(),
for (let i = 0; i < len; ++i) {
let li = createElement('li'),
prop_id = id + '_' + optId;
range.tooltip = options[i].label || optId;
range.class = data.class || '';
range.class += ' tb_multi_field tb_range_' + optId;
if (isBorderRadius === true) {
range.class += ' tb_is_border_radius';
let rangeEl = this.range.render(range, this);
if (i !== 0 && i !== 3) {
let oppId = optId === 'right' ? 'top' : optId,
opposite = createElement('li', 'tb_seperate_opposite tb_opposite_' + (oppId === 'bottom' ? 'top' : oppId));
opposite.appendChild(this.checkboxGenerate('checkbox', {
id: id + '_opp_' + oppId,
class: 'style_apply_oppositive',
let ch_op = opposite.querySelector('.style_apply_oppositive');
ch_op.tfOn('change', function (e) {
self.margin._bindingOppositive(this, true);
.parentNode.insertBefore(createElement('','tb_oppositive_state'), ch_op.nextSibling);
if (ch_op.checked === true) {
self.afterRun.push(() => {
self.margin._bindingOppositive(ch_op);
if (isBorderRadius === true) {
if (options[i].id === 'top') {
prop += 'top-left-radius';
} else if (options[i].id === 'right') {
prop += 'top-right-radius';
} else if (options[i].id === 'left') {
prop += 'bottom-left-radius';
} else if (options[i].id === 'bottom') {
prop += 'bottom-right-radius';
} else if ('transform' === data.type) {
prop = data.prop + '-' + options[i].id;
if (this.is_new === true && !uncheck_all && this.values[prop_id]) {
this.styles[prop_id] = {prop: prop, selector: data.selector};
d = createDocumentFragment();
d.appendChild(self.checkboxGenerate('icon_checkbox',
id: 'checkbox_' + id + '_apply_all',
class: 'style_apply_all',
{name: '1', value: 'all', icon: '<span class="apply_all_checkbox_icon">' + api.Helper.getIcon('ti-link').outerHTML + '</span>'}
default: (this.component === 'module' && this.is_new === true && !uncheck_all) || Object.keys(this.values).length === 0 ? '1' : false
const apply_all = d.querySelector('.style_apply_all');
apply_all.tfOn('change', function () {
self.margin._apply_all(this, true);
if (apply_all.checked === true) {
self.afterRun.push(() => {
self.margin._apply_all(apply_all);
self.range.update(id, v, self);
self.checkbox.update(id + '_opp_top', self.getStyleVal(id + '_opp_top'), self);
self.range.update(self._stylesData[id].bottomId, self.getStyleVal(self._stylesData[id].bottomId), self);
const items = ['topId', 'bottomId'],