123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- 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: [
- {
- id: 'commands',
- buttons: [{}],
- },
- {
- id: 'options',
- buttons: [
- {
- active: false,
- id: 'sw-visibility',
- className: 'fa fa-square-o',
- command: 'core:component-outline',
- context: 'sw-visibility',
- attributes: { title: 'View components' },
- },
- {
- id: 'preview',
- className: 'fa fa-eye',
- command: 'preview',
- context: 'preview',
- attributes: { title: 'Preview' },
- },
- {
- id: 'fullscreen',
- className: 'fa fa-arrows-alt',
- command: 'fullscreen',
- context: 'fullscreen',
- attributes: { title: 'Fullscreen' },
- },
- // {
- // id: 'export-template',
- // className: 'fa fa-code',
- // command: 'export-template',
- // attributes: { title: 'View code' },
- // },
- ],
- },
- {
- id: 'views',
- buttons: [
- // {
- // id: 'open-sm',
- // className: 'fa fa-paint-brush',
- // command: 'open-sm',
- // active: false,
- // togglable: false,
- // attributes: { title: 'Open Style Manager' },
- // },
- {
- id: 'open-tm',
- className: 'fa fa-cog',
- command: 'open-tm',
- active: faCogActive,
- togglable: true,
- attributes: { title: 'Settings' },
- },
- // {
- // id: 'open-layers',
- // className: 'fa fa-bars',
- // command: 'open-layers',
- // togglable: false,
- // attributes: { title: 'Open Layer Manager' },
- // },
- // {
- // id: 'open-blocks',
- // className: 'fa fa-th-large',
- // command: 'open-blocks',
- // active: faThLargeActive,
- // togglable: true,
- // attributes: { title: 'Open Blocks' },
- // },
- ],
- },
- ],
- };
- // 定义自定义组件类型
- const myNewComponentTypes = (editor) => {
- //连接属性
- // editor.Components.addType('a', {
- // isComponent: (el) => el.tagName === 'A',
- // model: {
- // defaults: {
- // traits: [
- // {
- // type: 'text', // Type of the trait
- // name: 'href', // (required) The name of the attribute/property to use on component
- // label: 'URL', // The label you will see in Settings
- // }
- // ],
- // },
- // },
- // });
- //图片属性
- // editor.Components.addType('img', {
- // isComponent: (el) => el.tagName === 'IMG',
- // model: {
- // defaults: {
- // traits: [
- // {
- // type: 'text', // Type of the trait
- // name: 'title', // (required) The name of the attribute/property to use on component
- // label: 'title', // The label you will see in Settings
- // },
- // {
- // type: 'text', // Type of the trait
- // name: 'width', // (required) The name of the attribute/property to use on component
- // label: 'width', // The label you will see in Settings
- // },
- // {
- // type: 'text', // Type of the trait
- // name: 'height', // (required) The name of the attribute/property to use on component
- // label: 'height', // The label you will see in Settings
- // },
- // ],
- // },
- // },
- // });
- };
- const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
- // 创建 GrapesJS 编辑器实例
- const editor = grapesjs.init({
- container: '#mtb_visual_editor', // 指定编辑器容器的 DOM 元素
- fromElement: true, // 从 DOM 元素中加载初始内容
- height: '100%', // 设置编辑器的高度
- width: '100%', // 设置宽度自适应
- storageManager: false,
- panels: panelsConfig,
- plugins: [myNewComponentTypes],
- assetManager: {
- upload: '/dist/visual-editor/upload',
- uploadName: '_file_',
- multiUpload:false,
- headers: {
- 'X-CSRF-TOKEN': csrfToken,
- },
- },
- });
- //定义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 paragraph 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']; // 定义需要解锁的组件类名
- 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);
- // });
- // 如果有交集,解锁组件
- if (component.get('attributes').mtb_edit == '1' || component.get('attributes').mtb_edit == 'true') {
- component.set({ locked: false });
- setBorder(component);
- }
- if (component.get('attributes').mtb_edit == '0' || component.get('attributes').mtb_edit == 'false') {
- component.set({ locked: true });
- }
- if (component.get('attributes').mtb_edit == '2') {
- component.set({ locked: false });
- setBorder(component);
- //关闭子组件
- component.forEachChild(child => {
- child.set({ locked: true });
- })
- }
- })
- });
- function setBorder(component) {
- if (component.attributes.tagName == 'a') {
- component.setStyle({
- border: '2px dotted #f08300'
- });
- } else {
- component.setStyle({
- border: '1px dotted #3b97e3'
- });
- }
- }
- // 监听组件选择事件
- editor.on('component:selected', (comp) => {
- //去掉选中组件后的按钮
- const selectedComponent = editor.getSelected();
- //const defaultToolbar = selectedComponent.get('toolbar');
- //先不给删除按钮
- if (selectedComponent.get('attributes').mtb_edit == 'true' || selectedComponent.get('attributes').mtb_edit == '1' || selectedComponent.get('attributes').mtb_edit == '2') {
- selectedComponent.set({
- toolbar: [
- ]
- });
- } else {
- selectedComponent.set({
- toolbar: [
- ]
- // 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',
- // }]
- });
- }
- if (selectedComponent.get('attributes').mtb_toolbar != '' && selectedComponent.get('attributes').mtb_toolbar != undefined) {
- const mtbToolbar = selectedComponent.get('attributes').mtb_toolbar;
- const safeActions = mtbToolbar.split(',');
- console.log(safeActions);
- let inputToolbar = [];
- if (safeActions.includes('clone')) {
- // 执行克隆相关逻辑
- inputToolbar.push({
- attributes: { class: 'fa fa-clone' },
- command: 'tlb-clone',
- title: 'Clone',
- });
- }
- if (safeActions.includes('delete')) {
- // 执行删除相关逻辑
- inputToolbar.push({
- attributes: { class: 'fa fa-trash' },
- command: 'tlb-delete',
- title: 'Delete',
- });
- }
- selectedComponent.set({
- toolbar: inputToolbar
- });
- }
- // 双击图片时弹出图片管理器
- if (selectedComponent.attributes.tagName == 'img') {
- //双击图片时弹出图片管理器
- const el = selectedComponent.getEl();
- // 添加双击事件监听器
- el.addEventListener('dblclick', () => {
- am.open({
- types: ['image'], // This is the default option
- select(asset, complete) {
- const selected = editor.getSelected();
- if (selected) {
- selected.addAttributes({ src: asset.getSrc() });
- complete && am.close();
- }
- },
- });
- });
- }
- //其他
- });
- // 隐藏或显示左侧面板
- function leftPanelDisplay(isShow = true) {
- if (isShow) {
- let elements1 = document.querySelectorAll('.gjs-pn-views-container');
- elements1.forEach(function(element) {
- element.style.display = 'block'; // 或者 'flex',取决于你希望如何显示这些元素
- });
- let elements2 = document.querySelectorAll('.gjs-pn-views');
- elements2.forEach(function(element) {
- element.style = 'border_bottom: 2px solid var(--gjs-main-dark-color)';
- });
- } else {
- 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-bottom:none';
- });
- }
- }
- // 监听编辑器加载完成事件
- editor.on('load', () => {
- //----------
- // 下接菜单
- //----------
- // 获取目标元素
- const targetElement = document.querySelector('.fa-arrows-alt');
- // 创建下拉选择框
- const dropdown = document.createElement('select');
- dropdown.className = 'custom-select'; // 添加自定义样式类
- dropdown.id = 'dropdown'; // 添加 id 属性
- // 构建 option 标签
- var options = '';
- siteMenu.forEach(function (item) {
- if (mid == item.id) {
- options += `<option value="${item.id}" uri="${item.url}" selected>${item.title}</option>`;
- } else {
- options += `<option value="${item.id}" uri="${item.url}">${item.title}</option>`;
- }
- });
- // 将生成的 option 标签添加到 dropdown 中
- dropdown.innerHTML = options;
- // 将下拉选择框插入到目标元素之后
- targetElement.insertAdjacentElement('afterend', dropdown);
- dropdownel = document.getElementById('dropdown');
- // 监听 change 事件
- dropdownel.addEventListener('change', function () {
- // 获取选中的 option
- var selectedOption = dropdownel.options[dropdownel.selectedIndex];
- // 获取选中的 id 和 uri
- var id = selectedOption.value;
- var uri = selectedOption.getAttribute('uri');
- if (id > 0) {
- // 生成跳转的 URL
- var redirectUrl = `?mid=${id}&uri=${encodeURIComponent(uri)}`;
- // 跳转到生成的 URL
- window.location.href = redirectUrl;
- }
- });
- //----------
- //发布
- //----------
- customSelect = document.querySelector('.custom-select');
- // 创建 sendButton 按钮
- const sendButton = document.createElement('button');
- sendButton.textContent = publishBtnName; // 按钮文本
- sendButton.classList.add('send-button');
- sendButton.classList.add('layui-btn');
- sendButton.classList.add('layui-btn-radius');
- 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);
- $('body').css({
- visibility: 'visible',
- opacity: 1
- });
- });
- //保存模版内容
- editor.on('update', () => {
- const html = editor.getHtml();
- // 你可以在这里添加自定义逻辑
- //ajax提交数据
- $.ajax({
- url: '/dist/visual-editor/preview-save',
- type: 'POST',
- headers: {
- 'X-CSRF-TOKEN': csrfToken,
- },
- data: { // 发送数据
- html: html
- },
- success: function (res) {
- if (res.status != 1) {
- layer.msg('save data error, please try again later!',{shade: [0.5, '#000']});
- }
- },
- error: function (err) {
- alert(err);
- }
- });
- });
- // 上传图片时触发loading效果
- editor.on('asset:upload:start', () => {
- loadIndex = layer.load(0, {shade: [0.5, '#000']});
- });
- editor.on('asset:upload:end', () => {
- layer.close(loadIndex);
- });
- // 图片懒加载
- layui.use('flow', function(){
- var flow = layui.flow;
- //当你执行这样一个方法时,即对页面中的全部带有 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;
- }
|