: 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
model = api.Registry.get(el.tfClass('active_module')[0].dataset.cid);
model = api.Module.initModule(args);
model.previewReload( model.get('mod_settings'));
let libraryItems = [api.MainPanel.el, api.SmallPanel.el],
fr = api.Library.create([data]);
for (let i = libraryItems.length - 1; i > -1; --i) {
let libItem = libraryItems[i].tfClass('library_container')[0];
let selectedTab = libItem.closest('.panel_tab').querySelector('.library_tab .current');
libItem.appendChild(fr.cloneNode(true));
Themify.triggerEvent(selectedTab, _CLICK_);
api.Spinner.showLoader('done');
api.LiteLightBox.alert(data.msg);
api.Spinner.showLoader('error');
saveBtn = lb.tfClass('builder_save_button')[0],
titleInput = lb.tfTag('input')[0];
saveBtn.tfOn(_CLICK_, saveAsLibraryItem);
titleInput.tfOn('keydown', saveAsLibraryItem, {passive: true});
Themify.on('themify_builder_lightbox_close', () => {
lb.classList.remove('tb_save_module_lightbox');
saveBtn.tfOff(_CLICK_, saveAsLibraryItem);
titleInput.tfOff('keydown', saveAsLibraryItem, {passive: true});
return new Promise(async(resolve,reject)=>{
await api.LightBox.save();
const box=this.el.querySelector('.tb_'+this.type+'_action').getBoundingClientRect(),
component = this.isSubCol===true?'SubColumn':this.get('mod_name'),
name = component.charAt(0).toUpperCase() + component.slice(1),
label = this.type === 'subrow' ? 'Sub-Row' : (this.isSubCol===true? 'Sub-Column' : name),
name: i18n.import_tab.replace('%s', name),
label: i18n.import_label.replace('%s', label),
help: i18n.import_data.replace('%s', name),
api.LightBox.el.classList.add('tb_import_export_lightbox');
const lb=await api.LightBox.setStandAlone(box.left, box.top).open(options),
const val = lb.querySelector('#tb_data_field').value;
let res = JSON.parse(val);
if (res.component_name !== this.type) {
TF_Notification.showHide('error',i18n.text_alert_wrong_paste);
api.undoManager.start('import',this.id);
if (res.used_gs !== undefined) {
res=await api.GS.setImport(res.used_gs, res);
delete res.component_name;
await this.setData(api.Base.builderSave(res,'empty'),this.el);
api.ModulePageBreak.countModules();
api.undoManager.end('import');
savBtn=lb.tfClass('builder_save_button')[0];
savBtn.tfOn(_CLICK_,click);
Themify.on('themify_builder_lightbox_close', lb => {
lb.classList.remove('tb_import_export_lightbox');
savBtn.tfOff(_CLICK_,click);
await api.LightBox.save();
const box=this.el.querySelector('.tb_'+this.type+'_action').getBoundingClientRect(),
component = this.isSubCol===true?'SubColumn':this.get('mod_name'),
name = component.charAt(0).toUpperCase() + component.slice(1),
label = this.type === 'subrow' ? 'Sub-Row' : (this.isSubCol===true? 'Sub-Column' : name),
name: i18n.export_tab.replace('%s', name),
label: i18n.import_label.replace('%s', label),
help: i18n.export_data.replace('%s', name),
api.LightBox.el.classList.add('tb_import_export_lightbox');
const lb=await api.LightBox.setStandAlone(box.left, box.top).open(options),
used_gs = api.GS.findUsedItems(data),
input = lb.querySelector('#tb_data_field'),
e.stopImmediatePropagation();
data.component_name = this.type;
for (let i = used_gs.length - 1; i > -1; --i) {
let gsPost = api.GS.styles[used_gs[i]],
styles = api.Helper.cloneObject(gsPost.data[0]);
if ('row' === gsPost.type || 'subrow' === gsPost.type) {
} else if (styles.cols !== undefined) {
if ('column' === gsPost.type) {
styles = styles.modules?.[0].mod_settings || undefined;
if (styles !== undefined && Object.keys(styles).length > 0) {
data: api.Base.builderSave(styles,'empty')
if (Object.keys(gsData).length) {
input.tfOn(_CLICK_, selectText,{passive:true})
.value=JSON.stringify(data);
Themify.on('themify_builder_lightbox_close', lb => {
lb.classList.remove('tb_import_export_lightbox');
input.tfOff(_CLICK_, selectText,{passive:true});
if (api.isPreview || this.isEmpty===true) {
slug = _this.get('mod_name'),
isBuilderEdit=type==='editBuilder' && api.isVisual,
_this.tab=type==='edit' || type==='swap' || !type?'setting':type;
if (api.activeModel !== null) {
if (isBuilderEdit===false && api.activeModel.id === _this.id) {
const clicked = lbEl.querySelector('a[data-id="tb_options_'+_this.tab+'"]');
Themify.triggerEvent(clicked,_CLICK_);
api.ActionBar.clearClicked();
if(isBuilderEdit===true){
_this.setBreadCrumbs(lbEl);
options:_this.constructor.getOptions(slug),
name:_this.constructor.getSettingsName(slug)
options:api.styleData[slug]
visibility:_this.constructor.getVisibility?.()?? true,
animation:_this.constructor.getAnimation?.()??true
if ( this.constructor.enableTooltip?.() !== false ) {
data.setting.options.push({
Themify.trigger( 'tb_edit_component', {
await lb.open(data,_this);
el.classList.add('tb_current_module');
el.classList.add('tb_outline_anim');
el?.classList.remove('tb_current_module','tb_outline_anim');
while (attr.length > 0) {
el.removeAttribute(attr[0].name);
_this.setHtmlAttributes();
const oldState=api.undoManager.getState('saveLightbox');
const diff = api.undoManager.getDiff('saveLightbox',oldState,api.undoManager.getCurrentState('saveLightbox'));
api.undoManager.clear('saveLightbox');
api.undoManager.styleChanges(diff.styles,'old',!diff.html);
await _this.visualPreview(api.restoreVals);
await api.bootstrap([_this.id],undefined,false);
api.Utils.runJs(el, type);
}else if(type==='module'){
_this.backendLivePreview(api.restoreVals);
const event = input.tagName === 'INPUT' && 'hide_anchor' !== type ? 'keyup' : 'change',
onChange=(input,value,ev)=>{
const id=input.closest('.tb_lb_option').id;
if(api.activeModel?.id===this.id){
if(!api.LightBox.el.contains(input)){
const lightboxInput=api.LightBox.el.querySelector('#'+id);
const type=lightboxInput.closest('[data-type]').dataset.type;
for(let items=lightboxInput.children,i=items.length-1;i>-1;--i){
items[i].classList.toggle('selected',items[i].id===value);
lightboxInput.children[0].classList.add('selected');
else if (type === 'checkbox'){
lightboxInput.tfClass('tb_checkbox')[0].checked=!!value;
lightboxInput.value=value;
else if(this.type==='row' && ev==='change' && !input.parentNode.tfClass('tb_field_error_msg')[0] && api.undoManager.has('rowOptions')){
api.undoManager.end('rowOptions');
if(type==='custom_css_id'){
const _this=e.currentTarget,
lightboxInput=api.activeModel?.id===this.id?api.LightBox.el.querySelector('#'+id):null,
error2=lightboxInput?.parentNode.tfClass('tb_field_error_msg')[0],
error1=_this.parentNode.tfClass('tb_field_error_msg')[0],
idText=this.el.tfClass('tb_row_id')[0],
validate=api.Forms.getValidator('custom_css_id')(_this,this.el),
lightboxInput?.classList.remove('tb_field_error');
if(this.type==='row' && api.activeModel?.id!==this.id && !api.undoManager.has('rowOptions')){
api.undoManager.start('rowOptions',this);
this.el.removeAttribute('id');
idText.textContent=this.get(id);
const errorText=validate===false?i18n.errorId:validate;
const er = createElement('span','tb_field_error_msg',errorText);
if(lightboxInput && !error2 && !api.LightBox.el.contains(_this)){
lightboxInput.classList.add('tb_field_error');
lightboxInput.after(er.cloneNode(true));
error1.textContent=errorText;
error2.textContent=errorText;
else if(type==='custom_css'){
api.Forms.getValidator('custom_css')(e.currentTarget);
const v=e.currentTarget.value.trim();
if(this.type==='row' && api.activeModel?.id!==this.id && !api.undoManager.has('rowOptions')){
api.undoManager.start('rowOptions',this);
const el =this.type==='module'?this.el.tfClass('module')[0]:(this.type==='subrow'?this.el.tfClass('module_subrow')[0]:this.el),
const prevCl=prev.split(' ');
for(let i=prevCl.length-1;i>-1;--i){
prevCl[i]=prevCl[i].trim();
for(let i=0;i<vCl.length;++i){
else if(type==='layout'){
if(this.type==='row' && api.activeModel?.id!==this.id){
api.undoManager.start('rowOptions',this);
const layout=e.currentTarget.closest('.tb_lb_option'),
v=layout.tfClass('selected')[0].id,
api.liveStylingInstance.bindRowWidthHeight(id, v, this.el);
const cl=this.el.classList;
if (id === 'row_height') {
cl.toggle('fullheight',v === 'fullheight');
cl.remove('fullwidth','fullwidth_row_container');
cl.add('fullwidth_row_container');
else if (v === 'fullwidth-content') {
else if(type==='row_anchor'){
if(this.type==='row' && api.activeModel?.id!==this.id && !api.undoManager.has('rowOptions')){
api.undoManager.start('rowOptions',this);
api.Forms.getValidator('row_anchor')(e.currentTarget);
const v=e.currentTarget.value,
cl.remove('tb_section-'+prev,'tb_has_section');
cl.add('tb_section-'+v,'tb_has_section');
el.removeAttribute('data-anchor');
el.tfClass('tb_row_anchor')[0].textContent=v;
else if(type==='hide_anchor'){
if(this.type==='row' && api.activeModel?.id!==this.id){
api.undoManager.start('rowOptions',this);
const target=e.currentTarget,
v=target.checked?target.value:null;
this.el.toggleAttribute('data-hide-anchor', v==='1');
let target=e.currentTarget;
onChange(target,v,e.type);
target.tfOff('focusout',focusOut,{passive:true,once:true});
onChange(target, target.value, 'change');
api.undoManager.clear('rowOptions');
interval=target =focusOut=null;
target.tfOn('focusout',focusOut,{passive:true,once:true});
interval=setInterval(()=>{//workaround for firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=559561
if(target && !target.isConnected){
if(!api.isVisual && event==='keyup'){
input.tfOn('keydown focusin focusout copy paste',e=>{//disable guttenberg events