Milkscript ノートの内容からサブタスクを作成。サブタスクを一括削除し、内容をノートに転記する

引き続きMilkScriptのコードを載せていきます。

ノート → サブタスク

ノートの内容からサブタスクを追加していくスクリプトです。

こちらも公式にある『Tasks from note』というスクリプトを自分の使いやすいようにアレンジしたものです。

スクリプト実行前

以下のように選択しているタスクのノートに追加したいサブタスクを書き記し……

スクリプト実行後

スクリプトが実行されると、当該タスクのサブタスクとして追加される。という仕組みです。

スクリプト


// 選択タスクの最新ノートの内容から、サブタスクを作成(スマートアドに対応)
if (rtm.getSelectedTasks().length !== 1){
    throw new Error("タスクが選択されていない、または複数タスクが選択されています");
}
const [selectedTask] = rtm.getSelectedTasks();

// 定数『note』に選択タスクの中で最新ノートを格納
const note = selectedTask.getNotes()
    .reduce((result, note) =>
    result == null || note.getModifiedDate() > result.getModifiedDate() ?
        note : result, null);
if (note == null) {
    throw new Error("選択されたタスクにノートがありません");
}

// noteを改行ごとに分割
const context = note.getContent().split('\n');

// サブタスクを追加。字下げされていたら、孫タスクとして追加する
let parent = selectedTask.getName();
context.forEach(line => {
    if (!line.match(/^[\s\t]+/)) {
    parent = formatTaskName(line);
    selectedTask.addSubtask(parent,true);
    } else {
    const [parentTask] = selectedTask.getSubtasks(parent);
    parentTask.addSubtask(formatTaskName(line,true));
    }
})

// 箇条書きの冒頭からスペースとハイフンをトリムする
function formatTaskName(text) {
    const match = text.match(/^([-\s]+)/);
    const stCount = match ? match[0].length : 0;
    return text.slice(stCount);
}
                    

選択タスクが0、または複数ある場合はエラーになります。
また選択中のタスクにノートがない場合もエラーとなります。

最後に更新されたノートの情報が取得されます。

使い方

私はよくMarkDown記法を使ってノートアプリにプロジェクトの大雑把なプランや、ざっくりやること、経過などをメモしていくのですが、その一環でタスクをMarkDown形式で細分化して書いていきます。

それをいざタスク管理アプリ『remember the milk(以下RTMと表記)』に登録する際、ちまちまコピペするよりスクリプトで一気に登録できたら便利だな……と、コードを書いてみました。

公式で公開されているコードをそのまま使ってもいいのですが、自分の中でMilkScriptの理解度を深めるため書いたものです。

あと冒頭の『- 』はトリムされます。
字下げされていれば、孫タスクとして追加されます。……が、挙動がイマイチで、たまに意図しない動きをします。

サブタスク → ノート

上記スクリプトの逆バージョンです。
選択中のタスクの中のサブタスクを、ノートに箇条書きするためのスクリプトです。

スクリプト実行前

スクリプト実行後

スクリプト


if (rtm.getSelectedTasks().length !== 1){
    throw new Error(“タスクが選択されていない、または複数タスクが選択されています”);
    }
    // 定数『selectedTask』に選択タスクを格納する
    const [selectedTask] = rtm.getSelectedTasks();
    if (selectedTask.getSubtasks().length === 0) {
    throw new Error(“選択されたタスクにサブタスクがありません。”);
    }
    
    // 選択されたタスクにあるサブタスクを取得する
    const subtasks = selectedTask.getSubtasks();
    
    // 二次元配列にタスクとタグ、締切を格納
    const data = [];
    for (let i = 0; i < subtasks.length; i++) {
    const name = subtasks[i].getName();
    
    const tags = subtasks[i].getTags().flatMap(tag => tag.getName());
    const tagNames = subtasks[i].getTags().length > 0 ? ‘#’ + tags.join(’ #’) : ``;
    
    const due = subtasks[i].getDueDate();
    const dueString = due ? ‘^’ + due.toISOString().substring(0, 10) : ‘’;
    
    const row = [name, tagNames, dueString];
    data.push(row);
    }
    
    // 二次元配列をタスク名でソートする
    data.sort(function(a, b) {
    const nameA = a[0].toUpperCase();
    const nameB = b[0].toUpperCase();
    
    let comparison = 0;
    if (nameA > nameB) {
    comparison = 1;
    } else if (nameA < nameB) {
    comparison = -1;
    }
    return comparison;
    });
    
    for (let j = 0; j < data.length; j++) {
    selectedTask.getSubtasks().forEach(task => {
    if(task.getName() === data[0,j][0,0] && task.getSubtasks().length > 0) {
    
        task.getSubtasks().forEach( subtask => {
    
        const tags = subtask.getTags().flatMap(tag => tag.getName());
        let tagNames = '';
        if (subtask.getTags().length > 0){
            tagNames = '#' + tags.join(' #')};
    
        const due = subtask.getDueDate();
        const dueString = due ? '^' + due.toISOString().substring(0, 10) : '';
    
        const subData = [' ' + subtask.getName(),tagNames,dueString]
        data.splice(j+1,0,subData);
        });
    }
    });
    }
    
    // 配列から文字列変数へ
    let context = ‘’;
    data.forEach(data => {
    context = context + data + ‘\n’;
    });
    
    context = context.replaceAll(’,’,’ ');
    
    // サブタスクを文字列変数『context』に格納し、ノートを作成する
    selectedTask.addNote(context);
    
    // 選択したタスクからサブタスクを削除する
    // selectedTask.getSubtasks().forEach(subtask => subtask.delete());
                    

選択タスクが0、または複数ある場合はエラーになります。
また選択中のタスクにサブタスクがない場合もエラーとなります。

サブタスクはあいうえお順にてソートされます。

自分で使っているコードでは、ノートに転記後、サブタスクは一括削除しているのですが、ここで紹介しているコードでは念のため削除にあたる部分をコメントアウトしています。

動作確認後、大丈夫と思ったらコメントアウトを解除して使ってください。

使い方

当初、計画していたタスクに狂いが生じた時に、一旦取り下げしたくてサブタスク群を削除したい場合、後からどんなことをしようとしていたのか振り返りに使うためのものです。

また最初に紹介した『ノート → サブタスク』を実行すれば、またサブタスクに戻すことができます。

スマートアドには、タグ(#)と締切日(^)にのみ対応しています。