OverRainbow

omni outliner plugin try try

☕️ 2 min read

你可以从本文了解到

背景

习惯是一个人的迭代系统,好的习惯可以帮助我们在生活和工作中更好的成长。

我平时有记工作日志的习惯,Omin Outliner是一款大纲软件,能够实现任意层级深度的结构,用于记录工作事项和复盘都非常方便。

我平时的日志主要下面这样的结构。

可以简化成

2022-10 【月】
    10.3-10.7 【周】
        10.3【日】
        10.4【日】
        10.5【日】
        10.6【日】
        10.7【日】
            TOP3【三件最重要的事】
            🧙‍♀️🐟【学到的新知识】

整体看上去是非常结构化,并且可以自动化的。

之前我都是低效率的手动录入每周,之前一直就在想等有空了一定要自动化。

那么我们来实现一下这个功能。

基本概念

1、文档

首先OO的文档整体的基本概念可以参考官网,咱们主要是用到2个概念。

1、Document,即整个文件

2、Item,用户选中的节点或节点组

2、插件

OO的插件是写在一个IIFE中,返回的就是这个action,OO会将顶部注释的内容和这段插件代码进行关联,比如增加菜单和快捷入口等。

/*{
    "author": "mzvast",
    "targets": ["omnioutliner"],
    "type": "action",
    "identifier": "com.mycompany.createPlanFromMonth",
    "version": "0.1",
    "description": "A plug-in that...",
    "label": "createPlanFromMonth",
    "mediumLabel": "createPlanFromMonth",
    "longLabel": "createPlanFromMonth",
    "paletteLabel": "createPlanFromMonth",
}*/
(() => {
    var action = new PlugIn.Action(function (selection) {
    
      // 你的代码

    return action;
})();

插件设计和实现

首先这是最终代码

整体就是要做下面这些事。

1、输入一个或多个月份,生成工作日数据结构。相当于产生VDOM。(纯JS)

2、将上一部生成的工作日数组插入到文档中去。相当于VDOM转换成OO的对象。(使用OO API)

首先来看第一部分纯JS代码,生成工作日数据结构,这部分比较简单,主要是要注意几个边界条件,问题不大。

 // 输入
// 2022-06 
// 输出
// ans = [
//     ['6.1', '6.2', '6.3'],
//     ['6.5', '6.6', '6.7', '6.8', '6.9'],
// ];
function generateCalender(itemValue) {
        const startPoint = new Date(itemValue);
        const y = startPoint.getFullYear();
        const m = startPoint.getMonth() + 1; // 月
        const d = startPoint.getDate(); // 日

        const ans = [];
        let tmp = [];
        while (
            startPoint.getMonth() + 1 <= m &&
            startPoint.getFullYear() === y
          // 当前日期还在本月,继续循环
        ) {
            const day = startPoint.getDay();
            if (day < 6 && day > 0) {
                tmp.push(`${m}.${startPoint.getDate()}`); // 插入工作日到tmp
            } else if (tmp.length) {
                ans.push(tmp); // 将tmp插入ans
                tmp = [];
            }
            startPoint.setDate(startPoint.getDate() + 1); // 增加一天
        }

        return ans;
    }

然后就要处理第二部分了。也没什么复杂的逻辑,看注释就可以了解。

关键是用到几个API

1、document.editors[0].selectedNodes获取当前选中的节点list

2、document.outline.outlineColumn当前focus的列,一行一列就确定了单元格

3、selectedItem.valueForColumn(targetColumn).string获取某个单元格的内容

4、selectedItem.addChild向一个item插入子节点,其中第一个参数表示插入位置,end表示插入到末尾。

/*{
    "author": "mzvast",
    "targets": ["omnioutliner"],
    "type": "action",
    "identifier": "com.mycompany.createPlanFromMonth",
    "version": "0.1",
    "description": "A plug-in that...",
    "label": "createPlanFromMonth",
    "mediumLabel": "createPlanFromMonth",
    "longLabel": "createPlanFromMonth",
    "paletteLabel": "createPlanFromMonth",
}*/
(() => {
    var action = new PlugIn.Action(function (selection) {
        var selectedItems = document.editors[0].selectedNodes.map(function (
            node
        ) {
            return node.object;
        });
                
      // 同时支持单选和多选
        selectedItems.forEach((item) => {
            processItem(item);
        });


    });
    // 处理一条记录
    function processItem(selectedItem) {
     
        var targetColumn = document.outline.outlineColumn; // 获取当前的列
        var itemValue = selectedItem.valueForColumn(targetColumn).string; // 当前单元格的内容
        console.log('Invoked with selection', itemValue);
        // 2022-1,2022-01
        // 数据校验
        if (!/\d{4}-\d{2}/i.test(itemValue)) {
            new Alert('bad date, expect YYYY-MM', itemValue).show(function (result) {});
            return;
        }

        // 输入
        // 2022-06
        // getDay 0周日 1周一..6周六

        const ans = generateCalender(itemValue);

        // 最终的数据结构
        // ans = [
        //     ['6.1', '6.2', '6.3'],
        //     ['6.5', '6.6', '6.7', '6.8', '6.9'],
        // ];

        // renderer
        for (let i = 0; i < ans.length; i++) {
            // i=> week
            const week = selectedItem.addChild(
                selectedItem.end,
                function (item) {
                    item.topic =`${ans[i][0]}-${ans[i][ans[i].length - 1]}`;
                }
            );
            for (let j = 0; j < ans[i].length; j++) {
                const day = week.addChild(week.end, function (item) {
                    item.topic = ans[i][j];
                });

                day.addChild(day.end, function (item) {
                    item.topic = 'TOP3';
                });
                day.addChild(day.end, function (item) {
                    item.topic = '🧙‍♀️🐟';
                });
            }
        }
    }

    function generateCalender(itemValue) {
        // ...
    }

    return action;
})();

总结

这款插件在使得之后个人工作日志的迭代效率更max了。

借此机会还深入了解了OO的文档结构和API,以后开发类似的插件就会更得心应手。

也希望本文可以帮到对OO 插件感兴趣的同学。