Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ MarkText is an open-source Markdown editor powered by the support of its communi

| [<img src="docs/assets/sponsors/serpapi.png" width="150">](https://serpapi.com/?utm_source=marktext) | [Scrape Google and other search engines from our fast, easy, and complete API.](https://serpapi.com/?utm_source=marktext) |
| ------------- |:-------------|
| [<img src="docs/assets/sponsors/ukey.png" width="150">](https://www.ukey.com) | [Secure hardware wallet made simple.](https://www.ukey.com) |

## Screenshot

Expand Down
Binary file removed docs/assets/sponsors/ukey.png
Binary file not shown.
9 changes: 8 additions & 1 deletion packages/desktop/src/main/filesystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ export const writeFile = async(

// write-file-atomic does not create parent directories; recreate a moved or
// deleted folder first so an (auto)save into it still succeeds (#3509).
await ensureDir(path.dirname(pathname))
// Only do this when the parent does not already exist. On Windows fs.mkdir
// returns EPERM (not EEXIST) for an existing volume root (e.g. "E:\"), so for
// an existing parent — drive roots included — ensureDir would throw and block
// saving directly to a drive root instead of being a harmless no-op (#5150).
const dir = path.dirname(pathname)
if (!isDirectory(dir)) {
await ensureDir(dir)
}

// Durable atomic save: write to a temp file in the target's directory, fsync
// it, then rename it over the target. This survives an application crash AND
Expand Down
37 changes: 37 additions & 0 deletions packages/desktop/test/e2e/task-list-autocheck.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import {
// proven nesting fixture from the unit parity spec.
const NESTED_TASKS = '- [ ] parent\n\n - [ ] child1\n - [ ] child2\n'

const SCROLLED_TASKS = `${Array.from(
{ length: 80 },
(_, index) => `Paragraph before task ${index + 1}`
).join('\n\n')}\n\n- [ ] review decision\n`

const setAutoCheck = async(app: ElectronApplication, value: boolean): Promise<void> => {
await sendIpcToRenderer(app, 'mt::user-preference', { autoCheck: value })
}
Expand Down Expand Up @@ -129,3 +134,35 @@ test.describe('Checklist 32 — task list autoCheck cascade via a real checkbox
await expectNoRendererErrors(app)
})
})

test.describe('Task-list checkbox preserves the viewport', () => {
test('clicking a visible checkbox in a long document does not jump to the top', async() => {
const { app, page } = await launchWithMarkdown(SCROLLED_TASKS, {
suppressErrorDialog: true
})

try {
const checkbox = page.locator('.editor-component input[type=checkbox]')
await checkbox.scrollIntoViewIfNeeded()

const before = await page.evaluate(() => {
const editor = document.querySelector('.editor-component') as HTMLElement | null
return editor?.scrollTop ?? 0
})
expect(before).toBeGreaterThan(500)

await checkbox.click()
await expect(checkbox).toBeChecked()
await page.waitForTimeout(250)

const after = await page.evaluate(() => {
const editor = document.querySelector('.editor-component') as HTMLElement | null
return editor?.scrollTop ?? 0
})
expect(after).toBeGreaterThan(before - 100)
await expectNoRendererErrors(app)
} finally {
await app.close()
}
})
})
5 changes: 5 additions & 0 deletions packages/muya/src/block/gfm/taskListCheckbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ class TaskListCheckbox extends TreeNode {
this._checked = checked;
this.update(checked, 'user');
}

// The control is not editable, so clicking it does not move the
// text selection. Seat the caret in this item before the desktop's
// selection-follow scroll can reveal a stale off-screen cursor.
(this.parent as TaskListItem).firstContentInDescendant()?.setCursor(0, 0, true);
};

const eventIds = [
Expand Down
6 changes: 3 additions & 3 deletions packages/website/content/docs/end-user/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Yes, MarkText is licensed under the [MIT](https://github.com/marktext/marktext/b

### Can I use MarkText as note management/taking app?

MarkText is a pure markdown editor without feature such as knowledge management and tags but yes, you can do this via the integrated filesystem explorer and task lists.
MarkText is a pure markdown editor without features such as knowledge management and tags but yes, you can do this via the integrated filesystem explorer and task lists.

### Where can I find documentation?

Expand All @@ -28,15 +28,15 @@ The full documentation is available on the MarkText website:

Yes, please see [here](PORTABLE.md) for further information.

### How can I report bugs and problems
### How can I report bugs and problems?

You can report bugs and problems via our [GitHub issue tracker](https://github.com/marktext/marktext/issues). Please provide a detailed description of the problem to better solve the issue.

### I cannot launch MarkText on Linux (SUID sandbox)

> _The SUID sandbox helper binary was found, but is not configured correctly._

Normally, you should never get this error but if you disabled user namespaces, this error message may appears in the command output when launching MarkText. To solve the issue, that Chromium cannot start the sandbox (process), you can choose one of the following steps:
Normally, you should never get this error but if you disabled user namespaces, this error message may appear in the command output when launching MarkText. To solve the issue, that Chromium cannot start the sandbox (process), you can choose one of the following steps:

- Enable Linux kernel user namespaces to use the preferred sandbox: `sudo sysctl kernel.unprivileged_userns_clone=1`.
- Set correct SUID sandbox helper binary permissions: `sudo chown root <path_to_marktext_dir>/chrome-sandbox && sudo chmod 4755 <path_to_marktext_dir>/chrome-sandbox`. This is preferred if you don't want to enable user namespaces.
Expand Down
Binary file removed packages/website/public/assets/ukey.png
Binary file not shown.
3 changes: 0 additions & 3 deletions packages/website/src/components/Support.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ export default function Support() {
<a className="sponsor-logo" href={DOWNLOAD.serpapi} {...EXT_LINK} title="SerpApi">
<img src="/assets/serpapi.png" alt="SerpApi" loading="lazy" />
</a>
<a className="sponsor-logo" href={DOWNLOAD.ukey} {...EXT_LINK} title="UKey Wallet">
<img className="sponsor-logo-raw" src="/assets/ukey.png" alt="UKey Wallet" loading="lazy" />
</a>
</div>
</div>
</div>
Expand Down
3 changes: 1 addition & 2 deletions packages/website/src/lib/downloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ export const DOWNLOAD = {
sponsor: 'https://github.com/sponsors/marktext',
twitter:
'https://twitter.com/intent/tweet?via=marktextme&url=https://github.com/marktext/marktext/&text=What%20do%20you%20want%20to%20say%20to%20app?&hashtags=happyMarkText',
serpapi: 'https://serpapi.com/?utm_source=marktext',
ukey: 'https://www.ukey.com'
serpapi: 'https://serpapi.com/?utm_source=marktext'
}
Loading