: 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
((api,_CLICK_,topWindowDoc) => {
const row=doc.tfId('tmpl-builder_row_action').content,
column=doc.tfId('tmpl-builder_column_action').content,
subrow=doc.tfId('tmpl-builder_subrow_action').content,
module=doc.tfId('tmpl-builder_module_action').content,
{isFrontend,Registry}=api,
let root=target.getRootNode(),
tabId = target.dataset.href;
root.querySelector('#'+tabId).classList.add('selected');
tabId=root.querySelector('.row_menu .selected');
tabId=tabId?.dataset.href || 'grid';
const el=root.querySelector('#'+tabId),
grid=root.querySelector('#grid'),
cid=root.host.closest('[data-cid]').dataset.cid,
hide=tabId === 'grid'?root.querySelector('#row_options'):grid,
optionTab=root.querySelector('#options');
if(el.childElementCount<2){
const model=Registry.get(cid);
for(let nav=target.parentNode.children,i=nav.length-1;i>-1;--i){
nav[i].classList.toggle('selected',nav[i]===target);
el.classList.add('selected');
hide?.classList.remove('selected');
if(type!=='click' && optionTab!==null){
api.Utils.addViewPortClass(optionTab);
actionBarPrevEl?.classList.remove('tb_current_module') || bodyCl.add('tb_nested_hover');
actionBarPrevEl= Registry.get(cid).el;
actionBarPrevEl.classList.add('tb_current_module');
const cid=e.target.dataset.cid;
const currentTarget= e.currentTarget,
el=model.type==='subrow'?model.el.tfClass('module_subrow')[0]:model.el,
actionBar=el.querySelector(':scope>.tb_'+model.type+'_action');
if(model.type==='module'){
currentTarget.closest('.tb_small_bar')?.classList.remove('tb_small_bar');
model.el.classList.remove('tb_small_bar');
el.classList.add('tb_show_action');
Themify.triggerEvent(actionBar,'pointerover',{target:actionBar},true);
api.ActionBar.disable=api.ActionBar.disableClear=true;
currentTarget.tfOff(_CLICK_,smallBarClick,{passive:true}).remove();
api.Builder.get().el.tfOff('pointerdown', disable,{passive:true});
doc.tfOff('pointerdown', disable,{passive:true});
topWindowDoc.tfOff('pointerdown', disable,{passive:true});
Themify.off('themify_builder_lightbox_close', disable);
for (let selected = api.Builder.get().el.tfClass('tb_show_action'),i = selected.length - 1; i > -1; --i) {
selected[i].classList.remove('tb_show_action');
api.ActionBar.disableClear=api.ActionBar.disable=null;
Themify.triggerEvent(e.target,'pointerover',{target:e.target},true);
api.Builder.get().el.tfOn('pointerdown', disable,{passive:true});
doc.tfOn('pointerdown', disable,{passive:true});
Themify.on('themify_builder_lightbox_close', disable,true);
topWindowDoc.tfOn('pointerdown', disable,{passive:true});
inner_menu=target.classList.contains('more') || target.classList.contains('inner_more')?target.tfClass('menu')[0]:null;
if (inner_menu || target.classList.contains('inner_more') || target.classList.contains('menu')) {
api.Utils.addViewPortClass((inner_menu || target));
if(target.hasAttribute('data-href')){
const tab=root.querySelector('.tab');
for(let nav=m.children,i=nav.length-1;i>-1;--i){
nav[i].classList.remove('selected');
tab.classList.remove('selected');
else if(!inner_menu && target.part.contains('nested') && !root.querySelector('.nested_menu')){
let el=root.host.closest('[data-cid]'),
builder=api.Builder.get().el,
submenu=createElement('ul','menu nested_menu tf_hide tf_box tf_scrollbar');
if(el.classList.contains('tb_show_action')){
el = el.parentNode.closest('[data-cid]');
if(!el || !builder.contains(el)){
ids.push(el.dataset.cid);
for(let i=0;i<ids.length;++i){
let model = Registry.get(ids[i]);
li = createElement('li','',type==='module'?model.getName():(model.isSubCol?'Sub Column':type)),
if(i===0 && model.isEmpty){
if(type==='subrow' || type==='row'){
li.style.marginInlineStart=(5*lvl)+'px';
submenu.tfOn(_CLICK_,smallBarClick,{passive:true})
.part='menu nested_menu';
target.appendChild(submenu);
api.Utils.addViewPortClass(submenu);
}else if(target.dataset.cid && target.parentNode.classList.contains('nested_menu')){
smallBarHover(target.dataset.cid);
shadowRootClick=function(e){
const action=e.target.closest('[data-action],[part]');
let module=Registry.get(this.host.closest('[data-cid]').dataset.cid),
actionName=action.dataset.action || action.part.item(0);
if(actionName==='edit' || actionName==='styling' || actionName==='visibility' || actionName==='swap'){
if(actionName==='edit' && module.type==='module' && this.querySelector('.swap')?.offsetParent){
actionName='editBuilder';
else if(actionName==='add_col'){
const col=new api.Column({},module.type==='subrow');
api.undoManager.start('move');
api.Drop.column(col.el,el,'right').then(()=>{
api.undoManager.end('move');
else if(actionName==='up' || actionName==='down'){
const nextEl= actionName==='up'?el.previousElementSibling:el.nextElementSibling,
offset=parseInt(getComputedStyle(doc.querySelector(':root')).getPropertyValue('--tb_toolbar_h'));
el.classList.add('tb_draggable_item');
api.undoManager.start('move');
actionName==='up'?nextEl.before(el):nextEl.after(el);
Themify.trigger('tb_' + module.type + '_sort', [el]);
api.undoManager.end('move');
el.classList.remove('tb_draggable_item');
api.Utils.scrollTo(el,offset*2-window.scrollY,{behavior:'smooth'});
else if(module[actionName]){
module[actionName](actionName==='paste'?e.target.classList.contains('style'):e.target);
else if(e.target.hasAttribute('data-href')){
showTab(e.target,'click');
class Bar extends HTMLElement {
const tpl=this.constructor._template.cloneNode(true),
menu=tpl.querySelector('.dropdown'),
parent=this.constructor===ModuleBar?this.parentNode.parentNode:null,
isSmall=parent?.offsetWidth <220;
menu.classList.add('tb_small_bar');
menu.children[~~(menu.childElementCount/2)].after(menu.firstElementChild);
parent?.classList.toggle('tb_small_bar',isSmall);
this.attachShadow({ mode:'open'}).appendChild(tpl);
menu.tfOn('pointerover',menuHover,{passive:true});
this.shadowRoot.tfOn(_CLICK_,shadowRootClick,{passive:true});
const menu=this.shadowRoot.tfOff(_CLICK_,shadowRootClick,{passive:true}).querySelector('.dropdown');
menu?.tfOff('pointerover',menuHover,{passive:true})
.tfClass('nested_menu')[0]?.tfOff(_CLICK_,smallBarClick,{passive:true});
bodyCl.remove('tb_nested_hover');
actionBarPrevEl?.classList.remove('tb_current_module');
class RowBar extends Bar {
class ColumnBar extends Bar {
class SubrowBar extends Bar {
class ModuleBar extends Bar {
customElements.define('tb-row-bar', RowBar);
customElements.define('tb-column-bar', ColumnBar);
customElements.define('tb-subrow-bar', SubrowBar);
customElements.define('tb-module-bar', ModuleBar);
const actionBarCss=module.querySelector('style'),//we are rendreing the inline css ONLY in module bar on the page loading
fr=createDocumentFragment(),
gridCss=row.querySelector('#module_row_grids_style'),
formFields=row.querySelector('#module_form_fields_style'),
allowedSvg=new Set(['move','pencil','settings','brush','layers','more','save','export','import','files','clipboard','eye','new-window','desktop','tablet','tablet','mobile','help','widgetized']),
topHead=topWindowDoc.head;
fr.appendChild(api.ToolBar.getBaseCss());
const svgs=fr.querySelectorAll('#tf_svg symbol');
for(let i=svgs.length-1;i>-1;--i){
let id=svgs[i].id.replace('tf-ti-','');
module.prepend(fr.cloneNode(true));
fr.appendChild(actionBarCss.cloneNode(true));
row.prepend(fr.cloneNode(true));
column.prepend(fr.cloneNode(true));
fr.appendChild(formFields.cloneNode(true));
subrow.prepend(fr,gridCss.cloneNode(true));
topHead.prepend(formFields.cloneNode(true));
topHead.appendChild(formFields.cloneNode(true));
if (api.isGSPage === true) {
this.breadCrumbs = createElement('ul','tb_action_breadcrumb');
Themify.on('themify_builder_ready',()=>{
const builder=api.Builder.get().el;
builder.tfOn(_CLICK_, e=>{
if(api.isDocked && target.classList.contains('tb_dragger')){
api.EdgeDrag.openLightBox(target);
if(target.closest('.tb_visibility_hint,.tb_row_info')){
const model=Registry.get(target.closest('[data-cid]').dataset.cid);
if(target.closest('.tb_visibility_hint')){
model.edit('visibility');
const cssField=lb.querySelector('.tb_field_group_css .tb_style_toggle.tb_closed');
Themify.triggerEvent(cssField, e.type);
.tfOn('pointerover', e=>{
cancelAnimationFrame(this.req);
clearTimeout(this.timer);
this.req=requestAnimationFrame(()=>{
this.timer=setTimeout(()=>{
builder.tfOn('pointerleave', e=>{
if(e.relatedTarget!==e.currentTarget.ownerDocument.body){
api.EdgeDrag.clearTimer(e.clientX,e.clientY);
tagName = target.tagName;
if(!doc.activeElement.isContentEditable && tagName !== 'INPUT' && tagName !== 'TEXTAREA'){
if(tagName==='DIV' &&target.classList.contains('tb_dragger')){
api.EdgeDrag.openLightBox(target);
const el = target.closest('[data-cid]');
const model = Registry.get(el.dataset.cid),
actionBar=model.el.tfTag('tb-'+model.type+'-bar')[0];
if(model.isEmpty!==true){
if(!actionBar.contains(target)){
const editBtn=actionBar.shadowRoot.querySelector('.edit');
Themify.triggerEvent(editBtn,_CLICK_);
if(!themifyBuilder.disableShortcuts){
const canvas = isFrontend ? null : doc.tfId('tb_canvas_block');
topWindowDoc.tfOn('keydown', e=>{
canvas.tfOn('keydown', e=>{
}, true,api.is_builder_ready);
tagName = target.tagName;
if (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !doc.activeElement.isContentEditable && !api.LightBox.el.contains(target) && (!isFrontend ||!api.activeModel?.el?.contains(doc.activeElement))) {
items = api.Builder.get().el.tfClass('tb_element_clicked');
else if (e.ctrlKey === true || e.metaKey === true) {
else if (code === 'KeyD') {
else if (code === 'KeyV') {
pasteStyle = e.shiftKey === true;
if(typeof e.preventDefault==='function'){
if(act === 'delete' || act === 'paste'){
await api.LightBox.save();
api.undoManager.start(act);
for (let i = len - 1; i > -1; --i) {
let selected = items[i].closest('[data-cid]');
let el=Registry.get(selected.dataset.cid);
proms.push(el[act](pasteStyle,true));
await Promise.all(proms);
api.undoManager.end(act);
items = api.Builder.get().el.querySelectorAll('.tb_hide_drag_left,.tb_hide_drag_right'),
offset=api.isVisual?3:13;
for (let i = items.length - 1; i > -1; --i) {
items[i].classList.remove('tb_hide_drag_left', 'tb_hide_drag_right');
col.classList.add('tb_hide_drag_left');
if ((left + col.offsetWidth+offset) >= col.parentNode.offsetWidth) {
col.classList.add('tb_hide_drag_right');
if (api.isPreview!==true && !bodyCl.contains('tb_start_animate') && this.disable === null && target.id!=='tb_small_toolbar_root') {
api.EdgeDrag.setTimer(target);
api.EdgeDrag.clearTimer(e.clientX,e.clientY);
if (this.disablePosition === null) {
const el=target.closest('[data-cid]');
if(el!==null && !el.classList.contains('tb_active_layout_part')){
const cid=el.dataset.cid,
model = Registry.get(cid);
if(target.classList.contains('tb_grid_drag')){
this.columnDragers(target);
const actionBar=model.type==='module'?el.querySelector(':scope > .tb_'+model.type+'_action'):(target.classList.contains('tb_action_wrap')?target:null);
let slug= model.get('mod_name'),