: 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
if (bp === 'desktop') { //backward
const oldGutter = this.getSizes('gutter',bp),
sel=this.type==='subrow'?'module_subrow':this.type + '_inner',
cl = this.el.tfClass(sel)[0].classList;
if (vals.gutter === 'none' || vals.gutter === 'narrow') {
cl.add('gutter-' + vals.gutter);
cl.remove('gutter-' + oldGutter);
this.setGridCss(res, bp);
const savedVals = ['align', 'area', 'size', 'gutter', 'auto_h'],
for (let i = savedVals.length - 1; i > -1; --i) {
if (vals[savedVals[i]] !== undefined) {
newVals[savedVals[i]] = vals[savedVals[i]];
if (newVals.auto_h !== undefined && newVals.auto_h !== '-1') {
this.setSizes(newVals, bp);
prevModel = api.activeModel || null,
constructor=ThemifyConstructor,
prevComponent = constructor.component,
args =this.constructor.getOptions().slice(0, 7);
if (prevModel !== null) {
prevType = prevModel.type;
prevData = api.Helper.cloneObject(prevModel.get('styling'));
constructor.values = prevModel?.id === this.id && constructor.clicked === 'setting' ? api.Forms.serialize('tb_options_setting', true) : (api.Helper.cloneObject(this.get('styling')) || {});
constructor.type = constructor.component = this.type;
args[5].accordion = false;
el.replaceChildren(constructor.create(args));
constructor.values = prevData;
constructor.component = prevComponent;
constructor.type = prevType;
api.activeModel = prevModel;
let grid = target.dataset.grid || '',
count = grid ? (grid.includes('_') ? grid.split('_').length : parseInt(grid)) : '',
bp = api.activeBreakPoint,
sel=this.type==='subrow'?'module_subrow':this.type + '_inner',
inner = this.el.tfClass(sel)[0],
cols = api.Utils.getColumns(inner),
wrap = target.closest('#grid'),
range = wrap.querySelector('#range'),
slider = wrap.querySelector('#slider'),
changeType = bp === 'desktop' ? 'grid' : 'style',
points = bp === 'desktop' ? api.breakpointsReverse : [bp],
isSame=this.isLightboxOpen(),
isLightboxClick=isSame? api.LightBox.el.contains(wrap.getRootNode().host):true;
api.undoManager.start(changeType, this);
else if(!isLightboxClick){
isLightboxClick=!this.syncLightbox('size',grid);
gridCl.remove('tb_col_count_' + oldCount);
gridCl.add('tb_col_count_' + count);
cl.remove('tb_col_count_' + oldCount);
cl.add('tb_col_count_' + count);
const fr = createDocumentFragment();
for (let i = oldCount - 1; i >= count; --i) {
let childs = cols[i].tfClass('tb_holder')[0].children;
for (let j = 0; j < childs.length; ++j) {
fr.appendChild(childs[j]);
cols[i].remove(); // finally remove it
cols[cols.length - 1].tfClass('tb_holder')[0].appendChild(fr); // relocate active_module
for (let i = 0; i < count; ++i) {
let c = new api.Column(cols[i], this.type === 'subrow');
cols[cols.length - 1].after(fr);
cols=api.Utils.getColumns(inner);
const _COL_CLASSES = api.getColClass(),
_COL_CLASSES_VALUES = api.getColClassValues(),
colsClass = _COL_CLASSES[grid] || _COL_CLASSES[colsCount],
len = _COL_CLASSES_VALUES.length - 1;
for (let i = colsCount - 1; i > -1; --i) {
let c = cols[i].classList;
for (let j = len; j > -1; --j) {
c.remove(_COL_CLASSES_VALUES[j]);
if (colsClass !== undefined && colsCount < 7) {
c.remove('first', 'last');
cols[0].classList.add('first');
cols[colsCount - 1].classList.add('last');
this.setCols({size: grid, area: ''});
//reset in responsive mode
for (let i = points.length - 2; i > -1; --i) {
//reseting to auto, if breakpoint has auto value select it otherwise the parent value should be applied
area = this.getGridCss({size: 'auto'}, _bp);
if (area['--area'] && !area['--area'].includes(' ')) {//apply css and update data
this.setCols({size: 'auto'}, _bp);
this.setGridCss({'--area': '', '--col': ''}, _bp);
this.setSizes({size: 'auto'}, _bp);// update data
this.setMaxGutter('',_bp);
const areaLength = getComputedStyle(inner).getPropertyValue('--area').split('" "')[0].split(' ').length;
gridCl.toggle('tb_1col_grid', areaLength === 1);
range.max = slider.max = this.getMaxGutter();
range.value = slider.value = parseFloat(this.setMaxGutter('',bp));
api.Utils.setColumnsCount(cols);
Themify.trigger('tb_grid_changed', [this.el.closest('.module_row'), inner]);
api.Utils.onResize(true);
api.undoManager.end(changeType);
const gutter = target.dataset.value,
gutterValue = ThemifyStyles.getGutterValue(gutter),
rangeWrap = target.closest('#grid'),
range = rangeWrap.querySelector('#range'),
slider = rangeWrap.querySelector('#slider'),
gutterVal = parseFloat(parseFloat(gutterValue).toFixed(2).toString()).toString(), //trailing zeros
unit = gutterValue.replace(gutterVal, '') || '%',
isSame=this.isLightboxOpen();
range.max = slider.max = this.getMaxGutter(unit);
range.value = slider.value = gutterVal;
rangeWrap.querySelector('#range_unit').value = unit;
api.undoManager.start('style', this);
else if(!api.LightBox.el.contains(rangeWrap.getRootNode().host)){
this.syncLightbox(target.closest('[data-col]').dataset.col,gutter);
this.setCols({gutter: gutter});
api.Utils.onResize(true);
api.undoManager.end('style');
const value = target.dataset.value,
isSame=this.isLightboxOpen();
api.undoManager.start('style', this);
else if(!api.LightBox.el.contains(target.getRootNode().host)){
this.syncLightbox(target.closest('[data-col]').dataset.col,value);
if (api.activeBreakPoint === 'desktop') { //backward
const sel=this.type==='subrow'?'module_subrow':this.type + '_inner',
inner = this.el.tfClass(sel)[0];
inner.classList.toggle('col_auto_height', value === '1');
this.setCols({auto_h: value});
api.undoManager.end('style');
const value = target.dataset.value,
isSame=this.isLightboxOpen();
api.undoManager.start('style', this);
else if(!api.LightBox.el.contains(target.getRootNode().host)){
this.syncLightbox(target.closest('[data-col]').dataset.col,value);
if (api.activeBreakPoint === 'desktop') { //backward
let sel=this.type==='subrow'?'module_subrow':this.type + '_inner',
innerCl = this.el.tfClass(sel)[0].classList,
prev = this.get('sizes').desktop_align,
prev = prev.replace('col_align_', '');
prev = prev === 'center' ? 'middle' : 'bottom';
innerCl.remove('col_align_' + prev);
if (_align === 'start') {
_align = _align === 'center' ? 'middle' : 'bottom';
innerCl.add('col_align_' + _align);
this.setCols({align: value});
api.undoManager.end('style');
const mode = api.activeBreakPoint === 'desktop' ? 'direction' : 'style',
sel=this.type==='subrow'?'module_subrow':this.type + '_inner',
inner = this.el.tfClass(sel)[0],
isSame=this.isLightboxOpen();
api.undoManager.start(mode, this);
if (api.activeBreakPoint === 'desktop') {
if (!inner.hasAttribute('data-transition')) {
inner.dataset.transition = 1;
let cols = api.Utils.getColumns(inner),
desktopSizes = this.getSizes('size'),
for (let i = len - 1; i > -1; --i) {
oldcolsAreas[cols[i].dataset.cid] = (i + 1);
cols[len - 1].tfOn('transitionend', function () {
const fr = createDocumentFragment();
for (let i = len - 1; i > -1; --i) {
this.tfOn('transitionend', () => {
for (let i = len - 1; i > -1; --i) {
cols[i].style.setProperty('transition', '');
cols[i].style.setProperty('transition-delay', '');
cols[i].style.setProperty('transform', '');
inner.classList.remove('direction_rtl');
inner.removeAttribute('data-transition');
for (let i = len - 1; i > -1; --i) {
newColsAreas[cols[i].dataset.cid] = (i + 1);
//keep the breakpoints cols order
for (let points = api.breakpointsReverse, i = points.length - 2; i > -1; --i) {
let respArea = self.getSizes('area', points[i]);
if (!respArea.includes('"')) {//is css variable
respArea = computed.getPropertyValue('--area' + respArea).replace(/\s\s+/g, ' ').trim();
for (let cid in newColsAreas) {
if (oldcolsAreas[cid] !== newColsAreas[cid]) {
.replaceAll(oldcolsAreas[cid] + ' ', '#' + newColsAreas[cid] + '# ')
.replaceAll(oldcolsAreas[cid] + '"', '#' + newColsAreas[cid] + '#"');
self.setCols({area: respArea.replaceAll('#', '')}, points[i]);
api.undoManager.end(mode);
self = len = desktopSizes = cols = null;
self.setCols({size: desktopSizes.split(' ').reverse().join(' ')});
for (let i = len - 1; i > -1; --i) {
cols[i].style.setProperty('transition-delay', ((len - i) / 10) + 's');
cols[i].style.setProperty('transform', 'scale(1)');
for (let i = len - 1; i > -1; --i) {
cols[i].style.setProperty('transition', 'transform .3s ' + ((i + 1) / 10) + 's');
cols[i].style.setProperty('transform', 'scale(0)');
let area = getComputedStyle(inner).getPropertyValue('--area').replace(/ +/g, ' ').trim(),
colsSize = area.split('" "')[0].split(' ').length;
area = area.replaceAll('"', '').trim().split(' ').reverse();
for (let i = len - 1; i > -1; --i) {
area.push(area.splice(i, 1)[0]);
for (let i = 0, len2 = (len / colsSize); i < len2; ++i) {
newArea.push('"' + area.slice(i * colsSize, (i + 1) * colsSize).join(' ') + '"');
this.setCols({area: newArea.join(' ')});
api.undoManager.end(mode);
api.ToolBar.breakpointSwitcher(el.dataset.id).then(() => {
const scrollTop = this.el.getBoundingClientRect().top + window.scrollY - 100;
window.top.scroll(0, scrollTop);
window.scroll(0, scrollTop);
api.ActionBar.hover({target: this.el.tfClass('tb_' + this.type + '_action')[0]});
const tpl = doc.tfId('tmpl-builder_grid_list').content.cloneNode(true),
bp = api.activeBreakPoint,
sel=this.type==='subrow'?'module_subrow':this.type + '_inner',
inner = this.el.tfClass(sel)[0],
count = api.Utils.getColumns(inner).length,
countClass = 'tb_col_count_' + count,
areaLength = bp !== 'desktop' ? getComputedStyle(inner).getPropertyValue('--area').split('" "')[0].split(' ').length : null,
range = tpl.querySelector('#range'),
rangeUnit = tpl.querySelector('#range_unit'),
slider = tpl.querySelector('#slider'),
this.setMaxGutter('',bp);
let items = tpl.querySelector('.grid_list').children,
{gutter, align, size, auto_h} = this.getSizes('',bp);
if (!size || count===1) {
size = count > 6 ? 'user' : count;
else if (typeof size === 'string' && size.includes(' ')) {
for (let i = cl.length - 1; i > -1; --i) {
if (cl[i].indexOf('tb_col_count_') === 0) {
if (countClass !== cl[i]) {
elCl.add(countClass, api.activeBreakPoint);
elCl.toggle('tb_1col_grid', areaLength === 1);
if (api.activeBreakPoint !== 'desktop') {
elCl.add('tb_responsive_mode');
if (this.el.classList.contains('fullheight')) {
for (let i = items.length - 1; i > -1; --i) {
items[i].classList.toggle('selected', items[i].dataset.grid === size.toString());
items = tpl.querySelector('.alignment').children;
for (let i = items.length - 1; i > -1; --i) {
items[i].classList.toggle('selected', items[i].dataset.value === align);
auto_h=auto_h.toString();
items = tpl.querySelector('.auto_height').children;
for (let i = items.length - 1; i > -1; --i) {
items[i].classList.toggle('selected', items[i].dataset.value === auto_h);
gutter = ThemifyStyles.getGutter(gutter);
items = tpl.querySelector('.gutter').children;
for (let i = items.length - 1; i > -1; --i) {
items[i].classList.toggle('selected', items[i].dataset.value === gutter);
gutter = ThemifyStyles.getGutterValue(gutter);
const gutterVal = parseFloat(gutter),
gutter_unit = gutter.toString().replace(gutterVal.toString(), '') || '%';
range.max = slider.max = this.getMaxGutter(gutter_unit,bp);
range.value = slider.value = parseFloat(gutterVal.toFixed(4)).toString(); //trailing zeros
rangeUnit.value = gutter_unit,
parent=el.parentNode || el;
parent.tfOn(_CLICK_, e => {
selected = target.closest('li'),
model=api.Registry.get(cid);
const colAction = selected.closest('[data-col]');
const childs = colAction.children,
action = colAction.dataset.col;
for (let i = childs.length - 1; i > -1; --i) {
childs[i].classList.toggle('selected', selected === childs[i]);
else if (target.closest('.expand')) {
const holder = el.querySelector('#range_holder'),
input = ThemifyConstructor.range.render({
max: this.getMaxGutter('%')
max: this.getMaxGutter('em')