: 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
((body,topBody,bodyCl,topWindow) => {
if(!Themify.builder_url){
const baseUrl = new URL( doc.currentScript.src );
baseUrl.pathname = baseUrl.pathname.replace('components.min.js', '');
Themify.builder_url=baseUrl.toString().replace('js/editor/build/','');
breakpointsReverse: Object.keys(themify_vars.breakpoints).reverse(),
isGSPage : bodyCl.contains('gs_post'),
isVisual:topWindow !== window,//can be changed, in the frontend can be toggle backend mode
isFrontend:false,//can't be changed init once, in backend false, in the frontend true
activeBreakPoint: 'desktop',
isSafari: /^((?!chrome|android).)*safari/i.test(navigator.userAgent),
if(_jsModulePrms===null){
this.inlineEditor=this.isFrontend=this.isVisual;
const url = Themify.builder_url+'js/editor/',
allPromisses = [Themify.loadJs(Themify.url+'js/admin/notification',!!window.TF_Notification)],
addons=themifyBuilder.addons,
componentUrl=url + 'lazy-components/';
this.componentsURL = componentUrl;
for(let addonUrl in addons){
allPromisses.push(Themify.loadJs(addonUrl,null,addons[addonUrl]));
Themify.loadJs(url+'frontend/themify-builder-inline-editing'),
Themify.loadJs('image-resize',!!window.ThemifyImageResize),
Themify.loadJs(componentUrl+'correct-col-paddings')
//allPromisses.push(Themify.loadJs(moduleUrl+'tree'));
Themify.loadJs(componentUrl + 'right-click');
// Themify.loadJs(componentUrl + 'drop-files');
allPromisses[0].then(()=>{
TF_Notification.init().then(root=>{
topBody.appendChild(root);
_jsModulePrms= Promise.all(allPromisses).then(()=>{
ThemifyConstructor.init();
Themify.loadJs(componentUrl+'offline');
localStorage.removeItem('tb_visual_templates');
localStorage.removeItem('tb_form_templates_');
setInterval(()=>{Registry.observer();},15000);
for(let files=themifyBuilder.style_json,i=files.length-1;i>-1;--i){
prms.push(new Promise(async (resolve,reject)=>{
const f=new URL(files[i]),
origin=window.location.origin;
const res=await Themify.fetch('', null, fetchArgs,f.toString() );
Object.assign(this.styleData,res);
_stylePrms=Promise.all(prms);
LocalFetch(data,type,params){
data.nonce=themifyBuilder.nonce;
let builder=this.Builder?.get(),
bid=builder?.post_id || builder?.id || themifyBuilder.post_ID || '';
if(bid==='' || isNaN(bid)){
builder=this.Builder?.get(0);
bid=builder?.post_id || builder?.id|| '';
Themify.trigger('tb_filter_fetch',data);
return Themify.fetch(data,type,params);
getColClass(){//backward compatibility
return { //deprecated,don't use it need for backward compatibility
3: ['col3-1', 'col3-1', 'col3-1'],
4: ['col4-1', 'col4-1', 'col4-1', 'col4-1'],
5: ['col5-1', 'col5-1', 'col5-1', 'col5-1', 'col5-1'],
6: ['col6-1', 'col6-1', 'col6-1', 'col6-1', 'col6-1', 'col6-1'],
1_2: ['col3-1', 'col3-2'],
2_1: ['col3-2', 'col3-1'],
1_3: ['col4-1', 'col4-3'],
3_1: ['col4-3', 'col4-1'],
1_1_2: ['col4-1', 'col4-1', 'col4-2'],
1_2_1: ['col4-1', 'col4-2', 'col4-1'],
2_1_1: ['col4-2', 'col4-1', 'col4-1']
getColClassValues(){//backward compatibility
return Array.from(new Set([].concat.apply([], Object.values(this.getColClass()))));
api.breakpointsReverse.push('desktop');
Themify.upload_url=themifyBuilder.upload_url;
correctBuilderData(rows){
if(!rows || !Array.isArray(rows)){
rows=rows?Object.values(rows):[];
for(let i=rows.length-1;i>-1;--i){
let {styling:rowSt,cols}=r;
if(rowSt!==undefined && (!rowSt || Array.isArray(rowSt))){
if(!Array.isArray(cols)){
cols=r.cols=Object.values(cols);
for(let j=cols.length-1;j>-1;--j){
let {styling,modules}=col;
if(styling!==undefined && (!styling || Array.isArray(styling))){
modules=this.correctBuilderData(modules);
if (el[0] !== undefined) {
if(el.nodeType===Node.TEXT_NODE){
return el.cloneNode(true);
const node = remove===true?el:el.cloneNode(true);
//after cloning dom the video is playing in bg
const v = node.tfTag('video');
for (let i = v.length - 1; i > -1; --i) {
for (let items = node.tfClass('tb_dragger'), i = items.length - 1; i > -1; --i) {
for (let items = Themify.selectWithParent('[contenteditable]', node), i = items.length - 1; i > -1; --i) {
items[i].contentEditable=false;
items[i].closest('.tb_editor_on')?.classList.remove('tb_editor_on', 'tb_editor_clicked');
for (let items = Themify.selectWithParent('[draggable]', node), i = items.length - 1; i > -1; --i) {
items[i].setAttribute('draggable', 'true');
for (let items = node.tfClass('tb_action_wrap'), i = items.length - 1; i > -1; --i) {
item.removeAttribute('id');
item.removeAttribute('style');
for (let items = node.querySelectorAll('.tb_del_btn,.tb_add_btn'), i = items.length - 1; i > -1; --i) {
items[i].replaceChildren();
const uiItems=node.querySelectorAll('.tb_editor_on,.tb_element_clicked,.tb_selected_img,.tb_editor_clicked,.tb_hide_drag_col_right,.tb_hide_drag_left,.tb_hide_drag_right,.tb_drag_one_column,.tb_drag_side_column,.tb_draggable_item,.tb_column_drag_inner,.tb_active_action_bar,.compact-mode,.tf_dragger_negative');
for (let i = uiItems.length - 1; i > -1; --i) {
uiItems[i].classList.remove( 'tb_element_clicked','tb_editor_on','tb_selected_img','tb_editor_clicked', 'tb_hide_drag_col_right','tb_hide_drag_left','tb_hide_drag_right', 'tb_drag_one_column', 'tb_drag_side_column', 'tb_draggable_item', 'tb_column_drag_inner','tb_active_action_bar','compact-mode','tf_dragger_negative');
for (let items = node.querySelectorAll('[data-drag-w],[data-pos]'), i = items.length - 1; i > -1; --i) {
items[i].removeAttribute('data-drag-w');
items[i].removeAttribute('data-pos');
node.classList.remove('tb_selected_img', 'tb_element_clicked','tb_editor_on','tb_editor_clicked', 'tb_hide_drag_col_right','tb_hide_drag_left','tb_hide_drag_right', 'tb_drag_one_column', 'tb_drag_side_column', 'tb_draggable_item', 'tb_column_drag_inner','tb_active_action_bar','compact-mode','tf_dragger_negative');
node.removeAttribute('data-drag-w');
node.removeAttribute('data-pos');
return obj?JSON.parse(JSON.stringify(obj)):{};
compareObject(oldSettings,newSetting){
if(oldSettings && newSetting){
const size1=oldSettings.hasOwnProperty('length')?oldSettings.length:Object.keys(oldSettings).length,
size2=newSetting.hasOwnProperty('length')?newSetting.length:Object.keys(newSetting).length;
for(let i in oldSettings){
if(newSetting[i]===undefined){
if(oldSettings[i]!==null && typeof oldSettings[i] === 'object'){
if(typeof newSetting[i]!=='object' || this.compareObject(oldSettings[i],newSetting[i])){
else if(newSetting[i]!=oldSettings[i] || (typeof newSetting[i]==='object' && typeof oldSettings[i]!=='object')){
const parts = link.split('?')[0].split('.');
return ['jpg', 'jpeg', 'tiff', 'png', 'gif', 'bmp', 'svg', 'svgz','webp','apng'].includes(parts[parts.length - 1]);
limitString(str, limit=120) {
if (str !== '' && str !== undefined) {
const tmp = createElement();
str = tmp.textContent; // strip html tags
new_str = str.length > limit ? (str.substr(0, limit)+'...') : str;
return Themify.loadJs('https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js',!!window.JSZip,false);
return ThemifyStyles.toRGBA(v);
const fontello_prefix=themifyBuilder.fontello_prefix;
if (typeof fontello_prefix!== 'undefined') {
const fontello_regex = new RegExp(themifyBuilder.fontello_use_suffix ? fontello_prefix + '$' : '^' + fontello_prefix);
if (fontello_regex.test(icon)) {
return createElement('i',icon);
icon = 'tf-' + icon.trim().replace(' ', '-');
let classes = 'tf_fa ' + icon;
const svg = createElementNS('',classes);
svg.appendChild(createElementNS('use',{href:'#' + icon}));
lottie=createElement('tf-lottie'),
tmpl=createElement('template');
if(arr.r && arr.r!=='svg'){
json={actions:json,loop:1};
tmpl.innerHTML=JSON.stringify(json);
lottie.appendChild(tmpl);
return tb_createDocumentFragment();
if (el.getAttribute('data-tfminicolors-initialized') !== null) {
v = jQuery(el).tfminicolors('rgbaString');
const opacity = el.dataset.opacity;
if (opacity !== '' && opacity !== null) {
v = ThemifyStyles.toRGBA(v + '_' + opacity);
return api.ToolBar.el.querySelector('.breakpoint-'+bp+' span').textContent;
const uid=(Math.random().toString(36).substr(2, 4) + (new Date().getUTCMilliseconds()).toString()).substr(0, 7);
return Registry.get(uid)?this.generateUniqueID():uid;
clearElementId(data, _new) {
for (let i=data.length-1;i>-1;--i) {
opt = item.styling || item.mod_settings;
item.element_id = this.generateUniqueID();
const customCss=opt.custom_css_id;
if (customCss !== undefined && customCss !== '') {
let id = j!==1?(customCss+'-'+j):customCss;
if (!doc.tfId(id)?.closest('.module_row')) {
let nested=opt.content_accordion || opt.tab_content_tab,
bulder=opt.builder_content;
if (bulder !== undefined) {
if(typeof bulder === 'string'){
bulder=JSON.parse(bulder);
this.clearElementId(bulder, true);
opt.builder_content = bulder;
for (let j=nested.length-1;j>-1;--j) {
let bulder=nested[j].builder_content;
if(typeof bulder === 'string'){
bulder=JSON.parse(bulder);
this.clearElementId(bulder, true);
nested[j].builder_content = bulder;
if (item.cols !== undefined) {
this.clearElementId(item.cols, _new);
} else if (item.modules !== undefined) {
this.clearElementId(item.modules, _new);
async codeMirror(el,mode,conf={}){
conf.isDarkMode=api.isDarked;
await topWindow.Themify.loadJs(Themify.url+'js/admin/modules/codemirror/codemirror',!!topWindow.ThemifyCodeMiror);
const obj=new topWindow.ThemifyCodeMiror(el,mode,conf);
if(!window.CompressionStream || themifyBuilder.gzip_disabled){
const byteArray = new TextEncoder().encode(data),
cs = new CompressionStream('gzip'),
writer = cs.writable.getWriter();
const res=await (new Response(cs.readable)).arrayBuffer();
return btoa(String.fromCharCode(...new Uint8Array(res)));
for(let [id,model] of this.items){
if(!model.el.isConnected){
this.items.set(item.id, item);
return this.items.get(id) || null;
const model = this.get(id);
for(let v of this.items){
this.get(v[0])?.el.remove();
const events=this._events.get(id) || {};
this._events.set(id, events);
const events=this._events.get(id);
else if(events[ev]!==undefined){
for(let i=events[ev].length-1;i>-1;--i){