盘古之白 - 如何更优雅地写 wiki
用了一段时间 mediawiki,对自带的搜索还是不太满意,主要表现为:
- 全文搜索的中文是按照单字分词,结果比较杂乱,同页面有多个匹配时预览显示不全就算了,有些页面一个都不显示。至今还没摸出规律
- Cargo 的 drill 页的标题快速过滤对中文支持太差,英文也仅支持“单词样式”的(也即单词在标题头尾或者前后有空格)。这也是写这篇心得的主要原因
- 英文的全文搜索结果只有在“单词样式”下才比较直观
- 等了很久的elastic升级也没有什么进展
所以改造之路就此开始,既然只能依赖简单粗暴的数据库搜索,规范化写作就是唯一一条路,其中最重要的要算 中英文混排用空格隔开 这一条。然后就发现了宝藏工具 Pangu.js
。安装打包好的浏览器插件测试,功能比较简单,就一个按键,然后可以选择是否加载网页时自动排版。这个JS库针对的是纯文本或者html,不支持markdown以及其它标记型语言。最郁闷的是,VisualEditor 下基本不起作用。
然后就找到了一个用了 Panju.js
的 wiki 站,移植过来,感觉有戏。最初的设想是通过组合快捷键触发 JS 读取选中文本,格式化好之后写入剪切板,前端显示通知然后手动粘贴。想法很美好,然而就在快完工时突然意识到一个严重漏洞:这个只针对纯文本的内容好使,碰到带格式的这么一转换肯定撸的干干净净。就此开启挖坑之旅。
首先想到的是选中文本读取为 html 格式,转换后再以 html 粘贴。碰到的第一个问题就是: Pangu.js
在 VisualEditor 下根本不起作用,而浏览器插件是可以的。研究源码发现问题出在 spacingPageBody
可用而 spacingNode
不可用。于是开始了无聊的逐句对比debug,找到根源在于 Xpath :
|
虽然不知道 .//*/
意义是什么,至少可以读取到 Node 中的内容了。然而这还不够,作者在核心代码里屏蔽掉了 textarea 和带 contentEditable 属性的内容(debug到吐)。所以:
|
接下来就是获取选中 Node,然而又遇到另外一个问题,如果选取在段落边界,相邻的 element 可能会乱入。还有一个问题是如何保留格式再粘贴回来。所以暂时放弃这个办法,依赖 Pangu.js
自带的DOM操作逻辑直接修改原位格式化。之后就碰到了最郁闷的事:每次格式化段落之前要把光标点击到这个段落,否则再点回来就会自动还原。注意是点击,键盘移动或者 JS 模拟点击都不行。追踪还原事件发现这个写在 VE 的核心代码里,这样的话就不能全文批量格式化了。找了很多可能的解决办法,最后的决定是:妥协。回归最原始的方式:点击快捷键时通过 getSelection
函数获取光标或者选区所在的段落,执行格式化。主要代码如下:
1 |
|
另外,VE 有个插件系统,这个需求通过这个 Gadget 实现应该会更好些。然鹅研究了半天就逐渐失去耐心,主要原因还是找不到方法直接操作文本或者 DOM,只能做些简单的文本替换。这个先这样凑活着用,有时间再去折腾。
参考
elastic · Gerrit Code Review (wikimedia.org)
中英文混排的“Social Distancing” - Fing’s Blog
vinta/pangu.js: Paranoid text spacing in JavaScript (github.com)
View source for MediaWiki:Pangu.js | Fandom Developers Wiki
Adding JavaScript to Wiki Pages - MediaWiki
Bubble notifications - MediaWiki
javascript获取选中的文本/html - ArthurPatten - 博客园 (cnblogs.com)
javascript - JS: Get array of all selected nodes in contentEditable div - Stack Overflow
getselection - How to get selected html text with javascript? - Stack Overflow
VisualEditor - Documentation
VisualEditor/Gadgets - MediaWiki