|
@@ -1,3 +1,12 @@
|
|
|
+var faCogActive = true;
|
|
|
+var faThLargeActive = false;
|
|
|
+var activeIcon = getVariable('active_icon');
|
|
|
+if (activeIcon) {
|
|
|
+ faCogActive = activeIcon === 'fa-cog'? true : false;
|
|
|
+ faThLargeActive = activeIcon === 'fa-th-large'? true : false;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
const panelsConfig = {
|
|
|
stylePrefix: 'pn-', // 面板的样式前缀
|
|
|
defaults: [
|
|
@@ -53,7 +62,7 @@ const panelsConfig = {
|
|
|
id: 'open-tm',
|
|
|
className: 'fa fa-cog',
|
|
|
command: 'open-tm',
|
|
|
- active: true,
|
|
|
+ active: faCogActive,
|
|
|
togglable: true,
|
|
|
attributes: { title: 'Settings' },
|
|
|
},
|
|
@@ -64,13 +73,14 @@ const panelsConfig = {
|
|
|
// togglable: false,
|
|
|
// attributes: { title: 'Open Layer Manager' },
|
|
|
// },
|
|
|
- // {
|
|
|
- // id: 'open-blocks',
|
|
|
- // className: 'fa fa-th-large',
|
|
|
- // command: 'open-blocks',
|
|
|
- // togglable: false,
|
|
|
- // attributes: { title: 'Open Blocks' },
|
|
|
- // },
|
|
|
+ {
|
|
|
+ id: 'open-blocks',
|
|
|
+ className: 'fa fa-th-large',
|
|
|
+ command: 'open-blocks',
|
|
|
+ active: faThLargeActive,
|
|
|
+ togglable: true,
|
|
|
+ attributes: { title: 'Open Blocks' },
|
|
|
+ },
|
|
|
],
|
|
|
},
|
|
|
],
|
|
@@ -139,29 +149,45 @@ const editor = grapesjs.init({
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
+//定义block块
|
|
|
+const bm = editor.Blocks; // `Blocks` is an alias of `BlockManager`
|
|
|
+bm.add('block_p', {
|
|
|
+ // Your block properties...
|
|
|
+ label: 'Paragraph',
|
|
|
+ media: `<svg style="width:20px;height:20px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M192 32l64 0 160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0 0 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-352-32 0 0 352c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-96-32 0c-88.4 0-160-71.6-160-160s71.6-160 160-160z"/></svg>`,
|
|
|
+ content: '<p>insert your text here</p>',
|
|
|
+});
|
|
|
+bm.add('block_span', {
|
|
|
+ // Your block properties...
|
|
|
+ label: 'Text',
|
|
|
+ media: `<svg style="width:20px;height:20px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l128 0 0 352c0 17.7 14.3 32 32 32s32-14.3 32-32l0-352 128 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L192 32 32 32z"/></svg>`,
|
|
|
+ content: '<span>insert your text here</span>',
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+//图片管理器
|
|
|
const am = editor.AssetManager;
|
|
|
// 锁定整个画布
|
|
|
editor.getWrapper().set({ locked: true });
|
|
|
-
|
|
|
// 遍历所有组件并解锁具有edit属性的组件
|
|
|
-const edit_classes = ['mtb_edit']; // 定义需要解锁的组件类名
|
|
|
+// const edit_classes = ['mtb_edit']; // 定义需要解锁的组件类名
|
|
|
editor.getComponents().each(component => {
|
|
|
component.onAll(component => {
|
|
|
//解销CLASS
|
|
|
- let html = component.toHTML();
|
|
|
- const classes = component.getClasses();
|
|
|
- // 判断是否有交集
|
|
|
- const hasIntersection = classes.some(item => {
|
|
|
- // 如果是数组,则递归检查子数组
|
|
|
- if (Array.isArray(item)) {
|
|
|
- return item.some(subItem => edit_classes.includes(subItem));
|
|
|
- }
|
|
|
- // 如果是字符串,直接检查是否在 edit_classes 中
|
|
|
- return edit_classes.includes(item);
|
|
|
- });
|
|
|
+ // let html = component.toHTML();
|
|
|
+ // const classes = component.getClasses();
|
|
|
+ // // 判断是否有交集
|
|
|
+ // const hasIntersection = classes.some(item => {
|
|
|
+ // // 如果是数组,则递归检查子数组
|
|
|
+ // if (Array.isArray(item)) {
|
|
|
+ // return item.some(subItem => edit_classes.includes(subItem));
|
|
|
+ // }
|
|
|
+ // // 如果是字符串,直接检查是否在 edit_classes 中
|
|
|
+ // return edit_classes.includes(item);
|
|
|
+ // });
|
|
|
|
|
|
// 如果有交集,解锁组件
|
|
|
- if (hasIntersection || component.get('attributes').mtb_edit == 'true') {
|
|
|
+ if (component.get('attributes').mtb_edit == 'true') {
|
|
|
component.set({ locked: false });
|
|
|
setBorder(component);
|
|
|
}
|
|
@@ -180,15 +206,13 @@ editor.getComponents().each(component => {
|
|
|
if (component.get('attributes').mtb_edit_this == 'false') {
|
|
|
component.set({ locked: true });
|
|
|
}
|
|
|
-
|
|
|
})
|
|
|
-
|
|
|
});
|
|
|
|
|
|
function setBorder(component) {
|
|
|
if (component.attributes.tagName == 'a') {
|
|
|
component.setStyle({
|
|
|
- border: '3px dotted #f08300'
|
|
|
+ border: '2px dotted #f08300'
|
|
|
});
|
|
|
} else {
|
|
|
component.setStyle({
|
|
@@ -197,24 +221,32 @@ function setBorder(component) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 监听组件选择事件
|
|
|
editor.on('component:selected', (comp) => {
|
|
|
//去掉选中组件后的按钮
|
|
|
const selectedComponent = editor.getSelected();
|
|
|
- const defaultToolbar = selectedComponent.get('toolbar');
|
|
|
- selectedComponent.set({
|
|
|
- // toolbar: [ ...defaultToolbar, { attributes: {class: commandIcon}, command: commandToAdd}]
|
|
|
- toolbar: [ ]
|
|
|
- });
|
|
|
+ //const defaultToolbar = selectedComponent.get('toolbar');
|
|
|
+ //最外层不显示按钮
|
|
|
+ if (selectedComponent.get('attributes').mtb_edit == 'true' || selectedComponent.get('attributes').mtb_edit_this == 'true') {
|
|
|
+ selectedComponent.set({
|
|
|
+ toolbar: [
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ selectedComponent.set({
|
|
|
+ // toolbar: [ ...defaultToolbar, { attributes: {class: commandIcon}, command: commandToAdd}]
|
|
|
+ toolbar: [{
|
|
|
+ attributes: { class: 'fa fa-clone' },
|
|
|
+ command: 'tlb-clone',
|
|
|
+ title: 'Clone',
|
|
|
+ }, {
|
|
|
+ attributes: { class: 'fa fa-trash' },
|
|
|
+ command: 'tlb-delete',
|
|
|
+ title: 'Delete',
|
|
|
+ }]
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
- //如果是连接与图片,显示右边的属性面板
|
|
|
- // let tags = ['a', 'img'];
|
|
|
- // const hasScheduleAttribute = selectedComponent.attributes;
|
|
|
- // if (tags.includes(selectedComponent.attributes.tagName)) {
|
|
|
- // //editor.runCommand('open-tm');
|
|
|
- // } else {
|
|
|
- // }
|
|
|
|
|
|
// 双击图片时弹出图片管理器
|
|
|
if (selectedComponent.attributes.tagName == 'img') {
|
|
@@ -224,13 +256,10 @@ editor.on('component:selected', (comp) => {
|
|
|
el.addEventListener('dblclick', () => {
|
|
|
am.open({
|
|
|
types: ['image'], // This is the default option
|
|
|
- // Without select, nothing will happen on asset selection
|
|
|
select(asset, complete) {
|
|
|
const selected = editor.getSelected();
|
|
|
if (selected) {
|
|
|
selected.addAttributes({ src: asset.getSrc() });
|
|
|
- // The default AssetManager UI will trigger `select(asset, false)`
|
|
|
- // on asset click and `select(asset, true)` on double-click
|
|
|
complete && am.close();
|
|
|
}
|
|
|
},
|
|
@@ -241,24 +270,11 @@ editor.on('component:selected', (comp) => {
|
|
|
|
|
|
});
|
|
|
|
|
|
-var open_tm_show = true;
|
|
|
-var cogIcons = document.querySelectorAll('.fa-cog');
|
|
|
-cogIcons.forEach(function(icon) {
|
|
|
- icon.addEventListener('click', function() {
|
|
|
- // 在这里执行你想要的操作
|
|
|
- if (open_tm_show) {
|
|
|
- open_tm_show = false;
|
|
|
- } else {
|
|
|
- open_tm_show = true;
|
|
|
- }
|
|
|
- leftPanelDisplay(open_tm_show);
|
|
|
- });
|
|
|
-});
|
|
|
|
|
|
+
|
|
|
+// 隐藏或显示左侧面板
|
|
|
function leftPanelDisplay(isShow = true) {
|
|
|
if (isShow) {
|
|
|
- // canvasBg = document.querySelector('.gjs-cv-canvas');
|
|
|
- // canvasBg.classList.remove('gjs-cv-canvas-bg');
|
|
|
let elements1 = document.querySelectorAll('.gjs-pn-views-container');
|
|
|
elements1.forEach(function(element) {
|
|
|
element.style.display = 'block'; // 或者 'flex',取决于你希望如何显示这些元素
|
|
@@ -268,23 +284,23 @@ function leftPanelDisplay(isShow = true) {
|
|
|
element.style = 'border_bottom: 2px solid var(--gjs-main-dark-color)';
|
|
|
});
|
|
|
} else {
|
|
|
- // canvasBg = document.querySelector('.gjs-cv-canvas');
|
|
|
- // canvasBg.classList.add('gjs-cv-canvas-bg');
|
|
|
let elements1 = document.querySelectorAll('.gjs-pn-views-container');
|
|
|
elements1.forEach(function(element) {
|
|
|
element.style.display = 'none'; // 或者 'flex',取决于你希望如何显示这些元素
|
|
|
});
|
|
|
let elements2 = document.querySelectorAll('.gjs-pn-views');
|
|
|
elements2.forEach(function(element) {
|
|
|
- element.style = 'border:none';
|
|
|
+ element.style = 'border-bottom:none';
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
-// 监听 load 事件
|
|
|
+// 监听编辑器加载完成事件
|
|
|
editor.on('load', () => {
|
|
|
- // 在这里执行你的初始化逻辑
|
|
|
+ //----------
|
|
|
+ // 下接菜单
|
|
|
+ //----------
|
|
|
// 获取目标元素
|
|
|
const targetElement = document.querySelector('.fa-arrows-alt');
|
|
|
// 创建下拉选择框
|
|
@@ -321,8 +337,9 @@ editor.on('load', () => {
|
|
|
window.location.href = redirectUrl;
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
- //发布按钮
|
|
|
+ //----------
|
|
|
+ //发布
|
|
|
+ //----------
|
|
|
customSelect = document.querySelector('.custom-select');
|
|
|
// 创建 sendButton 按钮
|
|
|
const sendButton = document.createElement('button');
|
|
@@ -333,12 +350,69 @@ editor.on('load', () => {
|
|
|
sendButton.classList.add('layui-btn-radius');
|
|
|
sendButton.style = 'margin-left:10px;height:25px;line-height:25px;padding:0 10px;vertical-align:unset;'; // 添加样式(可选)
|
|
|
customSelect.insertAdjacentElement('afterend', sendButton);
|
|
|
+ //发布按钮点击事件
|
|
|
+ sendButton.addEventListener('click', function () {
|
|
|
+ // 显示loading
|
|
|
+ loadIndex = layer.load(0, {shade: [0.5, '#000']});
|
|
|
+ // 发送数据
|
|
|
+ $.ajax({
|
|
|
+ url: '/dist/visual-editor/publish',
|
|
|
+ type: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'X-CSRF-TOKEN': csrfToken,
|
|
|
+ },
|
|
|
+ data: {},
|
|
|
+ success: function (res) {
|
|
|
+ layer.close(loadIndex);
|
|
|
+ layer.msg(res.message,{shade: [0.5, '#000']});
|
|
|
+ },
|
|
|
+ error: function (err) {
|
|
|
+ layer.close(loadIndex);
|
|
|
+ layer.msg(err,{shade: [0.5, '#000']});
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
|
|
|
+ //----------
|
|
|
+ // 右侧面板显示隐藏
|
|
|
+ //----------
|
|
|
+ // 监听属性按钮点击事件
|
|
|
+ var gjsPnBtn = document.querySelectorAll('.gjs-pn-btn');
|
|
|
+ var headRightBtn = ['fa-cog', 'fa-th-large'];
|
|
|
+ gjsPnBtn.forEach(function(icon1) {
|
|
|
+ let hasIntersection = headRightBtn.some(function(btnClass) {
|
|
|
+ return icon1.classList.contains(btnClass);
|
|
|
+ });
|
|
|
+ if (hasIntersection) {
|
|
|
+ icon1.addEventListener('click', function() {
|
|
|
+ hasActive = false;
|
|
|
+ gjsPnBtn.forEach(function(icon) {
|
|
|
+ if (icon.classList.contains('gjs-pn-active')) {
|
|
|
+ hasActive = true;
|
|
|
+ saveVariable('active_icon',icon.classList.item(2));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (hasActive) {
|
|
|
+ leftPanelDisplay(true);
|
|
|
+ } else {
|
|
|
+ leftPanelDisplay(false);
|
|
|
+ saveVariable('active_icon','none');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ //右侧面板显示隐藏
|
|
|
+ if (faCogActive === false && faThLargeActive === false) {
|
|
|
+ leftPanelDisplay(false)
|
|
|
+ }
|
|
|
+ //----------
|
|
|
//关闭loading
|
|
|
+ //----------
|
|
|
layer.close(loadIndex);
|
|
|
+
|
|
|
});
|
|
|
|
|
|
-//更新时调用接口保存数据
|
|
|
+//保存模版内容
|
|
|
editor.on('update', () => {
|
|
|
const html = editor.getHtml();
|
|
|
// 你可以在这里添加自定义逻辑
|
|
@@ -354,7 +428,7 @@ editor.on('update', () => {
|
|
|
},
|
|
|
success: function (res) {
|
|
|
if (res.status != 1) {
|
|
|
- alert('save error');
|
|
|
+ layer.msg('save data error, please try again later!',{shade: [0.5, '#000']});
|
|
|
}
|
|
|
},
|
|
|
error: function (err) {
|
|
@@ -363,6 +437,7 @@ editor.on('update', () => {
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+
|
|
|
// 上传图片时触发loading效果
|
|
|
editor.on('asset:upload:start', () => {
|
|
|
loadIndex = layer.load(0, {shade: [0.5, '#000']});
|
|
@@ -378,3 +453,14 @@ layui.use('flow', function(){
|
|
|
//当你执行这样一个方法时,即对页面中的全部带有 lay-src 的 img 元素开启了懒加载(当然你也可以指定相关 img)
|
|
|
flow.lazyimg();
|
|
|
});
|
|
|
+
|
|
|
+
|
|
|
+// 保存变量到LocalStorage
|
|
|
+function saveVariable(name, value) {
|
|
|
+ localStorage.setItem(name, JSON.stringify(value));
|
|
|
+}
|
|
|
+// 从LocalStorage读取变量
|
|
|
+function getVariable(name) {
|
|
|
+ const value = localStorage.getItem(name);
|
|
|
+ return value ? JSON.parse(value) : null;
|
|
|
+}
|