Compare commits

..

No commits in common. "main" and "1.2.1" have entirely different histories.
main ... 1.2.1

7 changed files with 13 additions and 45 deletions

View file

@ -114,7 +114,6 @@ After triggering, you'll see a notice confirming the task was created.
- **"TickTick auth failed: state mismatch"** — the OAuth flow expired or was started in a different session. Tap Connect again and complete the flow without delays.
- **"Failed to obtain access token"** — most often a bad Client ID or Secret, or the Redirect URI you set in the TickTick developer portal doesn't exactly match the one in the plugin. Copy/paste both rather than typing.
- **`"invalid_grant"` / `"Invalid redirect: ... does not match one of the registered values"`** — the URI registered in the TickTick Developer Portal isn't byte-equal to the one the plugin sends. The most common cause is a trailing `/` in the portal entry. Edit your TickTick app and remove any trailing slash so it matches the plugin's Redirect URI field exactly.
- **The Connect popup link does nothing** — make sure your default browser is set and you've allowed Obsidian to open external links. Try long-pressing the link to copy it, then paste into Safari/Chrome.
- **Callback page shows the code as text instead of returning to Obsidian** — that's the manual-fallback case. Paste the code into the "Authorization code" field; the plugin will exchange it for a token. (This happens if the callback page hasn't been deployed with the deep-link redirect.)
- **The "Open in Obsidian" link in TickTick does nothing** — confirm the Advanced URI plugin is installed and enabled in the same vault.

File diff suppressed because one or more lines are too long

34
main.ts
View file

@ -37,33 +37,6 @@ function getParagraph(editor: Editor, currentLine: number): { text: string, star
return { text: paragraphText.trim(), start, end };
}
// Strip Markdown formatting so the TickTick task title is plain text.
// Removes leading list/checkbox/heading/quote markers and inline emphasis,
// keeping the inner text. Leaves single underscores alone to preserve
// snake_case identifiers.
function stripMarkdown(text: string): string {
return text
// Images: ![alt](url) -> alt
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
// Markdown links: [text](url) -> text
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
// Wiki links: [[page|alias]] -> alias, [[page]] -> page
.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, '$2')
.replace(/\[\[([^\]]+)\]\]/g, '$1')
// Leading blockquote / heading / list / checkbox / ordered-list markers
.replace(/^\s*(?:>\s*|#{1,6}\s+|[-*+]\s+\[[ xX]\]\s+|[-*+]\s+|\d+\.\s+)+/, '')
// Bold/italic via underscores: only strip matched pairs, so
// snake_case identifiers are left intact.
.replace(/__([^_]+)__/g, '$1')
// Asterisk emphasis, highlight, strikethrough, inline code:
// remove the markers whether or not they're balanced (a dangling
// "**" at the start of a line should still be stripped).
.replace(/\*\*?|~~|==|`/g, '')
// Collapse remaining whitespace/newlines
.replace(/\s+/g, ' ')
.trim();
}
// Helper function to generate PKCE codes: codeVerifier and corresponding codeChallenge
async function generatePKCECodes(): Promise<{ codeVerifier: string; codeChallenge: string }> {
const codeVerifier = generateRandomString(64); // between 43 and 128 characters
@ -204,8 +177,7 @@ export default class TickTickPlugin extends Plugin {
const filePath = view.file.path;
const advancedUri = `obsidian://advanced-uri?vault=${encodeURIComponent(vaultName)}&filepath=${encodeURIComponent(filePath)}&block=${encodeURIComponent(blockId)}`;
const taskDescription = `${taskText}\n\n[Open in Obsidian](${advancedUri})`;
const cleanTitle = stripMarkdown(taskText);
const taskTitle = cleanTitle.length > 50 ? cleanTitle.substring(0, 50) + "..." : cleanTitle;
const taskTitle = taskText.length > 50 ? taskText.substring(0, 50) + "..." : taskText;
await this.ensureFreshToken();
@ -236,7 +208,7 @@ export default class TickTickPlugin extends Plugin {
new Notice('Please enter your Client ID in the settings.');
return;
}
const redirectUri = (this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app').trim().replace(/\/+$/, '');
const redirectUri = this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app';
const scope = encodeURIComponent('tasks:read tasks:write');
const { codeVerifier, codeChallenge } = await generatePKCECodes();
const state = generateRandomString(32);
@ -253,7 +225,7 @@ export default class TickTickPlugin extends Plugin {
*/
async exchangeAuthCodeForToken(code: string): Promise<void> {
const tokenEndpoint = 'https://ticktick.com/oauth/token';
const redirectUri = (this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app').trim().replace(/\/+$/, '');
const redirectUri = this.settings.redirectUri || 'https://ticktick-quick-add-obsidian-6yawfmvnj-mooshs-projects-0635287d.vercel.app';
const clientId = this.settings.clientId;
const clientSecret = this.settings.clientSecret;
const codeVerifier = this.settings.tempCodeVerifier;

View file

@ -1,7 +1,7 @@
{
"id": "ticktick-quickadd-task",
"name": "TickTick Quick Add Task",
"version": "1.2.3",
"version": "1.2.1",
"minAppVersion": "1.4.0",
"description": "Create TickTick tasks from text at your cursor with automatic deep links back to your notes. Requires the Advanced URI plugin.",
"author": "Muxin Li",

View file

@ -1,6 +1,6 @@
{
"name": "ticktick-quickadd-task",
"version": "1.2.3",
"version": "1.2.1",
"description": "Create TickTick tasks from text at your cursor with automatic deep links back to your notes. Requires the Advanced URI plugin.",
"main": "main.js",
"scripts": {

View file

@ -89,13 +89,13 @@ export class TickTickSettingTab extends PluginSettingTab {
new Setting(containerEl)
.setName('Redirect URI')
.setDesc('Copy this exact value into your TickTick app\'s Redirect URI field in the developer portal. Do not add a trailing slash — the URIs must match exactly. Only change it here if you self-host the callback page.')
.setDesc('Copy this exact value into your TickTick app\'s Redirect URI field in the developer portal. Only change it here if you self-host the callback page.')
.addText(text =>
text
.setPlaceholder(DEFAULT_SETTINGS.redirectUri!)
.setValue(this.plugin.settings.redirectUri || '')
.onChange(async (value) => {
this.plugin.settings.redirectUri = value.trim().replace(/\/+$/, '');
this.plugin.settings.redirectUri = value.trim();
await this.plugin.saveSettings();
})
);
@ -241,12 +241,11 @@ export class TickTickSettingTab extends PluginSettingTab {
new Setting(details)
.setName('Redirect URI')
.setDesc('Must match the value registered in your TickTick app exactly, with no trailing slash.')
.addText(text =>
text
.setValue(this.plugin.settings.redirectUri || '')
.onChange(async (value) => {
this.plugin.settings.redirectUri = value.trim().replace(/\/+$/, '');
this.plugin.settings.redirectUri = value.trim();
await this.plugin.saveSettings();
})
);

View file

@ -2,7 +2,5 @@
"1.0.0": "0.15.0",
"1.1.0": "1.4.0",
"1.2.0": "1.4.0",
"1.2.1": "1.4.0",
"1.2.2": "1.4.0",
"1.2.3": "1.4.0"
"1.2.1": "1.4.0"
}