BUg in RichTextEditor
adarshsingh197 opened this issue · 1 comments
GrapesJS version
- I confirm to use the latest version of GrapesJS
What browser are you using?
chrome
Reproducible demo link
i have given the code in issues
Describe the bug
Screencast.from.12-06-24.03.09.58.PM.IST.webm
problem is right after applying any bold or italic it is getting disappeard once i click somewhere.
onMounted(async () => {
componentsTypeScript.value = {};
componentsDefaults.value = {};
appId.value = useRoute().query.appId;
designerStore.bAppLoaded = false;
await designerStore.getPlugins();
// try {
// const idbPlugins: Plugin[] = await loadPlugins()
// if (idbPlugins.length === 0) {
// const allPlugins: Plugin[] = await designerStore.getPlugins()
// storePlugins(allPlugins)
// } else {
// console.log('idbPlugins', idbPlugins)
// designerStore.setStoredPlugins(idbPlugins)
// designerStore.getPlugins().then(function (pluginResponse: Plugin[]) {
// storePlugins(pluginResponse)
// })
// }
// } catch (error) {
// const allPlugins: Plugin[] = await designerStore.getPlugins()
// storePlugins(allPlugins)
// }
designerStore.bAppLoaded = true;
// let latestVersion= await designerStore.getAppLatestVersion(appId.value);
designerStore.currentBAApplication = await designerStore.getApp(appId.value, undefined)//,latestVersion.version);
designerStore.currentBAApplication={...designerStore.currentBAApplication,id:designerStore.currentBAApplication.clonedBAId}
designerStore.modifiedAppName = appNameTuner(designerStore.currentBAApplication.baAppName);
// Get Primary Dependencies to initialize the editor with
const baAppDependencies = await designerStore.getDependencies();
const libs = baAppDependencies;
const jsLibs: any[] = [];
const cssLibs: any[] = [];
libs.forEach((link) => {
if (link.endsWith(".js")) {
jsLibs.push(link);
} else if (link.endsWith(".css")) {
cssLibs.push(link);
}
});
// const uniqCssLibs = uniq(cssLibs)
// libs.forEach((dep: any) => {
// if (dep.type == 'css') {
// cssLibs.push(dep.src)
// } else if (dep.type == 'js') {
// jsLibs.push(dep.src)
// }
// })
let uniqCssLibs = uniq(cssLibs);
let uniqJsLibs = uniq(jsLibs);
uniqJsLibs = [
"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js",
"https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js",
"https://cdnjs.cloudflare.com/ajax/libs/primeui/4.1.15/primeui.min.js",
...uniqJsLibs,
];
editorNonReactive= grapesjs.init({
height: "100%",
container: "#canvasBlock",
fromElement: true,
canvasCss: .gjs-selected { outline: 2px solid #c200fdb8 !important; }
,
layerManager: {
custom: true
},
richTextEditor:{
stylePrefix: 'rte-',
adjustToolbar: true,
actions: ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap'],
custom: true,
},
selectorManager: {
appendTo: "#selectors",
// This is make grapesjs to use class styles as the priority and change styles of class instead of id provided by grapesjs
componentFirst: true,
},
styleManager: {
appendTo: "#styles",
},
colorPicker: {
appendTo: "parent",
showButtons: false,
showSelectionPalette: false,
show: function (this: any) {
const sideBarElement: any = document.getElementById("widgetResizable");
const handlerXPos: number = this.getBoundingClientRect().x;
const sidebarXPos: number = sideBarElement.getBoundingClientRect().x;
if (handlerXPos - sidebarXPos < 160) {
this.nextElementSibling.style.left = "0px";
}
},
offset: { top: 30, left: -180 },
},
traitManager: {
appendTo: "#traits",
},
deviceManager: {
default: "Desktop",
devices: [
{
id: "desktop",
name: "Desktop",
width: "",
widthMedia: "",
},
{
id: "tablet",
name: "Tablet",
width: "768px",
widthMedia: "768px",
height: "1024px",
},
{
id: "mobile",
name: "Mobile",
width: "360px",
widthMedia: "360px",
},
],
},
plugins: [
Basics,
styleBackground,
// tailwindBlocks,
"grapesjs-preset-webpage",
"grapesjs-tabs",
styleFilter,
pluginRulers,
customType,
plugin,
domComponents,
loopComponent,
loginform,
forgetPasswordForm,
signupForm,
formComponents,
nativeformComponents,
primeUiPlugin,
panelsManager,
traitManager,
dynamicPlugins,
dynamicWidgets,
animationPlugin,
dynamicComponent,
customBlockComponent,
scrollAnimationComponent,
googleIcons,
listPlugin,
blockManager,
assetManager,
componentManager,
parserPostCSS,
],
pluginsOpts: {
"grapesjs-preset-webpage": {
blocks: ["tab-contents"],
},
"grapesjs-tabs": {},
[plugin]: {
/* options */
},
},
canvas: {
styles: [
"https://fonts.googleapis.com/css2?family=Lato:wght@400;500;700;900&display=swap",
"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;700&display=swap",
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;900&display=swap",
"https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700;900&display=swap",
"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;700;900&display=swap",
"https://fonts.googleapis.com/css?family=Montserrat:400,700&display=swap",
"https://fonts.googleapis.com/css?family=Plus+Jakarta+Sans:wght@400,700&display=swap",
"https://fonts.googleapis.com/css?family=Montserrat:400,700&display=swap",
"https://fonts.googleapis.com/css?family=Plus+Jakarta+Sans:wght@400,700&display=swap",
...uniqCssLibs,
],
scripts: [...uniqJsLibs],
},
jsInHtml: true,
storageManager: {
autoload: true,
onLoad: async (data: any, opts: any) => {
try {
console.log("onLoad");
store.state.appLoading=true;
let resp: any;
// let latestVersion= await designerStore.getAppLatestVersion(appId.value);
if (designerStore.triedLoadFromFile) {
resp = designerStore.app;
} else {
resp = designerStore.currentBAApplication ? designerStore.currentBAApplication : await designerStore.getApp(appId.value, undefined)
}
appId.value=resp.clonedBAId
setSchemasAttrs(resp.sources);
const pageData = resp.config;
BaApplication.value = {...resp,id:resp.clonedBAId};
store.state.appLoading=false;
if (designerStore.triedLoadFromFile) {
setInterval(() => {
// do nothing
}, 1000);
designerStore.setLoadFromFile(false);
}
//we are returning {} if pageData is undefined in order to avoid caching of the previous UI in to newly created BaApp.
return pageData!==undefined? pageData : {};
} catch (error) {
$q.notify({
type: "negative",
message: error.response.data.errorMessage,
});
if (error.response.data.errorCode == 4040) {
// const cleanedStr = editor.value.getHtml().replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
async function generateThumbnail(
thumbnail: string,
defaultThumb: any
) {
if (thumbnail && isUuid(thumbnail)) {
apiUrlGain.contentService
.getImageByThumbnailID(thumbnail)
.then((imgData) => {
page.value.thumbnail =
"data:image/png;base64, " + imgData.data.base64;
})
.catch((e) => {
console.log("Get Thumbnail ", e);
});
} else if (thumbnail) {
page.value.thumbnail = thumbnail;
} else {
page.value.thumbnail = defaultThumb;
}
}
const postBody: any = {
id: designerStore.currentBAApplication.id,
baAppName: designerStore.currentBAApplication.baAppName,
title: designerStore.currentBAApplication.title,
bbandEntryPageUrl: "string",
bcastEntryPackageUrl: "string",
bcastEntryPageUrl: "string",
thumbnail: "string",
config: {},
css: "",
deleted: false,
entryPageURL: "string",
files: designerStore.app.files,
html: {
pre: getHeadContent(),
body: getHTMLBODYV2(),
},
metaData: [],
script: "string",
sources: [],
types: {},
defaults: {},
version: designerStore.currentBAApplication.version,
wrapper: [],
events: [],
aqIds: [],
groupIds: [],
};
const resp = await designerStore.postApp(postBody);
$q.notify({
type: "positive",
message: "App created",
});
console.log("broad", resp.sources);
setSchemasAttrs(resp.sources);
const pageData = resp.config;
BaApplication.value = resp;
return pageData;
}
}
},
autosave: false,
onStore: async (data: any, opts: any) => {
console.log("onStore", data, opts, editor.value, designerStore.triedSaveToFile);
editor.value = await editorStore.getEditor();
const baAppNameSaved =
designerStore.currentBAApplication.baAppName.replace(/\s/g, "") +
"_" +
Date.now();
// const strippedWrapper = editor.value.getComponents().map((element:any) => {
// const { attributes, components } = element;
// return { attributes, components };
// });
componentsTypeScript.value = {};
componentsDefaults.value = {};
generateComponentTypeScript(editor.value.getWrapper());
const cssapp: any = editor.value.getCss({ avoidProtected: true });
const rules = editor.value.CssComposer.getAll();
const allCss = rules.map((rule: any) => rule.toCSS()).join("\n");
// const newCss = cssapp.replace(
// /#(?![\da-fA-F]{6}|[\da-fA-F]{3})(.+?)[\s|\{]/g,
// (match: any, id: any) => {
// // const newCss = baApp.css.replace(/#(.+?)[\s|\{]/g, (match, id) => {
// return `[id^=${id}]{`
// }
// )
let fileSaveConfig: any = {
bbandEntryPageUrl: "string",
bcastEntryPackageUrl: "string",
bcastEntryPageUrl: "string",
config: data,
css: allCss,
files: designerStore.app.files,
html: {
pre: getHeadContent(),
body: getHTMLBODYV2(),
},
script: designerStore.app.script || editor.value.getJs(),
sources: designerStore.app.sources || [],
types: componentsTypeScript.value,
defaults: componentsDefaults.value,
wrapper: editor.value.getComponents(),
events: designerStore.app.events || [],
variables: designerStore.app.variables || [],
aqIds: [],
groupIds: [],
}
if (designerStore.triedSaveToFile) {
const fileName = designerStore.modifiedAppName || baAppNameSaved;
const status = await downloadBAAppConfigAsJson(fileSaveConfig, fileName+'.json');
if (status) {
$q.notify({
type: "positive",
message: "Applet config download successful",
});
} else {
$q.notify({
type: "negative",
message: "Something went wrong while downloading the Applet config",
});
}
designerStore.setSaveToFile(false);
return;
}
const tenantId = useAuthStore().tenantId;
const postBody: any = {
...fileSaveConfig,
...{
id: designerStore.currentBAApplication.id,
ownerId: tenantId,
baAppName: baAppNameSaved,
title: designerStore.currentBAApplication.title,
deleted: false,
entryPageURL: `${baAppNameSaved}.html`,
metaData: [],
// version: designerStore.app.version,
}
};
try {
console.log("postBody", postBody);
store.commit('setSave',false)
await designerStore.putApp(postBody);
console.log("false")
// if(!store.state.saveToggle){}
Notify.create({
message: "App saved successfully!",
timeout: 2000,
position: "bottom",
color: "green",
textColor: "white",
badgeStyle: "display: none",
});
// store.commit('setSave',true);
designerStore
.captureScreenshot(designerStore.currentBAApplication.id)
.then((screenshotUrl) => {
const payload = {
id: designerStore.currentBAApplication.id,
thumbnail: screenshotUrl,
};
return designerStore.patchApp(payload);
});
} catch (error: any) {
$q.notify({
type: "negative",
message: error.response.data.errorMessage,
});
}
},
},
});
editor.value =editorNonReactive;
editor.value.on('rte:enable',()=>{
console.log("hello world 222222222222")
})
// Assuming you have access to the Rich Text Editor instance
const rte = editor.value.RichTextEditor;
// Add the 'bold' functionality
rte.add('bold', {
icon: '<b>B</b>',
attributes: { title: 'Bold' },
result: (rte: { exec: (arg0: string) => any; }) => rte.exec('bold')
});
rte.add('italic', {
icon: '<i>I</i>',
attributes: { title: 'Italic' },
result: (rte: { exec: (arg0: string) => any; }) => rte.exec('italic')
});
editor.value.onReady(async (e: any) => {
console.log("Ready", e);
editorStore.setEditor(editorNonReactive);
editorStore.setLayers(editorNonReactive.Layers);
// editor.value.runCommand("open-layers");
let blocks = editor.value?.BlockManager?.blocks?.models || [];
editorStore.addBlockManagerImages(blocks);
await nextTick();
try{
editorNonReactive.on('layer:custom', handleCustom);
editorNonReactive.on('layer:root', handleRootChange);
const lm = editorNonReactive.LayerManager;
lm.__trgCustom({ container: layerManagerContainer.value });
}
catch(error){
console.log(error);
}
// blockManager(editor.value)
styleManager(editor.value);
loadCustomFonts(editor.value);
loadZoomCommand(editor.value);
designerInitialized.value = true;
editor.value.on("component:add", (model: any) => {
if (model.attributes.type === "gjs-row") {
model.attributes.resizable = true;
model.setDragMode("absolute");
console.log("MOdel",model);
}
// this is to enable resize for all the elements other than row inside the column
else if(model.attributes.type !== "gjs-row" && model.attributes.type !== ""){
model.attributes.resizable = true;
model.setDragMode("absolute");
console.log("MOdel",model);
}
});
editor.value.on("modal", (props: any) => {
if (props.open) {
document
.querySelector("#canvasBlock > div.gjs-mdl-container")
?.setAttribute("title", "");
}
});
editor.value.on("component:select", (model: any) => {
console.log("select");
activeDrawerContent.value = "styles";
activeStylesTab.value = "Style Manager";
const selectedElement: HTMLElement = model.view.el;
const selectedChild: any =
selectedElement.childNodes.length > 0
? selectedElement.childNodes[0]
: null;
if (selectedChild !== null) {
const selectedCanvas: any =
selectedChild.childNodes.length > 0
? selectedChild.childNodes[0]
: null;
if (selectedCanvas !== null && selectedCanvas.tagName === "CANVAS") {
isChartCanvasSelected.value = true;
const classList = selectedElement.className;
if (classList.includes("gjs-selected")) {
const filteredClasses = classList
.replace("gjs-selected", "")
.trim();
if(filteredClasses.split(" ").length !== 0) {
var filteredArr = filteredClasses.split(" ");
filteredArr.forEach((ele_class: string) => {
selectedCanvas.classList.add(ele_class)
});
}
else {
selectedCanvas.classList.add(filteredClasses);
}
}
return;
}
}
isChartCanvasSelected.value = false;
setTimeout(() => {
setElementSelectedType(model.attributes);
}, 1);
});
editor.value.on("styleable:change", (model: any, property: any) => {
const value = model.getStyle()[property];
if (
property === "height" &&
isChartCanvasSelected.value &&
!value.includes("!important")
) {
model.addStyle({ [property]: value + ` !important` });
}
});
});
designerStore.changeFunctionality();
editor.value.runCommand("zoom-in-out-canvas", { value: 100 });
editor.value.on("run:ruler-visibility", (): void => {
console.log(toggleRuler.value);
toggleRuler.value = !toggleRuler.value;
});
// search plagiun hide and show
// designerStore.addSerchFilterToPlugins();
});
here is my code
Code of Conduct
- I agree to follow this project's Code of Conduct
From the official demo it looks to work as expected, so I guess it's related to your custom logic.
Please provide a minimal reproducible demo of the issue.