求助能否将“优化排版”按钮从折叠菜单中放到外面来

image.png

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25247 引用 • 104154 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9649 引用 • 43883 回帖 • 93 关注

相关帖子

被采纳的回答
  • wilsons 2 2 赞同

    最完美的方式,当如是也

    image.png

    // 把优化排版菜单移动到文档导航条
    {
        const main = (protyle)=>{
            // 发布服务下不显示
            if(window.siyuan.config.readonly) return;
            
            if(protyle?.querySelector('.protyle-breadcrumb [data-type="optimizeTypography"]')) return;
            const exitFocusBtn = protyle.querySelector('.protyle-breadcrumb [data-type="exit-focus"]');
            if(!exitFocusBtn) return;
            const optimizeHtml = `<button class="block__icon fn__flex-center ariaLabel" aria-label="优化排版" data-type="optimizeTypography"><svg><use xlink:href="#iconFormat"></use></svg></button>`;
            exitFocusBtn.insertAdjacentHTML('afterend', optimizeHtml);
            const optimizeBtn = protyle.querySelector('.protyle-breadcrumb [data-type="optimizeTypography"]');
            if(!optimizeBtn) return;
            optimizeBtn.addEventListener('click', () => {
                // 锁定状态下不可修改
                const icon = protyle?.querySelector('button[data-type="readonly"] use')?.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
                if(icon === '#iconLock') {
                    showMessage('锁定状态不可用');
                    return
                }
                // 优化排版
                // see https://github.com/siyuan-note/siyuan/blob/a01523dc98799590396ffcabdc90b2dc6efe8474/app/src/protyle/breadcrumb/index.ts#L415
                requestApi("/api/format/autoSpace", {
                    id: protyle?.querySelector('.protyle-title')?.dataset?.nodeId
                });
            });
        };
    
        // 监听protyle加载
        whenElementExist('.protyle:not(.fn__none)').then(main);
        observeProtyleLoad(main);
    
        function showMessage(message, isError = false, delay = 7000) {
            return fetch('/api/notification/' + (isError ? 'pushErrMsg' : 'pushMsg'), {
                "method": "POST",
                "body": JSON.stringify({"msg": message, "timeout": delay})
            });
        }
        async function requestApi(url, data, method = 'POST') {
            return await (await fetch(url, {method: method, body: JSON.stringify(data||{})})).json();
        }
        function whenElementExist(selector, node) {
            return new Promise(resolve => {
                const check = () => {
                    const el = typeof selector==='function'?selector():(node||document).querySelector(selector);
                    if (el) resolve(el); else requestAnimationFrame(check);
                };
                check();
            });
        }
        function observeProtyleLoad(callback, parentElement) {
            // 如果 parentElement 是字符串,则将其转换为 DOM 元素
            if (typeof parentElement === 'string') {
                parentElement = document.querySelector(parentElement);
            }
            // 创建一个 MutationObserver 实例
            const observer = new MutationObserver((mutationsList) => {
                mutationsList.forEach((mutation) => {
                    // 检查是否是属性变化并且变化的属性是 class
                    if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                        const targetElement = mutation.target; // 发生变化的目标元素
        
                        // 判断目标元素是否匹配指定选择器 .protyle:not(.fn__none)
                        if (targetElement.matches('.protyle:not(.fn__none)')) {
                            // 触发回调
                            callback(targetElement);
                        }
                    }
                });
            });
            // 配置观察选项
            const config = {
                attributes: true, // 监听属性变化
                attributeFilter: ['class'], // 仅监听 class 属性
                subtree: true, // 监听父容器及其所有后代元素
            };
            // 启动观察,默认监听 document.body 或指定的父容器
            observer.observe(parentElement || document.body, config);
        }
    }
    

    类似文章推荐 https://pipe.b3log.org/blogs/wilsons/articles/2025/04/15/1744703423359

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • 倒是不难,但 JS 容易出 BUG,我推荐你给优化排版设置一个快捷键

  • Muu 1
    1. 前置插件图片.png
    2. 设置快捷键图片.png
    3. 设置插件图片.png
    4. 效果图片.png
  • EmptyLight 1

    我记得优化排版可以通过快捷键设置分配快捷键

  • wilsons 2 2 赞同 3 评论

    最完美的方式,当如是也

    image.png

    // 把优化排版菜单移动到文档导航条
    {
        const main = (protyle)=>{
            // 发布服务下不显示
            if(window.siyuan.config.readonly) return;
            
            if(protyle?.querySelector('.protyle-breadcrumb [data-type="optimizeTypography"]')) return;
            const exitFocusBtn = protyle.querySelector('.protyle-breadcrumb [data-type="exit-focus"]');
            if(!exitFocusBtn) return;
            const optimizeHtml = `<button class="block__icon fn__flex-center ariaLabel" aria-label="优化排版" data-type="optimizeTypography"><svg><use xlink:href="#iconFormat"></use></svg></button>`;
            exitFocusBtn.insertAdjacentHTML('afterend', optimizeHtml);
            const optimizeBtn = protyle.querySelector('.protyle-breadcrumb [data-type="optimizeTypography"]');
            if(!optimizeBtn) return;
            optimizeBtn.addEventListener('click', () => {
                // 锁定状态下不可修改
                const icon = protyle?.querySelector('button[data-type="readonly"] use')?.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
                if(icon === '#iconLock') {
                    showMessage('锁定状态不可用');
                    return
                }
                // 优化排版
                // see https://github.com/siyuan-note/siyuan/blob/a01523dc98799590396ffcabdc90b2dc6efe8474/app/src/protyle/breadcrumb/index.ts#L415
                requestApi("/api/format/autoSpace", {
                    id: protyle?.querySelector('.protyle-title')?.dataset?.nodeId
                });
            });
        };
    
        // 监听protyle加载
        whenElementExist('.protyle:not(.fn__none)').then(main);
        observeProtyleLoad(main);
    
        function showMessage(message, isError = false, delay = 7000) {
            return fetch('/api/notification/' + (isError ? 'pushErrMsg' : 'pushMsg'), {
                "method": "POST",
                "body": JSON.stringify({"msg": message, "timeout": delay})
            });
        }
        async function requestApi(url, data, method = 'POST') {
            return await (await fetch(url, {method: method, body: JSON.stringify(data||{})})).json();
        }
        function whenElementExist(selector, node) {
            return new Promise(resolve => {
                const check = () => {
                    const el = typeof selector==='function'?selector():(node||document).querySelector(selector);
                    if (el) resolve(el); else requestAnimationFrame(check);
                };
                check();
            });
        }
        function observeProtyleLoad(callback, parentElement) {
            // 如果 parentElement 是字符串,则将其转换为 DOM 元素
            if (typeof parentElement === 'string') {
                parentElement = document.querySelector(parentElement);
            }
            // 创建一个 MutationObserver 实例
            const observer = new MutationObserver((mutationsList) => {
                mutationsList.forEach((mutation) => {
                    // 检查是否是属性变化并且变化的属性是 class
                    if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                        const targetElement = mutation.target; // 发生变化的目标元素
        
                        // 判断目标元素是否匹配指定选择器 .protyle:not(.fn__none)
                        if (targetElement.matches('.protyle:not(.fn__none)')) {
                            // 触发回调
                            callback(targetElement);
                        }
                    }
                });
            });
            // 配置观察选项
            const config = {
                attributes: true, // 监听属性变化
                attributeFilter: ['class'], // 仅监听 class 属性
                subtree: true, // 监听父容器及其所有后代元素
            };
            // 启动观察,默认监听 document.body 或指定的父容器
            observer.observe(parentElement || document.body, config);
        }
    }
    

    类似文章推荐 https://pipe.b3log.org/blogs/wilsons/articles/2025/04/15/1744703423359

    1 回复
    4 操作
    wilsons 在 2025-04-16 09:29:39 更新了该回帖
    wilsons 在 2025-04-15 22:09:54 更新了该回帖
    wilsons 在 2025-04-15 15:53:51 更新了该回帖
    wilsons 在 2025-04-15 13:28:24 更新了该回帖
    真不错,还顺便学会了用 pipe
    ACai 1
    @ACai 感谢打赏!我最近写了个思源文档直接发布到 pipe 的,目前仅单文档发布,后续可能增加批量和自动发布,如果有兴趣,好了 @ 你下。
    wilsons
    @wilsons 可以可以
    ACai
  • lichlaughing

    厉害厉害,还有个问题就是,文档锁定的状态下该按钮也能发挥作用。能否让该排版按钮在锁定状态下隐藏(解锁文章显示)或者锁定状下失效(不可以点击)解锁状态下可以点击 😄

    1 回复
  • 已修改

    锁定状态下点击会提示不可用

    发布服务下不显示

请输入回帖内容 ...

推荐标签 标签

  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 487 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    89 引用 • 147 回帖 • 1 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    37 引用 • 157 回帖 • 2 关注
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 460 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 1 关注
  • 职场

    找到自己的位置,萌新烦恼少。

    127 引用 • 1708 回帖
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    42 引用 • 130 回帖 • 247 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖 • 1 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 368 关注
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    267 引用 • 666 回帖 • 1 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 400 关注
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖 • 1 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    89 引用 • 122 回帖 • 617 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3198 引用 • 8215 回帖 • 1 关注
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 145 关注
  • sts
    2 引用 • 2 回帖 • 226 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖 • 1 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    211 引用 • 358 回帖 • 1 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    180 引用 • 408 回帖 • 489 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    133 引用 • 1124 回帖 • 114 关注
  • 音乐

    你听到信仰的声音了么?

    62 引用 • 512 回帖
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖 • 1 关注
  • abitmean

    有点意思就行了

    37 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖 • 2 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖 • 2 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    184 引用 • 1015 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖