Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Global by-function code" #3024

Open
4 tasks done
hmijail opened this issue Aug 12, 2024 · 2 comments
Open
4 tasks done

"Global by-function code" #3024

hmijail opened this issue Aug 12, 2024 · 2 comments
Labels
scope: scripting Issues to do with custom filters, custom sorting and similar type: enhancement New feature or request

Comments

@hmijail
Copy link

hmijail commented Aug 12, 2024

⚠️ Please check that this feature request hasn't been suggested before.

  • I searched previous Ideas in Discussions didn't find any similar feature requests.
  • I searched previous Issues didn't find any similar feature requests.
  • I am only requesting a single feature. Multiple changes should be split into individual requests, with links between them.
  • I believe my requested feature will be generally applicable to other users, not just me: it is not uniquely tied to my personal workflow.

🔖 Feature description

I have various helper JS functions that I find myself copy-pasting into every custom filter/sorting query block. This turns into a maintenance problem whenever a change is required in those functions: I have to change them everywhere.
So it would be great to be able to define those functions globally so that they are available to every custom filter/sorting query block.

✔️ Solution

Just like there is a setting for a "global query" that gets inserted into every query, there could be a "global by function code" setting that gets inserted into every by function block.

❓ Alternatives

Maybe it could be implemented with something like the macros mentioned in issue #2443. However I suspect that its scope doesn't really apply here.

📝 Additional Context

No response

@hmijail hmijail added the type: enhancement New feature or request label Aug 12, 2024
@claremacrae claremacrae added the scope: scripting Issues to do with custom filters, custom sorting and similar label Aug 12, 2024
@claremacrae
Copy link
Collaborator

Good news. This is possible already using the CustomJS plugin - and just needs documenting!

Credit: @mathijsvdv in this comment: #2219 (comment)

See some of my custom functions below, and the @example block shows how to use each function.

class Tasks {

    /**
     * group by recurring, but only if there is a happens date.
     *
     * @example
     * group by function \
     *     const {Tasks} = customJS; \
     *     return Tasks.recurringIfHasHappensDate(task);
     */
    recurringIfHasHappensDate(task) {
        if (task.happens.moment === null) return '';
        if (task.recurrence !== null) return ['Recurring'];
        return ['Not Recurring'];
    }

    /**
     * group by all IDs in a task - its id, and anything it depends on
     *
     * @example
     * group by function \
     *     const {Tasks} = customJS; \
     *     return Tasks.allIds(task);
     */
    allIds(task) {
        const combinedIds = Array.from(task.dependsOn);
        if (task.id !== '') combinedIds.push(task.id);
        return combinedIds;
    }

    /**
     * Group tasks by whether they are:
     *  - Blocked (and cannot be done).
     *  - Blocking (and can be done).
     *  - Or are neither, and can be done in any order.
     *
     * @example
     * group by function \
     *     const {Tasks} = customJS; \
     *     return Tasks.blockingAndBlockedLabel(task, query);
     */
    blockingAndBlockedLabel(task, query) {
        const blocked = task.isBlocked(query.allTasks);
        const blocking = task.isBlocking(query.allTasks);
        if (blocked) {
            return '%%3%% 🔒 Blocked';
        }
        if (blocking) {
            return '%%1%% 🚧 Blocking';
        }
        // Maybe 🌀 or 🎲 ?
        return '%%1%% 🌀 Do in any order';
    }

    /**
     * Return true if no tasks have the given ID
     * @param id
     * @param allTasks
     */
    idMissing(id, allTasks) {
        return ! allTasks.some((task) => task.id === id);
    }

    /**
     * Return true if the task depends on any IDs which do not match any tasks in the vault.
     * @param task
     * @param query
     * @returns {boolean}
     */
    dependsOnMissingID(task, query) {
        return task.dependsOn.some((id) => this.idMissing(id, query.allTasks));
    }

    /**
     * @example
     * sort by function \
     *   const {Tasks} = customJS; \
     *   return Tasks.randomSortKey(task);
     *
     * Credit: @qelo in https://github.com/obsidian-tasks-group/obsidian-tasks/discussions/330#discussioncomment-8902878
     */
    randomSortKey(task) {
        const TSH = s => {
            for (var i = 0, h = 9; i < s.length;) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
            return h ^ h >>> 9
        };
        return TSH(moment().format('Y-MM-DD') + ' ' + task.description)
    }
}

@hmijail
Copy link
Author

hmijail commented Aug 12, 2024

That's perfect, thank you.

I just found a problem: if I use const {Tasks} = customJS; as in these examples, if the page is the first one loaded by Obsidian, the query fails with "ReferenceError: customJS is not defined".

To avoid that problem, the CustomJS docs recommend to start with something like const {Tasks} = await cJS(); . However, await in a task query block fails with "SyntaxError: await is only valid in async functions and the top level bodies of modules"

So I'm having to reload that first page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: scripting Issues to do with custom filters, custom sorting and similar type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants