Compare commits

...

160 Commits

Author SHA1 Message Date
windingwind 568e460189 chore(publish): release v2.2.5 2025-01-19 14:25:46 +01:00
windingwind 5851b95ff1 fix: note tab session record
fix: #1265
2025-01-19 14:25:35 +01:00
windingwind 719be35dca doc: update readme and template doc
chore: remove deprecated template
chore: lint
2025-01-19 00:50:28 +01:00
windingwind bf46815ddb
test: add export.saveMD (#1266)
* test: add export.saveMD
2025-01-18 18:31:32 +01:00
windingwind 476b569555 chore(publish): release v2.2.4 2025-01-18 17:27:01 +01:00
windingwind 7ec71c9a10 fix: #1264 2025-01-18 17:26:44 +01:00
windingwind 83151daf7f chore(deps): zotero-types 2025-01-18 17:26:29 +01:00
windingwind 6259a9a2a6 chore(publish): release v2.2.3 2025-01-12 15:08:41 +01:00
windingwind 79f7c81886 fix: remove Services.jsm
fix: related errors on fx128 platform
2025-01-12 15:08:06 +01:00
windingwind 270d7fcb7f chore(deps): update scaffold 2025-01-12 15:07:07 +01:00
Mi Ramon cfedb94159
fix: bulleted list and numbered list nowarp (#1261) 2025-01-12 14:59:28 +01:00
windingwind 07e624c67d chore(publish): release v2.2.3-beta.4 2025-01-06 20:31:30 +01:00
windingwind b1fe4cc735 chore: sort templates in template picker
fix: #1250
2025-01-06 20:31:19 +01:00
windingwind 4726e7ca76 chore(publish): release v2.2.3-beta.3 2025-01-06 19:45:55 +01:00
windingwind 4fae5a422f update(deps): scaffold 2025-01-06 19:45:43 +01:00
windingwind 63f8ce3a58 fix: editor getPositionAtLine when line index exceeds line count 2025-01-06 19:42:13 +01:00
windingwind 7dd98cbd87 chore: improve note from annotation button 2025-01-06 12:28:43 +01:00
windingwind a138848c4f chore: improve note from annotation button style 2025-01-06 12:07:33 +01:00
windingwind 2b0ef07fee test: add template tests 2025-01-06 11:49:10 +01:00
windingwind 0e42f90549 chore(publish): release v2.2.3-beta.2 2025-01-06 00:43:26 +01:00
windingwind a144a74356 fix: insert template after cursor line
fix: #1248
2025-01-06 00:43:13 +01:00
windingwind e776bb9b22 chore(publish): release v2.2.3-beta.1 2025-01-05 22:51:48 +01:00
windingwind fb3d218f9f fix: addLineToNote when lineIndex out of range
fix: #1239
2025-01-05 22:51:25 +01:00
windingwind 2b4745e417 chore(publish): release v2.2.2 2025-01-05 18:20:16 +01:00
windingwind 303f13639c fix: magic palette locale 2025-01-05 18:19:51 +01:00
windingwind a88a582d71 chore(publish): release v2.2.1 2025-01-05 18:15:05 +01:00
windingwind a59647688e feat: refresh templates in magic palette
resolve: #1212
2025-01-05 18:14:53 +01:00
windingwind 80fcb350ef chore(publish): release v2.2.0 2025-01-05 17:45:05 +01:00
windingwind f95f2c87c5 chore: bump max version 2025-01-05 17:44:45 +01:00
windingwind f93a43fdb3 chore: disable patchOpenTabMenu temporarily 2024-12-29 18:45:11 +01:00
windingwind b8924c7e1f chore(deps): update deps 2024-12-29 18:42:47 +01:00
windingwind 62cdaf9c4d chore(publish): release v2.1.9 2024-12-13 13:56:02 +01:00
windingwind e5e149e6f2 fix: don't copy embedded images to its parent note 2024-12-13 13:55:49 +01:00
windingwind 6bfae7376c fix: multi-selection in note picker 2024-12-13 13:55:49 +01:00
windingwind 95a0f4916d add: api.convert.note2html dryRun flag
fix: note2html for preview in link creator
2024-12-13 13:55:49 +01:00
windingwind 6c8b8dc988 chore: move link creator content generation outside window scope
fix: content generation abort after window closed

fix: #1225
2024-12-13 13:55:08 +01:00
windingwind a3b5ac8050 add: api.template.runQuickInsertTemplate 2024-12-13 13:13:24 +01:00
windingwind c6d4d93c5d fix: note link section count exclude invalid items 2024-12-13 12:16:15 +01:00
windingwind a667f8ac72 chore(publish): release v2.1.8 2024-12-11 16:51:36 +01:00
windingwind 8f9092e787 chore: rename workflow 2024-12-11 16:51:28 +01:00
windingwind 3cf2379380 fix: release error with upstream deps 2024-12-11 16:51:05 +01:00
windingwind 78eeff91a3 chore(deps): scaffold as dev deps 2024-12-11 16:34:17 +01:00
windingwind 43a74a013b fix: underline annotation serialization
fix: #1222
2024-12-11 16:18:00 +01:00
windingwind 33330f0bda chore: lint 2024-12-11 16:17:33 +01:00
windingwind 65c220f292
feat: add tests (#1220) 2024-12-09 17:16:13 +01:00
windingwind c4a88df09f chore(publish): release v2.1.7 2024-11-30 10:09:18 +01:00
windingwind 6dc9259518 chore: lint 2024-11-30 10:08:50 +01:00
windingwind d17d5dc025 fix: rehype2remark list item inline bug
fix: #1207
2024-11-30 10:08:29 +01:00
windingwind cd7edb0f63 chore(doc): update note template example link format 2024-11-30 10:07:11 +01:00
windingwind a326c71a2c chore(publish): release v2.1.6 2024-11-19 17:02:01 +01:00
windingwind 88e831d395 fix: refresh template editor after importing 2024-11-19 17:01:47 +01:00
windingwind 67ffda4830 chore(publish): release v2.1.5 2024-11-18 23:17:59 +01:00
windingwind 60d0f30836 fix: #1201 2024-11-18 23:17:48 +01:00
windingwind 4cf1de6fbc chore(publish): release v2.1.4 2024-11-13 13:13:27 +01:00
windingwind f216b93771 add: npx command 2024-11-13 13:13:11 +01:00
windingwind e15e0552f6 fix: magic key input blur stops click event
fix: #1192
2024-11-13 13:13:04 +01:00
windingwind 47b65c7d97
Update README.md 2024-11-12 20:28:56 +01:00
windingwind 802bb3fc1c chore(publish): release v2.1.3 2024-11-12 15:00:42 +01:00
windingwind 6590c94fd7 add: magic key palette keyboard handle 2024-11-12 15:00:34 +01:00
windingwind b6a3f3c233 chore(publish): release v2.1.2 2024-11-12 14:42:45 +01:00
windingwind 3fc5adb516 fix: magic key command navigation 2024-11-12 14:42:36 +01:00
windingwind 1591c0f2a0 add: open attachment to magic key command 2024-11-12 14:37:42 +01:00
windingwind 354430200d add: copy link to magic key command 2024-11-12 13:41:01 +01:00
windingwind 7fe24db639 chore(publish): release v2.1.1 2024-11-11 21:56:21 +01:00
windingwind 4231f8c998 fix: do not scroll editor when showing magic key popup 2024-11-11 21:56:11 +01:00
windingwind 10dedacc1b chore(publish): release v2.1.0 2024-11-11 20:20:11 +01:00
windingwind e44e07eefa add: magic key command palette 2024-11-11 20:19:57 +01:00
windingwind 968eb0ef40 chore(publish): release v2.0.23 2024-11-11 10:32:13 +01:00
windingwind caa18fc5e2 fix: note editor plugin reconfigure
fix: #1190
fix: #1189
2024-11-11 10:32:04 +01:00
windingwind 4defc19ba3 chore(publish): release v2.0.22 2024-11-10 17:41:36 +01:00
windingwind ec1674cf11 add: paste plaintext markdown into note editor
resolve: #1185
2024-11-10 17:41:27 +01:00
windingwind 136b15aa38 chore(publish): release v2.0.21 2024-11-09 20:48:30 +01:00
windingwind 7859df48c0 update: rework export window 2024-11-09 20:48:14 +01:00
windingwind fccdd28677 update: deps 2024-11-09 17:33:08 +01:00
windingwind df1f5c58d6 chore(publish): release v2.0.20 2024-11-09 12:16:14 +01:00
windingwind 2f5eadda58 fix: MessageHelper dev flag 2024-11-09 12:16:01 +01:00
windingwind 59ab1413ad refactor: relation worker use MessageHelper 2024-11-09 12:15:02 +01:00
windingwind ba4ffb03db update: vscode launch.json 2024-11-09 11:46:22 +01:00
windingwind 6f8aa89276 fix: image viewer
move: toolbutton.css
2024-11-09 11:46:11 +01:00
windingwind 6d9402c12e chore(publish): release v2.0.19 2024-11-07 20:29:47 +01:00
windingwind 5e42e3db3d add: use `note.css` for note export to PDF
update: lint
2024-11-07 20:29:27 +01:00
windingwind e859fe8cd9 update: funding.yml 2024-10-26 10:38:34 +02:00
windingwind 4dbb34819d update: deps 2024-10-23 20:29:15 +02:00
windingwind 6332ef73c1 chore(publish): release v2.0.18 2024-10-21 17:56:30 +02:00
windingwind da68a449d2 add: parsing worker
fix: #1166
2024-10-21 17:37:32 +02:00
windingwind 5409a57e7d fix: outlinePane notifier id 2024-10-21 15:53:24 +02:00
windingwind 10fc0d5706 fix: skip auto-sync for all opened notes 2024-10-21 15:50:39 +02:00
windingwind 99d8bb4679 resolve: #1167 2024-10-21 10:18:22 +02:00
windingwind 1fa18a3540 chore(publish): release v2.0.17 2024-10-18 17:29:30 +02:00
windingwind 4a871a8c21 add: share button in template editor 2024-10-18 17:29:18 +02:00
windingwind 235362e160 chore(publish): release v2.0.16 2024-10-13 22:56:06 +02:00
windingwind 673c0bbce0 fix: template render
remove: do not support markdown backtick grammar
2024-10-13 22:55:58 +02:00
windingwind 49c6c0ba9b chore(publish): release v2.0.15 2024-10-13 16:26:50 +02:00
windingwind d02c35e2f0 fix: template editor help button 2024-10-13 16:15:19 +02:00
windingwind 314f3a0811 add: template editor format buttons 2024-10-13 10:45:49 +02:00
windingwind 196df9a915 chore(publish): release v2.0.14 2024-10-11 11:53:28 +02:00
windingwind 13e172a96c add: hover to show note link preview 2024-10-11 11:49:54 +02:00
windingwind ef1bbe1d73 fix: tree view parentId parsing
fix: #1156
2024-10-11 10:50:50 +02:00
windingwind d85d27f589 chore(publish): release v2.0.13 2024-10-11 10:40:47 +02:00
windingwind b3d8248c1f fix: template picker table height 2024-10-11 10:40:38 +02:00
windingwind 44fd14e8ed chore(publish): release v2.0.12 2024-10-07 21:36:18 +02:00
windingwind ec01f1c51f add: support creating note from template in library and group 2024-10-07 21:36:09 +02:00
windingwind 98fa74ed89 refactor: template picker
Use picker window to replace the PromptManager from toolkit
2024-10-07 21:05:44 +02:00
windingwind afab600f53 chore(publish): release v2.0.11 2024-10-05 13:08:07 +02:00
windingwind 58f9cc63d9 update: deps
fix: #1152
fix: #1153
2024-10-05 13:07:54 +02:00
windingwind 6e27f5ea62 update: use workspace typescript 2024-10-03 16:44:25 +02:00
windingwind 698f8631a0 chore(publish): release v2.0.10 2024-10-03 16:42:14 +02:00
windingwind c55694018a fix: tsc errors
update: scaffold

chore(publish): release v2.0.11

fix: tsc errors
2024-10-03 16:41:46 +02:00
windingwind 08adac1c43 update: ztoolkit 2024-10-03 15:12:44 +02:00
windingwind b356590622 chore(publish): release v2.0.9 2024-10-02 17:40:52 +02:00
ezellohar 0a73c0efee
Updated italian translation (#1147)
* Updated translation

* Update addon.ftl

* updated italian translation
2024-10-01 11:11:29 +02:00
windingwind fca3899e8d update: locale variables for template editor 2024-09-21 23:02:11 +02:00
windingwind 12e0ac971f chore(publish): release v2.0.8 2024-09-21 22:45:18 +02:00
windingwind 59693f2de4 fix: note link preview list item wrap
fix: #1135
2024-09-21 22:45:06 +02:00
windingwind dc10c10e8a chore(publish): release v2.0.7 2024-09-13 09:43:54 +02:00
windingwind 0855272ae0 update: deps 2024-09-13 09:43:48 +02:00
windingwind 309483b7e7 chore(publish): release v2.0.6 2024-09-12 10:17:55 +02:00
windingwind 500f89d1ba add: template editor list tag margin 2024-09-12 08:17:26 +00:00
windingwind 472d7ec106 add: select inserted snippet in template editor 2024-09-12 08:17:26 +00:00
windingwind fae986bce0 add: markdown snippets in template editor 2024-09-12 08:17:26 +00:00
windingwind dcd84e1e53 fix: update snippets after changing template type in template editor 2024-09-12 08:17:26 +00:00
windingwind 5caced3578 add: template editor snippets 2024-09-12 08:17:26 +00:00
windingwind 8efc32b78c chore(publish): release v2.0.5 2024-09-08 21:37:20 +02:00
windingwind 708283f3c6 fix: improve template editor preview error message 2024-09-08 21:37:11 +02:00
windingwind 15ca55bca7 add: template editor name edit improvements 2024-09-08 21:17:41 +02:00
windingwind fb8d20726a add: template editor label 2024-09-08 20:15:47 +02:00
windingwind ec96373413 add: keep tags of note from annotation in sync with the original annotation
resolve: #1095
2024-09-08 17:21:44 +02:00
windingwind 887d71487e update: ztoolkit v3 2024-09-08 16:52:27 +02:00
windingwind 73b4765069 chore(publish): release v2.0.4 2024-09-08 10:39:46 +02:00
windingwind 7dce2b0bdc fix: export to pdf image size
fix: #1103
fix: renderNoteHTML image height
2024-09-08 10:39:37 +02:00
windingwind ba50c9d7df update: lint 2024-08-28 22:05:49 +08:00
windingwind 0af915935b chore(publish): release v2.0.3 2024-08-24 10:42:06 +08:00
windingwind b441a2fb66 fix: open empty note in tab 2024-08-24 10:41:55 +08:00
windingwind 715d62756e
fix: readme link 2024-08-24 10:40:46 +08:00
windingwind 59ea297b17
Update README.md for 2.0.0 2024-08-24 10:38:54 +08:00
windingwind 4d785a3d1f chore(publish): release v2.0.2 2024-08-23 22:41:14 +08:00
windingwind 9975ae7d33 fix: link creator window dragging 2024-08-23 22:40:08 +08:00
windingwind 51fe82d70a chore(publish): release v2.0.1 2024-08-23 22:14:30 +08:00
windingwind 8cd6f12557 add: support multi-select in note picker
resolve: #1041
2024-08-23 22:14:16 +08:00
windingwind a0489f733d add: recent notes in note picker 2024-08-23 21:20:53 +08:00
windingwind 60a5ea8974 fix: should create new note from annotation if the linked one is deleted
fix: #1076
2024-08-23 18:51:52 +08:00
windingwind d1e48dc084 update: make template refresh stable 2024-08-23 18:45:14 +08:00
windingwind 1dea08ba8c fix: window button layout 2024-08-23 18:43:43 +08:00
windingwind 54bfd09fdd fix: rehype2note code node conversion should preserve wrap
fix: #1083
2024-08-23 18:40:24 +08:00
windingwind 0ecc74a6e8 update: use-refresh doc 2024-08-23 17:43:57 +08:00
windingwind be035893da fix: always open note from annotation in builtin window
fix: #1093
2024-08-23 17:19:01 +08:00
windingwind 3a5c92d070 update: target to Zotero 7's version 2024-08-09 15:58:15 +08:00
windingwind 3672b5f441 chore(publish): release v2.0.0 2024-08-09 15:54:48 +08:00
windingwind feec972217 update: readme 2024-08-09 15:54:23 +08:00
windingwind f3aaf3df41 chore(publish): release v1.1.4-beta.113 2024-08-04 18:03:21 +08:00
windingwind edaad57418 fix: relation section init bug 2024-08-04 18:03:12 +08:00
windingwind 1811a32b9a chore(publish): release v1.1.4-beta.112 2024-08-04 12:54:13 +08:00
windingwind 1b9f24d699 fix: link creator no titlebar on macos 2024-08-04 12:54:02 +08:00
windingwind 172b6418ba fix: do not render sections outside workspace 2024-08-04 12:51:47 +08:00
windingwind d1e02bf42d
update: tg links in readme 2024-08-02 23:04:01 +08:00
windingwind 4354cbbbf2
add: tg link in readme 2024-08-02 23:00:10 +08:00
windingwind 2fe9356afe chore(publish): release v1.1.4-beta.111 2024-08-02 22:25:05 +08:00
windingwind 288d1bdaa6 fix: release workflow token 2024-08-02 22:24:56 +08:00
windingwind 1f515cfdf9 chore(publish): release v1.1.4-beta.110 2024-08-02 22:10:18 +08:00
windingwind f3fe11f40d add: tg bot 2024-08-02 22:09:37 +08:00
172 changed files with 8799 additions and 8602 deletions

View File

@ -31,7 +31,7 @@ body:
id: bn_version
attributes:
label: Test on Better Notes version
description: Please provide the Better Notes version you are using here. You can find this in the menu -> Edit -> Settings -> Better Notes.
description: Please provide the Better Notes version you are using here. You can find this in the Settings -> Better Notes.
placeholder: e.g. 1.0.4
validations:
required: true
@ -43,7 +43,6 @@ body:
- Item
- Text
- QuickInsert
- QuickBackLink
- QuickImport
- QuickNote
- ExportMDFileName

4
.github/FUNDING.yml vendored
View File

@ -6,8 +6,8 @@ open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: windingwind
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: ["https://paypal.me/windingwind?country.x=C2&locale.x=zh_XC"]
custom: ["https://paypal.me/windingwind"]

View File

@ -1,9 +1,12 @@
name: Release
name: CI
on:
push:
tags:
- v**
pull_request:
branches:
- master
permissions:
contents: write
@ -11,10 +14,33 @@ permissions:
pull-requests: write
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install deps
run: npm install -f
- name: Test
run: npm test
# If it's triggered by a tag and the test job is successful, release the package
release:
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' && needs.test.result == 'success'
env:
GITHUB_TOKEN: ${{ secrets.GitHub_TOKEN }}
# Allow triggering other workflows
GITHUB_TOKEN: ${{ secrets.PAT }}
steps:
- name: Checkout
uses: actions/checkout@v4

19
.github/workflows/tgbot.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Notify Telegram on Release
on:
release:
types: [published]
jobs:
send_message:
runs-on: ubuntu-latest
steps:
- name: Send Telegram Message
run: |
msg_text='
📢 A new release of ${{ github.repository }} is published: ${{ github.event.release.tag_name }}
Release Name: ${{ github.event.release.name }}
Description: ${{ github.event.release.body }}
You can check updates in Zotero to get the latest version, or view on GitHub: ${{ github.event.release.html_url }}'
curl -s -X POST 'https://api.telegram.org/bot${{ secrets.TG_BOT_TOKEN }}/sendMessage' \
-d "chat_id=${{ secrets.TG_CHAT_ID }}&text=${msg_text}&reply_to_message_id=${{ secrets.TG_MSG_ID }}"

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ pnpm-lock.yaml
yarn.lock
zotero-cmd.json
.DS_Store
.env
.env
.scaffold

23
.vscode/launch.json vendored
View File

@ -1,7 +1,4 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
@ -9,28 +6,14 @@
"request": "launch",
"name": "StartDev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start-watch"]
"runtimeArgs": ["run", "start"]
},
{
"type": "node",
"request": "launch",
"name": "Restart",
"name": "Lint",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "restart"]
},
{
"type": "node",
"request": "launch",
"name": "Reload",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "reload"]
},
{
"type": "node",
"request": "launch",
"name": "Restart in Prod Mode",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "restart-prod"]
"runtimeArgs": ["run", "lint"]
}
]
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}

View File

@ -18,13 +18,13 @@
"\tremoveIfExists: ${13:true},",
"\tcustomCheck: (doc: Document, options: ElementOptions) => ${14:true},",
"\tchildren: [$15]",
"}, ${16:container});"
]
"}, ${16:container});",
],
},
"appendElement - minimum": {
"scope": "javascript,typescript",
"prefix": "appendElement",
"body": "appendElement({ tag: '$1' }, $2);"
"body": "appendElement({ tag: '$1' }, $2);",
},
"register Notifier": {
"scope": "javascript,typescript",
@ -39,7 +39,7 @@
"\t) => {",
"\t\t$0",
"\t}",
"});"
]
}
"});",
],
},
}

139
README.md
View File

@ -2,12 +2,13 @@
[![zotero target version](https://img.shields.io/badge/Zotero-7-green?style=flat-square&logo=zotero&logoColor=CC2936)](https://www.zotero.org)
[![Using Zotero Plugin Template](https://img.shields.io/badge/Using-Zotero%20Plugin%20Template-blue?style=flat-square&logo=github)](https://github.com/windingwind/zotero-plugin-template)
[![telegram group](https://img.shields.io/badge/Join%20Community-@bnzotero-blue?style=flat-square&logo=telegram)](https://t.me/boost/bnzotero)
<div align=center><img src="./docs/res/teaser.png" width="800px"></img></div>
Everything about note management. All in Zotero.
Better Notes Handbook (outdated, for version<=0.8.9): [中文 (provide translation)](https://zotero.yuque.com/staff-gkhviy/better-notes/biigg4?)
Join the community on Telegram: [@bnzotero](https://t.me/boost/bnzotero)
## 🧩 Outline
@ -22,7 +23,7 @@ Better Notes Handbook (outdated, for version<=0.8.9): [中文 (provide translati
<details style="text-indent: 2em">
<summary>More</summary>
[Getting Started with the _Workspace_](#getting-started-with-the-workspace)
[Getting Started by Opening a Note Tab](#getting-started-by-opening-a-note-tab)
[Note Editor](#note-editor)
@ -87,13 +88,11 @@ and:
## 👋 Install
- Download the plugin (.xpi file) from below. For Zotero 7 beta, please always use the latest beta version.
- Download the plugin (.xpi file) from below.
- [Latest Version: 1.1.4-beta.109](https://github.com/windingwind/zotero-better-notes/releases/download/v1.1.4-beta.109/better-notes-for-zotero.xpi)
- [Latest Version: 2.2.5](https://github.com/windingwind/zotero-better-notes/releases/download/v2.2.5/better-notes-for-zotero.xpi)
- [Latest Stable](https://github.com/windingwind/zotero-better-notes/releases/latest)
- [v1.0.4](https://github.com/windingwind/zotero-better-notes/releases/tag/1.0.4) (last for Zotero 6)
- [v0.8.9](https://github.com/windingwind/zotero-better-notes/releases/tag/0.8.9) (last with auto-insert, tag-insert, math-ocr, for Zotero 6)
- [All Releases](https://github.com/windingwind/zotero-better-notes/releases) (including beta plugin for Zotero 7 beta)
- [All Releases](https://github.com/windingwind/zotero-better-notes/releases)
_Note_: If you're using Firefox as your browser, right-click the `.xpi` and select "Save As.."
@ -109,61 +108,66 @@ BN offers a range of features that can be combined like Lego blocks to build you
Start taking notes in Zotero with BN in **5 minutes**!
### Getting Started with the _Workspace_
### Getting Started by Opening a Note Tab
> 💡 This section is outdated and will be removed. For the latest beta version, the workspace is no longer a thing. You can open unlimited number of note tab/window, which is what we call `workspace` in the past.
> 💡 In the latest version, the workspace is no longer a thing. You can open an unlimited number of note tabs/windows, which is what we called `workspace` in the past.
The _workspace_ serves as the **central hub** where input flows (papers and annotations) converge with output flows (summaries and comparisons).
To open a note in a tab, double-click/press `Enter` on the item in the library, as you would do to open an attachment. Holding `shift` opens the note in a new window.
To open the _workspace_, click the <img src="addon/chrome/content/icons/favicon.png" alt="icon" width="20px"> button in the tabs bar.
<div align=center><img src="https://github.com/user-attachments/assets/0824293b-765d-47af-8815-66f009adab0e" width="800px"></img></div>
<div align=center><img src="https://user-images.githubusercontent.com/33902321/236622132-5ed9bd23-3c0e-4775-b273-745824cc4b51.gif" width="800px"></img></div>
The _workspace_ contains a default note called the _workspace note_. You can create a new note as the _workspace note_ if prompted on opening _workspace_.
> 💡 How to set an existing note as the _workspace note_?
>
> 1. In the library: select a note item and right-click
> 2. In the note editor: click on the Tools button
>
> You can change the _workspace note_ at any time.
The _workspace_ allows you to take notes and write, just like you would in MS Word or a markdown editor (e.g., Obsidian).
> **Explore the _Workspace_!**
> **Explore the Note Tab!**
> 💡 The layout from left to right is:
>
> - Outline
> - _Workspace note_ editor (main editor)
> - Note link preview (hidden by default)
> - Reader notes pane (hidden by default)
>
> 💡 To toggle these panes, hover the _workspace_ tab and click corresponding buttons.
> 💡 To open the _workspace_ in a new window, drag the _workspace_ tab.
> - Note editor
> - Context pane (tags, related, relation graph, in/outbound links)
### Note Editor
The _workspace_ includes the note editor for the _workspace note_. You can use it to take notes and write summaries.
> 💡 How to open note editor?
> 💡 Where can I find the note editor?
>
> - In the library: click to open a note editor and double-click to open note editor in a standalone window.
> - In the PDF reader: right-side bar
> - In the note tab/window
> - In the library: click to open a note editor in the item pane
> - In the PDF reader: right-side context pane
>
> 💡 How to create a new note?
> Click the note icon in the library tools bar (the row under the tabs bar).
> Click the note icon in the library tools bar (the row under the tabs bar), or from the menu - File
<div align=center><img src="https://user-images.githubusercontent.com/33902321/236622355-2b8b2c00-a640-41fa-bb82-372fa10ecc64.png" width="400px"></img></div>
<div align=center><img src="https://github.com/user-attachments/assets/ec2ba415-8ec9-450d-9d73-d24d177ccd13" width="400px"></img></div>
#### Magic Key
BN enhances the note editor with a _Magic Key_ command palette, which can be opened by typing `/` in the editor. You can type or use the arrow keys to navigate the commands, and press `Enter` to execute.
<div align=center><img src="https://github.com/user-attachments/assets/bdbe244e-c120-4d9b-aa28-5285a25a723a" width="800px"></img></div>
#### Note Link Preview
BN enhances the note editor with link preview. Hover+Ctrl/Cmd or click the link to preview the linked note without leaving the current note.
<div align=center><img width="400px" alt="image" src="https://github.com/user-attachments/assets/b29769a1-3436-42bd-8481-eee1c0b4896a"></div>
#### Direct Markdown Paste
BN supports direct markdown paste. You can paste markdown content into the note editor, and it will be converted to the rich text format automatically.
### Note Link
To create a _note link_ between current note and the _workspace note_, simply click the <img src="addon/chrome/content/icons/favicon.png" width="20px"></img> button in the title bar of current note editor.
To create a _note link_ between the note you are editing and another note, click the <img src="addon/chrome/content/icons/favicon.png" width="20px"></img> button in the title bar of the note editor.
<div align=center><img src="https://user-images.githubusercontent.com/33902321/236622693-f7c7c82f-7434-4dbf-baf3-d03a72eb51c5.png" width="800px"></img></div>
<div align=center><img src="https://github.com/user-attachments/assets/e37a694b-613e-4242-9c14-d83708a3d1e7" width="800px"></img></div>
> 💡 What's the difference between `Mention in` and `Link to`?
>
> `Mention in` will insert a link of the current note (from which you open the link creator) to another note (which you pick in the link creator), i.e. inbound link.
> `Link to` will insert links of picked notes to the current note, i.e. outbound link.
You can also manually copy the note link from the note editor menu.
### Note Template
Still spending a lot of time writing summaries or doing copy-pasting while taking notes? Say hello to _Note Template_!
Are you spending a lot of time writing summaries and copy-pasting while taking notes? Say hello to _Note Template_!
_Note Template_ is designed for tasks like:
@ -173,13 +177,13 @@ _Note Template_ is designed for tasks like:
> 💡 Need help or looking for community templates? [See here →](https://github.com/windingwind/zotero-better-notes/discussions/categories/note-templates)
>
> 💡 Want to write/share your own templates?
> 💡 Want to write/share your templates?
>
> [How to write →](docs/about-note-template.md#write-note-template)
>
> [How to share →](docs/about-note-template.md#share-your-template)
<div align=center><img src="https://user-images.githubusercontent.com/33902321/236623159-8f67064b-1fab-4cf1-abf4-0c8243370a14.gif" width="800px"></img></div>
<div align=center><img src="https://github.com/user-attachments/assets/62e1438f-7910-4f57-ad88-c6a41dd9addf" width="800px"></img></div>
### Syncing: Note 🔄️ Markdown
@ -207,15 +211,9 @@ You can export your note to the following formats:
Simply click on the corresponding export button in the toolbar and follow the prompts.
### GPT Integration
### LLM Integration
The [Zotero-GPT](https://github.com/MuiseDestiny/zotero-gpt) plugin provides GPT Integration. If you also have Better Notes installed, you can wake up GPT pane in the _workspace_ note editor with `space` key.
You can:
- Ask GPT questions about current note
- Summarize/fix spelling and grammar/translate/polish the selection
- Accept suggestions/modifications from GPT with `enter` key.
The [Zotero-GPT](https://github.com/MuiseDestiny/zotero-gpt) plugin provides GPT Integration. If you also have Better Notes installed, you can wake up its chatting pane in the note editor and insert/modify content in the note.
### Action Workflow
@ -228,7 +226,7 @@ The [Actions & Tags](https://github.com/windingwind/zotero-actions-tags) plugin
### Other Features
- Quick Note: convert annotation to note with one click.
- Resize images with right-click menu.
- Resize images with a right-click menu.
- Preview images with double-click/ctrl-click.
## 🧲 API
@ -241,13 +239,24 @@ BN provides APIs for other plugin developers in `Zotero.BetterNotes.api.${API_MO
- `template`: Manipulate note templates
- `$export`: Export note
- `$import`: Import note
- `editor`: Note editor APIs. Give your script the full control of contents in the note editor.
- `editor`: Note editor APIs. Give your script full control of contents in the note editor.
- `note`: Note APIs. Parse and manipulate note content.
- `relation`: Note relation APIs. Get and set note relations.
- `utils`: Utility functions.
### Concepts about Note-Related APIs
In Zotero, the content of a note is stored as rich text, while when a note is opened in the note editor, it is rendered by ProseMirror as HTML.
Most of the time, it is recommended to use the `editor` API to interact with the content of the note, as it supports undo/redo and other features provided by editor. The `editor` API provides a set of powerful functions to analyze and manipulate the content in the note editor. Most of them needs an `editor` instance as the input, you can get the instance by calling `Zotero.BetterNotes.api.editor.getEditorInstance(noteId)`.
However, if note is not opened in the editor, you cannot get the `editor` instance. In this case, you can use the `note` API to interact with the content of the note.
## 🔧 Development
This plugin is built based on the [Zotero Plugin Template](https://github.com/windingwind/zotero-plugin-template). See the setup and debug details there.
To startup, run
To start, run
```bash
git clone https://github.com/windingwind/zotero-better-notes.git
@ -258,15 +267,31 @@ npm run build
The plugin is built to `./builds/*.xpi`.
To debug, run
```bash
npm run start
```
This will open a new Zotero instance with the plugin installed.
To test the plugin, run
```bash
npm run test
```
This will run the tests in the `./test` directory.
## 🔔 Disclaimer
Use this code under AGPL. No warranties are provided. Keep the laws of your locality in mind!
## 🔎 My Zotero Plugins
- [Translate for Zotero](https://github.com/windingwind/zotero-pdf-translate): PDF translation for Zotero
- [zotero-pdf-preview](https://github.com/windingwind/zotero-tag): PDF preview for Zotero
- [zotero-tag](https://github.com/windingwind/zotero-tag): Automatically tag items/Batch tagging
- [Translate for Zotero](https://github.com/windingwind/zotero-pdf-translate): Translate PDF, EPub, webpage, metadata, annotations, notes to the target language.
- [Actions & Tags for Zotero](https://github.com/windingwind/zotero-tag): Customize your Zotero workflow.
- [Bionic for Zotero](https://github.com/windingwind/bionic-for-zotero): Bionic reading experience with Zotero.
## 🙌 Sponsors

2
addon/bootstrap.js vendored
View File

@ -37,7 +37,7 @@ async function startup({ id, version, resourceURI, rootURI }, reason) {
`${rootURI}/chrome/content/scripts/__addonRef__.js`,
ctx,
);
Zotero.__addonInstance__.hooks.onStartup();
await Zotero.__addonInstance__.hooks.onStartup();
}
function onMainWindowLoad({ window: win }) {

View File

@ -0,0 +1,102 @@
<?xml version="1.0"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://zotero-platform/content/zotero.css" type="text/css"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://__addonRef__/content/styles/exportNotes.css" type="text/css"?>
<!-- prettier-ignore -->
<!DOCTYPE window>
<window
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
id="bn-export-notes"
data-l10n-id="title"
windowtype="__addonRef__-export-notes"
persist="screenX screenY width height sizemode"
style="min-width: 10em"
drawintitlebar-platforms="mac"
>
<xul:linkset>
<html:link rel="localization" href="browser/menubar.ftl" />
<html:link rel="localization" href="browser/browserSets.ftl" />
<html:link rel="localization" href="toolkit/global/textActions.ftl" />
<html:link rel="localization" href="zotero.ftl" />
<html:link rel="localization" href="__addonRef__-exportNotes.ftl" />
</xul:linkset>
<xul:commandset id="mainCommandSet">
<xul:command id="cmd_close" oncommand="window.close();" />
</xul:commandset>
<xul:keyset id="mainKeyset">
<xul:key
id="key_close"
data-l10n-id="close-shortcut"
command="cmd_close"
modifiers="accel"
reserved="true"
/>
</xul:keyset>
<script src="chrome://zotero/content/include.js"></script>
<script src="chrome://zotero/content/titlebar.js"></script>
<script src="chrome://zotero/content/customElements.js"></script>
<script src="chrome://__addonRef__/content/scripts/exportNotes.js"></script>
<dialog
buttons="accept, cancel, extra1"
buttonlabelextra1="Use System Export..."
>
<vbox>
<hbox>
<label id="target" data-l10n-id="target"></label>
</hbox>
<hbox align="center">
<label data-l10n-id="format" for="format"></label>
<menulist id="format" native="true">
<menupopup>
<menuitem
value="markdown"
data-l10n-id="format-markdown"
></menuitem>
<menuitem value="msword" data-l10n-id="format-msword"></menuitem>
<menuitem value="pdf" data-l10n-id="format-pdf"></menuitem>
<menuitem
value="freemind"
data-l10n-id="format-freemind"
></menuitem>
<menuitem value="note" data-l10n-id="format-note"></menuitem>
</menupopup>
</menulist>
</hbox>
<vbox>
<radiogroup id="linkMode" orient="vertical">
<radio value="keep" data-l10n-id="links-keep"></radio>
<radio value="embed" data-l10n-id="links-embed"></radio>
<radio value="standalone" data-l10n-id="links-standalone"></radio>
<!-- <radio value="remove" data-l10n-id="links-remove"></radio> -->
</radiogroup>
</vbox>
<vbox id="markdown-options">
<checkbox
id="markdown-autoSync"
data-l10n-id="markdown-autoSync"
native="true"
></checkbox>
<checkbox
id="markdown-withYAMLHeader"
data-l10n-id="markdown-withYAMLHeader"
native="true"
></checkbox>
<checkbox
id="markdown-autoFilename"
data-l10n-id="markdown-autoFilename"
native="true"
></checkbox>
</vbox>
</vbox>
</dialog>
</window>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="a" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<polygon
points="3.43 9.96 3.43 16.46 6.78 16.46 6.78 15.21 4.68 15.21 4.68 4.79 6.78 4.79 6.78 3.54 3.43 3.54 3.43 9.96"
style="stroke-width: 0px;" fill="currentColor" />
<polygon
points="16.57 10.04 16.57 3.54 13.22 3.54 13.22 4.79 15.32 4.79 15.32 15.21 13.22 15.21 13.22 16.46 16.57 16.46 16.57 10.04"
style="stroke-width: 0px;" fill="currentColor" />
<path
d="m6.23,12.33c0-.38.12-.69.36-.9.24-.22.5-.32.8-.32.21,0,.4.07.55.2.15.13.23.31.23.54,0,.51-.27.87-.81,1.07.2.17.42.26.65.26.4,0,.72-.24.96-.73.15-.27.39-1.07.71-2.4.33-1.34.49-2.13.49-2.37,0-.28-.08-.48-.24-.6-.16-.12-.35-.18-.56-.18-.4,0-.78.17-1.16.5-.38.33-.66.75-.84,1.25-.06.19-.12.31-.17.36-.05.05-.15.08-.3.09h-.08c-.28,0-.41-.08-.41-.25,0-.13.06-.33.19-.59.13-.26.31-.54.54-.84.23-.3.56-.56.98-.78.42-.22.86-.33,1.34-.33.88,0,1.53.29,1.97.87.55-.58,1.1-.87,1.65-.87.46,0,.86.13,1.21.38.35.26.53.61.53,1.05,0,.39-.12.69-.36.91s-.5.33-.8.33c-.22,0-.41-.07-.56-.21-.15-.14-.22-.32-.22-.54,0-.51.27-.87.82-1.07-.2-.17-.42-.26-.66-.26-.15,0-.29.03-.42.09s-.25.18-.35.35c-.11.17-.2.33-.27.49-.08.15-.16.39-.25.7-.09.31-.16.57-.21.79-.05.21-.13.53-.23.96-.1.43-.18.76-.25,1.01-.13.51-.2.88-.2,1.12,0,.28.08.48.25.6.17.12.36.19.57.19.4,0,.78-.17,1.16-.5.38-.33.66-.74.84-1.23.01-.02.02-.05.03-.1.01-.04.02-.07.03-.09s.02-.04.03-.07.02-.05.02-.06c0,0,.02-.03.03-.05s.03-.04.05-.04c.02,0,.04-.01.06-.02.02,0,.05-.02.07-.02h.2c.28,0,.41.08.41.24,0,.4-.29.92-.88,1.56-.59.65-1.31.97-2.16.97-.93,0-1.59-.29-2-.87h-.02c-.47.58-1.01.87-1.63.87-.45,0-.85-.13-1.2-.38-.35-.25-.53-.6-.53-1.05Z"
style="stroke-width: 0px;" fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,6 @@
<svg t="1728768259016" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4687"
width="20" height="20">
<path
d="M181.333333 509.866667v332.8H352.64v-64H245.333333V245.333333h107.306667v-64H181.333333v328.533334z m672.597334 4.266666v-332.8H682.666667v64h107.306666v533.333334H682.666667v64H853.930667v-328.533334z m-397.568 223.061334l85.930666-214.826667 84.736-211.84-59.434666-23.765333-84.693334 211.84-85.930666 214.826666 59.392 23.765334z"
fill="currentColor" p-id="4688"></path>
</svg>

After

Width:  |  Height:  |  Size: 559 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8V4.5V2H7.5H12C13.933 2 15.5 3.567 15.5 5.5C15.5 7.433 13.933 9 12 9C14.2091 9 16 10.7909 16 13C16 15.2091 14.2091 17 12 17H7.5H4V14.5V10.5V8ZM7.5 10.5V14.5H10.5C11.6046 14.5 12.5 13.6046 12.5 12.5C12.5 11.3954 11.6046 10.5 10.5 10.5H7.5ZM7.5 8V4.5H10.25C11.2165 4.5 12 5.2835 12 6.25C12 7.2165 11.2165 8 10.25 8H7.5Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@ -0,0 +1,6 @@
<svg t="1728768172242" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4279"
width="20" height="20">
<path
d="M256 426.666667a85.333333 85.333333 0 1 0 0-170.666667 85.333333 85.333333 0 0 0 0 170.666667z m597.333333-53.333334h-379.264v-64H853.333333v64z m0 298.666667h-379.264v-64H853.333333v64zM341.333333 640a85.333333 85.333333 0 1 1-170.666666 0 85.333333 85.333333 0 0 1 170.666666 0z"
fill="currentColor" p-id="4280"></path>
</svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -0,0 +1,6 @@
<svg t="1728768054402" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3427"
width="20" height="20">
<path
d="M170.666667 170.666667h682.666666v64H170.666667V170.666667z m597.333333 234.666666H256a21.333333 21.333333 0 0 0-21.333333 21.333334v170.666666a21.333333 21.333333 0 0 0 21.333333 21.333334h512a21.333333 21.333333 0 0 0 21.333333-21.333334v-170.666666a21.333333 21.333333 0 0 0-21.333333-21.333334zM256 341.333333h512a85.333333 85.333333 0 0 1 85.333333 85.333334v170.666666a85.333333 85.333333 0 0 1-85.333333 85.333334H256a85.333333 85.333333 0 0 1-85.333333-85.333334v-170.666666a85.333333 85.333333 0 0 1 85.333333-85.333334z m597.333333 448H170.666667V853.333333h682.666666v-64z"
fill="currentColor" p-id="3428"></path>
</svg>

After

Width:  |  Height:  |  Size: 809 B

View File

@ -0,0 +1,6 @@
<svg t="1728768084775" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3633"
width="20" height="20">
<path
d="M469.333333 298.666667h85.333334v426.666666h-85.333334v-170.666666H298.666667v170.666666H213.333333V298.666667h85.333334v170.666666h170.666666V298.666667z m281.6 0c-25.6 38.4-64 72.533333-110.933333 85.333333v42.666667h85.333333v298.666666h85.333334V298.666667h-59.733334z"
fill="currentColor" p-id="3634"></path>
</svg>

After

Width:  |  Height:  |  Size: 498 B

View File

@ -0,0 +1,6 @@
<svg t="1728768115138" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3879"
width="20" height="20">
<path
d="M384 302.933333h85.333333v426.666667H384v-170.666667H213.333333v170.666667H128v-426.666667h85.333333v170.666667h170.666667v-170.666667z m341.333333 341.333334c21.333333-17.066667 25.6-25.6 46.933334-46.933334 17.066667-17.066667 34.133333-34.133333 51.2-55.466666 12.8-17.066667 25.6-34.133333 38.4-55.466667 8.533333-17.066667 12.8-34.133333 12.8-55.466667 0-17.066667-4.266667-38.4-12.8-55.466666-8.533333-17.066667-17.066667-29.866667-34.133334-42.666667-12.8-12.8-29.866667-21.333333-51.2-25.6-21.333333-8.533333-42.666667-8.533333-64-8.533333-17.066667 0-29.866667 0-46.933333 4.266666-12.8 4.266667-29.866667 8.533333-42.666667 12.8-12.8 4.266667-25.6 12.8-38.4 21.333334-12.8 8.533333-25.6 17.066667-34.133333 29.866666l51.2 51.2c12.8-12.8 25.6-21.333333 42.666667-29.866666 17.066667-8.533333 29.866667-12.8 51.2-12.8s38.4 4.266667 55.466666 17.066666c12.8 12.8 21.333333 29.866667 21.333334 46.933334 0 17.066667-4.266667 34.133333-17.066667 46.933333-12.8 21.333333-25.6 38.4-42.666667 51.2-17.066667 17.066667-42.666667 38.4-68.266666 59.733333-25.6 21.333333-59.733333 46.933333-93.866667 68.266667v64h341.333333v-85.333333H725.333333z"
fill="currentColor" p-id="3880"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,6 @@
<svg t="1728768147139" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4077"
width="20" height="20">
<path
d="M601.6 605.866667c17.066667 12.8 34.133333 21.333333 51.2 29.866666 17.066667 8.533333 38.4 12.8 59.733333 12.8 21.333333 0 42.666667-4.266667 59.733334-12.8 12.8-4.266667 21.333333-21.333333 21.333333-34.133333 0-8.533333 0-17.066667-4.266667-25.6-4.266667-8.533333-12.8-12.8-21.333333-17.066667-12.8-4.266667-29.866667-8.533333-42.666667-12.8-21.333333-4.266667-42.666667-4.266667-64-4.266666v-68.266667c29.866667 4.266667 64-4.266667 93.866667-17.066667 17.066667-8.533333 25.6-21.333333 25.6-38.4 0-12.8-4.266667-25.6-17.066667-34.133333-12.8-8.533333-29.866667-12.8-46.933333-12.8-17.066667 0-34.133333 4.266667-46.933333 12.8-17.066667 8.533333-29.866667 17.066667-46.933334 25.6l-51.2-59.733333c21.333333-17.066667 46.933333-29.866667 68.266667-38.4 21.333333-8.533333 51.2-12.8 76.8-12.8 21.333333 0 42.666667 4.266667 68.266667 8.533333 17.066667 4.266667 34.133333 12.8 51.2 21.333333 12.8 8.533333 25.6 21.333333 34.133333 34.133334 8.533333 12.8 12.8 29.866667 12.8 46.933333 0 21.333333-8.533333 38.4-21.333333 55.466667-17.066667 17.066667-38.4 29.866667-64 38.4v4.266666c25.6 4.266667 51.2 17.066667 68.266666 34.133334 17.066667 17.066667 29.866667 38.4 29.866667 64 0 17.066667-4.266667 34.133333-12.8 51.2-8.533333 17.066667-21.333333 29.866667-38.4 38.4-17.066667 12.8-38.4 17.066667-55.466667 21.333333-21.333333 4.266667-42.666667 8.533333-68.266666 8.533333-34.133333 0-68.266667-4.266667-98.133334-17.066666-25.6-8.533333-46.933333-25.6-68.266666-42.666667l46.933333-59.733333zM384 469.333333H213.333333V298.666667H128v426.666666h85.333333v-170.666666h170.666667v170.666666h85.333333V298.666667H384v170.666666z"
fill="currentColor" p-id="4078"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="a" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<path d="m6.12,16l.88-.88L1.88,10l5.12-5.12-.88-.88L.12,10l6,6Zm7.77,0l-.88-.88,5.12-5.12-5.12-5.12.88-.88,6,6-6,6Z"
style="fill-rule: evenodd; stroke-width: 0px;" fill="currentColor" />
<path
d="m6.23,12.33c0-.39.12-.69.36-.9s.5-.32.8-.32c.21,0,.4.07.55.2s.23.31.23.54c0,.51-.27.87-.81,1.07.2.17.42.26.65.26.4,0,.72-.25.96-.73.15-.27.39-1.07.71-2.4s.49-2.13.49-2.37c0-.28-.08-.48-.24-.6s-.34-.18-.56-.18c-.4,0-.78.17-1.16.5s-.66.75-.84,1.25c-.06.19-.12.31-.17.36s-.15.08-.3.09h-.08c-.28,0-.41-.08-.41-.25,0-.13.06-.33.19-.59s.31-.54.54-.84.56-.56.98-.78.86-.33,1.34-.33c.88,0,1.53.29,1.97.87.55-.58,1.1-.87,1.65-.87.46,0,.86.13,1.21.38s.53.61.53,1.05c0,.39-.12.69-.36.91s-.5.33-.8.33c-.22,0-.41-.07-.56-.21s-.22-.32-.22-.54c0-.51.27-.87.82-1.07-.2-.17-.42-.26-.66-.26-.15,0-.29.03-.42.09s-.25.18-.35.35-.2.33-.27.49-.16.39-.25.7-.16.57-.21.79-.13.53-.23.96-.18.76-.25,1.01c-.13.51-.2.88-.2,1.12,0,.28.08.48.25.6s.36.19.57.19c.4,0,.78-.17,1.16-.5s.66-.74.84-1.23c.01-.02.02-.05.03-.1s.02-.07.03-.09.02-.04.03-.07.02-.05.02-.06.02-.03.03-.05.03-.04.05-.04.04-.01.06-.02.05-.02.07-.02h.2c.28,0,.41.08.41.24,0,.4-.29.92-.88,1.56s-1.31.97-2.16.97c-.93,0-1.59-.29-2-.87h-.02c-.47.58-1.01.87-1.63.87-.45,0-.85-.13-1.2-.38-.35-.25-.53-.6-.53-1.05Z"
style="stroke-width: 0px;" fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="a" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<path d="m6.12,16l.88-.88L1.88,10l5.12-5.12-.88-.88L.12,10l6,6Zm7.77,0l-.88-.88,5.12-5.12-5.12-5.12.88-.88,6,6-6,6Z"
style="fill-rule: evenodd; stroke-width: 0px;" fill="currentColor" />
<polygon points="8.91 14.4 10.59 10.2 12.25 6.07 11.09 5.6 9.43 9.74 7.75 13.93 8.91 14.4" style="stroke-width: 0px;"
fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 476 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2H15V4H12.0164L11.9839 4.17889L10.0164 15H13V17H5V15H7.98361L8.01613 14.8211L9.98361 4H7V2Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 270 B

View File

@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1132_37385)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 8.125C0 5.70875 1.95875 3.75 4.375 3.75H9.625C12.0412 3.75 14 5.70875 14 8.125C14 10.5412 12.0412 12.5 9.625 12.5H8.60669C8.5376 12.3045 8.5 12.0941 8.5 11.875C8.5 11.6559 8.5376 11.4455 8.60669 11.25H9.625C11.3509 11.25 12.75 9.85089 12.75 8.125C12.75 6.39911 11.3509 5 9.625 5H4.375C2.64911 5 1.25 6.39911 1.25 8.125C1.25 9.85089 2.64911 11.25 4.375 11.25H4.78433C4.76165 11.4552 4.75 11.6637 4.75 11.875C4.75 12.0863 4.76165 12.2948 4.78433 12.5H4.375C1.95875 12.5 0 10.5412 0 8.125ZM10.3751 7.49999H11.3934C11.4625 7.69547 11.5001 7.90584 11.5001 8.12499C11.5001 8.34413 11.4625 8.5545 11.3934 8.74999H10.3751C8.64919 8.74999 7.25008 10.1491 7.25008 11.875C7.25008 13.6009 8.64919 15 10.3751 15H15.6251C17.351 15 18.7501 13.6009 18.7501 11.875C18.7501 10.1491 17.351 8.74999 15.6251 8.74999H15.2157C15.2384 8.54478 15.2501 8.33624 15.2501 8.12499C15.2501 7.91373 15.2384 7.7052 15.2157 7.49999H15.6251C18.0413 7.49999 20.0001 9.45874 20.0001 11.875C20.0001 14.2912 18.0413 16.25 15.6251 16.25H10.3751C7.95883 16.25 6.00008 14.2912 6.00008 11.875C6.00008 9.45874 7.95883 7.49999 10.3751 7.49999Z" fill="currentColor"/>
</g>
<defs>
<clipPath id="clip0_1132_37385">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_6179_36208)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.0971 9L11.0138 9.50002L9.99326 15.6224C9.62633 17.8241 7.5441 19.3114 5.34247 18.9444C4.24166 18.761 3.31942 18.1487 2.71826 17.307L4.34573 16.1446C4.64939 16.5697 5.11523 16.879 5.67127 16.9716C6.78335 17.157 7.83513 16.4057 8.02048 15.2936L8.98619 9.50002L9.06953 9H4.99999V7H9.40286L10.0066 3.37761C10.3735 1.17599 12.4558 -0.311319 14.6574 0.055618C15.7582 0.239087 16.6804 0.851379 17.2816 1.69301L15.6541 2.85548C15.3505 2.43036 14.8846 2.12108 14.3286 2.02841C13.2165 1.84306 12.1647 2.59433 11.9794 3.70641L11.4305 7H16V9H11.0971Z" fill="currentColor"/>
</g>
<defs>
<clipPath id="clip0_6179_36208">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 866 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.11621 16L7.00009 15.1161L1.88398 10L7.00009 4.88388L6.11621 4L0.116211 10L6.11621 16ZM13.884 16L13.0001 15.1161L18.1162 10L13.0001 4.88388L13.884 4L19.884 10L13.884 16Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@ -0,0 +1,6 @@
<svg t="1728768200791" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4481"
width="20" height="20">
<path
d="M256 226.389333V426.666667H213.333333V285.610667l-35.925333 11.946666-13.482667-40.448 64-21.333333 28.074667-9.386667zM853.333333 373.333333h-379.264v-64H853.333333v64z m0 298.666667h-379.264v-64H853.333333v64zM194.730667 530.688c20.565333-6.101333 52.437333-10.410667 72.618666 15.658667 10.794667 13.952 12.202667 31.829333 9.984 46.506666-3.242667 21.418667-17.194667 47.914667-28.928 70.186667-3.712 7.082667-7.253333 13.738667-10.069333 19.626667H277.333333v42.666666H162.816c10.794667-18.645333 20.778667-35.712 30.592-52.522666l31.274667-53.802667c5.376-9.386667 15.786667-33.450667 6.826666-45.013333-3.84-4.949333-13.994667-10.325333-28.501333-5.973334-13.141333 3.84-24.874667 14.378667-33.024 21.674667l-0.298667 0.256-5.546666-46.165333c8.96-4.864 19.626667-9.813333 30.592-13.098667z"
fill="currentColor" p-id="4482"></path>
</svg>

After

Width:  |  Height:  |  Size: 1023 B

View File

@ -0,0 +1,6 @@
<svg t="1728767929805" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3225"
width="20" height="20">
<path
d="M170.666667 373.333333h682.666666v-64H170.666667v64z m341.333333 298.666667h341.333333v-64h-341.333333v64z m-342.613333 105.386667l126.72-126.72-126.72-126.72 45.226666-45.226667 149.333334 149.333333 22.613333 22.613334-22.613333 22.613333-149.333334 149.333333-45.226666-45.226666z"
fill="currentColor" p-id="3226"></path>
</svg>

After

Width:  |  Height:  |  Size: 509 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 2C8.85166 2 7.64614 2.28406 6.6953 2.91795C5.71482 3.5716 5 4.61209 5 6C5 6.77149 5.16552 7.44802 5.49725 8.02784C5.71987 8.41695 6.00217 8.73606 6.31739 9H2V10.25H9.10026C9.38748 10.3245 9.66916 10.3907 9.93645 10.4535L9.93646 10.4536L10.021 10.4734C11.1302 10.7344 12.0126 10.9532 12.6404 11.3471C12.9309 11.5294 13.1326 11.7308 13.2668 11.9653C13.3999 12.198 13.5 12.5215 13.5 13C13.5 13.9401 13.1463 14.4997 12.6183 14.8653C12.0364 15.2682 11.1404 15.5 10 15.5C7.79256 15.5 6.5 14.2197 6.5 13H4.5C4.5 15.7803 7.20744 17.5 10 17.5C11.3596 17.5 12.7136 17.2318 13.7567 16.5097C14.8537 15.7503 15.5 14.5599 15.5 13C15.5 12.2285 15.3345 11.552 15.0028 10.9722C14.8462 10.6985 14.6602 10.4595 14.4539 10.25H18V9H12.2582C11.6828 8.80946 11.0947 8.67127 10.5635 8.54645L10.5635 8.54645L10.479 8.52658C9.36982 8.26559 8.48741 8.04685 7.85962 7.65294C7.56905 7.47062 7.36738 7.26916 7.23322 7.03466C7.1001 6.80198 7 6.47851 7 6C7 5.38791 7.28518 4.9284 7.8047 4.58205C8.35386 4.21594 9.14834 4 10 4C10.8517 4 11.6461 4.21594 12.1953 4.58205C12.7148 4.9284 13 5.38791 13 6H15C15 4.61209 14.2852 3.5716 13.3047 2.91795C12.3539 2.28406 11.1483 2 10 2Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.809 9.5L1.95605 2H4.33823L8.00008 7.65923L11.6619 2H14.0441L9.19117 9.5L14.0441 17H11.6619L8.00008 11.3408L4.33823 17H1.95605L6.809 9.5ZM17.4697 15.2197L15 17.6893V19H15.5H20V17.5H17.3107L18.5303 16.2803C19.3008 15.5099 20 14.5711 20 13.5C20 12.9749 19.8289 12.3634 19.4242 11.8688C19.0004 11.3508 18.3498 11 17.5 11C16.6502 11 15.9996 11.3508 15.5758 11.8688C15.1711 12.3634 15 12.9749 15 13.5H16.5C16.5 13.2751 16.5789 13.0116 16.7367 12.8187C16.8754 12.6492 17.0998 12.5 17.5 12.5C17.9002 12.5 18.1246 12.6492 18.2633 12.8187C18.4211 13.0116 18.5 13.2751 18.5 13.5C18.5 13.9289 18.1992 14.4901 17.4697 15.2197Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 792 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.4697 4.21967L15 6.68934V8H15.5H20V6.5H17.3107L18.5303 5.28033C19.3008 4.50988 20 3.57109 20 2.5C20 1.97495 19.8289 1.36341 19.4242 0.868822C19.0004 0.350834 18.3498 0 17.5 0C16.6502 0 15.9996 0.350834 15.5758 0.868822C15.1711 1.36341 15 1.97495 15 2.5H16.5C16.5 2.27505 16.5789 2.01159 16.7367 1.81868C16.8754 1.64917 17.0998 1.5 17.5 1.5C17.9002 1.5 18.1246 1.64917 18.2633 1.81868C18.4211 2.01159 18.5 2.27505 18.5 2.5C18.5 2.92891 18.1992 3.49012 17.4697 4.21967ZM6.809 9.5L1.95605 2H4.33823L8.00008 7.65923L11.6619 2H14.0441L9.19117 9.5L14.0441 17H11.6619L8.00008 11.3408L4.33823 17H1.95605L6.809 9.5Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 785 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.75 3.25V6.75H3.25V3.25H16.75ZM3.25 8H7V11.75H3.25V8ZM8.25 11.75V8H11.75V11.75H8.25ZM11.75 13H8.25V16.75H11.75V13ZM13 16.75V13H16.75V16.75H13ZM13 11.75V8H16.75V11.75H13ZM3.25 13H7V16.75H3.25V13ZM18 2H2V18H18V2Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 389 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 14L11 2H9L4 14H6.16667L7.41667 11H12.5833L13.8333 14H16ZM10 4.8L8.04167 9.5H11.9583L10 4.8ZM2.25 17.75V16.25H17.75V17.75H2.25ZM1 15H2.25H17.75H19V16.25V17.75V19H17.75H2.25H1V17.75V16.25V15Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 369 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 2H4V11C4 14.5836 6.71815 17 10 17C13.2819 17 16 14.5836 16 11V2H14V11C14 13.4164 12.241 15 10 15C7.75901 15 6 13.4164 6 11V2ZM4 19V17.75H16V19H4Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@ -43,7 +43,7 @@
align-items: center;
}
</style>
<link rel="stylesheet" href="./toolbutton.css" />
<link rel="stylesheet" href="./styles/toolbutton.css" />
<script>
window.addEventListener("DOMContentLoaded", (e) => {
document.querySelector(".container").style["line-height"] = `${

View File

@ -560,10 +560,10 @@
margin-bottom: 0 !important;
}
.markdown-body a:not([href]) {
/* .markdown-body a:not([href]) {
color: inherit;
text-decoration: none;
}
} */
.markdown-body .absent {
color: var(--color-danger-fg);

View File

@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);

View File

@ -44,7 +44,7 @@
</xul:keyset>
<script src="chrome://zotero/content/include.js"></script>
<script src="chrome://zotero/content/title.js"></script>
<script src="chrome://zotero/content/titlebar.js"></script>
<script src="chrome://zotero/content/customElements.js"></script>
<script src="chrome://__addonRef__/content/scripts/customElements.js"></script>
<script src="chrome://__addonRef__/content/scripts/linkCreator.js"></script>

View File

@ -16,6 +16,11 @@
native="true"
preference="__prefsPrefix__.openNote.defaultAsWindow"
/>
<checkbox
data-l10n-id="basic-exportNotes-takeover"
native="true"
preference="__prefsPrefix__.exportNotes.takeover"
/>
</groupbox>
<groupbox>
<label><html:h2 data-l10n-id="editor-title"></html:h2></label>
@ -38,10 +43,31 @@
native="true"
preference="__prefsPrefix__.workspace.outline.keepLinks"
/>
<hbox align="center">
<html:label
data-l10n-id="editor-noteLinkPreviewType"
for="__addonRef__-editor-noteLinkPreviewType"
></html:label>
<radiogroup
id="__addonRef__-editor-noteLinkPreviewType"
preference="__prefsPrefix__.editor.noteLinkPreviewType"
orient="horizontal"
oncommand="Zotero.__addonInstance__.api.utils.requireRestart();"
>
<radio data-l10n-id="editor-noteLinkPreview-hover" value="hover" />
<radio data-l10n-id="editor-noteLinkPreview-ctrl" value="ctrl" />
<radio data-l10n-id="editor-noteLinkPreview-disable" value="disable" />
</radiogroup>
</hbox>
<checkbox
data-l10n-id="editor-noteLinkPreview"
data-l10n-id="editor-useMagicKey"
native="true"
preference="__prefsPrefix__.editor.noteLinkPreview"
preference="__prefsPrefix__.editor.useMagicKey"
/>
<checkbox
data-l10n-id="editor-useMarkdownPaste"
native="true"
preference="__prefsPrefix__.editor.useMarkdownPaste"
/>
</groupbox>
<groupbox>
@ -59,6 +85,7 @@
placeholder="-1 for disable"
id="__addonRef__-sync-period"
preference="__prefsPrefix__.syncPeriodSeconds"
onchange="Zotero.__addonInstance__.api.utils.requireRestart();"
></html:input>
</hbox>
<hbox align="center">
@ -87,6 +114,14 @@
></button>
</hbox>
</groupbox>
<groupbox>
<label><html:h2 data-l10n-id="annotationNote-title"></html:h2></label>
<checkbox
data-l10n-id="annotationNote-enableTagSync"
native="true"
preference="__prefsPrefix__.annotationNote.enableTagSync"
/>
</groupbox>
<groupbox>
<label><html:h2 data-l10n-id="about-title"></html:h2></label>

View File

@ -23,6 +23,10 @@
var parser = new DOMParser();
var serializer = new XMLSerializer();
var htmlString = e.data.html;
const styleString = e.data.style;
const style = document.createElement("style");
style.innerHTML = styleString;
document.head.appendChild(style);
var htmlDoc = parser.parseFromString(htmlString, "text/html");
var xhtmlString = serializer.serializeToString(htmlDoc);
document.querySelector(".markdown-body").innerHTML = xhtmlString;

View File

@ -21,9 +21,6 @@
</style>
<script>
var browser;
var { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm",
);
var { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm",
);

View File

@ -0,0 +1,8 @@
dialog {
-moz-window-dragging: drag;
}
#markdown-autoSync {
margin-inline-start: 18px;
margin-block-end: 24px;
}

View File

@ -8,6 +8,14 @@
overflow: auto;
}
window {
-moz-window-dragging: drag;
}
#top-container {
-moz-window-dragging: no-drag;
}
/* TODO: remove fx115 workaround */
tab {
color: unset !important;

View File

@ -33,4 +33,12 @@ bn-note-picker {
min-width: 200px;
max-height: 50%;
}
.bn-note-list-container {
width: 100%;
}
#bn-select-recent-notes-content {
border-left: var(--material-border-quarternary);
}
}

View File

@ -0,0 +1,133 @@
html,
body {
min-width: 600px;
min-height: 400px;
}
html,
body,
.viewport {
padding: 0;
margin: 0;
height: 100%;
word-wrap: break-word;
}
.viewport {
flex-grow: 1;
flex-shrink: 1;
margin: 0 5px 0 5px;
overflow-x: hidden;
overflow-y: auto;
}
.viewport-container {
padding: 0;
margin: 0;
height: calc(100% - 50px);
width: 100%;
display: flex;
flex-direction: row;
overflow: hidden;
border-bottom: var(--material-border);
background: var(--material-background);
}
.footer-container {
padding: 5px;
}
.list-viewport {
width: calc(30% - 10px);
height: 100%;
overflow: hidden;
}
#table-container {
height: 100%;
width: 100%;
overflow: auto;
}
#templates-table {
height: 100%;
}
.editor-viewport {
display: flex;
flex-direction: column;
width: calc(40% - 10px);
padding: 5px;
}
.preview-viewport {
display: flex;
flex-direction: column;
width: calc(30% - 10px);
padding: 5px;
}
.markdown-body {
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 0px;
}
.help-button {
appearance: auto;
-moz-default-appearance: -moz-mac-help-button;
min-width: 0;
}
.editor-button-container {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 4px;
}
.editor-button-container[hidden] {
display: none;
}
.format {
width: 28px;
height: 28px;
border-radius: 5px;
flex-grow: 0;
flex-shrink: 0;
margin: 0;
background-repeat: no-repeat;
background-position: center;
}
.format:hover {
background-color: var(--fill-quinary);
}
.format:active {
background-color: var(--fill-quarternary);
}
.snippet {
border: var(--material-panedivider);
border-radius: 4px;
cursor: pointer;
font-size: 0.916666667em;
line-height: 1.272727273;
overflow: hidden;
padding: 1px 4px;
text-overflow: ellipsis;
white-space: pre;
box-sizing: border-box;
color: var(--fill-primary);
}
.snippet.syntax {
background-color: color-mix(
in srgb,
var(--accent-yellow) 50%,
transparent 50%
);
}
.snippet.expression {
background-color: color-mix(
in srgb,
var(--accent-green) 50%,
transparent 50%
);
}
.snippet.variable {
background-color: color-mix(
in srgb,
var(--accent-azure) 50%,
transparent 50%
);
}
.snippet:hover {
background-color: var(--fill-quinary);
}

View File

@ -0,0 +1,24 @@
dialog {
-moz-window-dragging: drag;
max-height: 700px;
}
.viewport-container {
-moz-window-dragging: no-drag;
height: 100%;
}
.viewport {
width: 100%;
}
#table-container {
width: 100%;
height: 100%;
overflow: auto;
background: var(--material-background);
}
.virtualized-table {
height: 100%;
}

View File

@ -8,10 +8,7 @@
type="text/css"
href="chrome://__addonRef__/content/lib/css/dx.light.compact.css"
/>
<link
rel="stylesheet"
href="chrome://__addonRef__/content/toolbutton.css"
/>
<link rel="stylesheet" href="./styles/toolbutton.css" />
<link
rel="stylesheet"
type="text/css"
@ -73,6 +70,7 @@
}
.footer-container {
padding: 5px;
gap: 8px;
margin: 0;
height: 60px;
width: 100%;

View File

@ -44,10 +44,6 @@
</xul:keyset>
<script>
document.addEventListener("DOMContentLoaded", (ev) => {
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm",
);
Services.scriptloader.loadSubScript(
"chrome://zotero/content/include.js",
this,
@ -107,7 +103,7 @@
</div>
<div
class="footer-container"
style="justify-content: flex-start; padding: 10px"
style="justify-content: flex-start; padding: 10px; gap: 8px"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
<button id="refresh" data-l10n-id="refresh"></button>

View File

@ -45,10 +45,6 @@
</xul:keyset>
<script>
document.addEventListener("DOMContentLoaded", (ev) => {
const { Services } = ChromeUtils.import(
"resource://gre/modules/Services.jsm",
);
Services.scriptloader.loadSubScript(
"chrome://zotero/content/include.js",
this,
@ -61,79 +57,18 @@
window.arguments[0]._initPromise.resolve();
});
</script>
<style>
html,
body {
min-width: 600px;
min-height: 400px;
}
html,
body,
.viewport {
padding: 0;
margin: 0;
height: 100%;
word-wrap: break-word;
}
.viewport {
flex-grow: 1;
flex-shrink: 1;
margin: 0 5px 0 5px;
overflow-x: hidden;
overflow-y: auto;
}
.viewport-container {
padding: 0;
margin: 0;
height: calc(100% - 50px);
width: 100%;
display: flex;
flex-direction: row;
overflow: hidden;
border-bottom: var(--material-border);
background: var(--material-background);
}
.footer-container {
padding: 5px;
}
.list-viewport {
width: calc(20% - 10px);
height: 100%;
overflow: hidden;
}
#table-container {
height: 100%;
width: 100%;
overflow: auto;
}
#templates-table {
height: 100%;
}
.editor-viewport {
display: flex;
flex-direction: column;
width: calc(40% - 10px);
padding: 5px;
}
.preview-viewport {
display: flex;
flex-direction: column;
width: calc(40% - 10px);
padding: 5px;
}
.markdown-body {
box-sizing: border-box;
min-width: 200px;
max-width: 980px;
margin: 0 auto;
padding: 0px;
}
</style>
<link
rel="stylesheet"
type="text/css"
href="chrome://__addonRef__/content/lib/css/github-markdown.css"
/>
<link
rel="stylesheet"
href="chrome://__addonRef__/content/lib/css/katex.min.css"
/>
<link
rel="stylesheet"
href="chrome://__addonRef__/content/styles/templateEditor.css"
/>
</head>
<body class="zotero-window">
<div class="viewport-container">
@ -146,10 +81,40 @@
orient="horizontal"
></xul:splitter>
<xul:hbox class="viewport editor-viewport">
<div style="display: flex; align-items: center">
<xul:hbox align="center">
<div style="flex-shrink: 0" data-l10n-id="templateType"></div>
<xul:menulist id="editor-type" native="true">
<xul:menupopup>
<xul:menuitem
data-l10n-id="templateType-unknown"
value="unknown"
></xul:menuitem>
<xul:menuitem
data-l10n-id="templateType-system"
value="system"
hidden="true"
></xul:menuitem>
<xul:menuitem
data-l10n-id="templateType-item"
value="item"
></xul:menuitem>
<xul:menuitem
data-l10n-id="templateType-text"
value="text"
></xul:menuitem>
</xul:menupopup>
</xul:menulist>
<xul:button
id="templateType-help"
data-l10n-id="templateType-help"
class="help-button"
></xul:button>
</xul:hbox>
<xul:hbox align="center">
<div style="flex-shrink: 0" data-l10n-id="templateName"></div>
<input id="editor-name" type="text" style="width: 100%" />
</div>
</xul:hbox>
<div id="formats-container" class="editor-button-container"></div>
<div style="display: flex; flex-direction: column; height: 100%">
<iframe
id="editor"
@ -158,6 +123,7 @@
onmousedown="this.focus()"
></iframe>
</div>
<div id="snippets-container" class="editor-button-container"></div>
</xul:hbox>
<xul:splitter
state="open"
@ -173,13 +139,14 @@
</div>
<div
class="footer-container"
style="justify-content: flex-start; padding: 10px"
style="justify-content: flex-start; padding: 10px; gap: 8px"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
<button id="create" data-l10n-id="create"></button>
<button id="save" data-l10n-id="save"></button>
<button id="delete" data-l10n-id="delete"></button>
<button id="reset" data-l10n-id="reset"></button>
<button id="share" data-l10n-id="share"></button>
<button id="more" data-l10n-id="more"></button>
<button
id="options"
@ -195,8 +162,6 @@
></menuitem>
<menuitem id="importNote" data-l10n-id="importNote"></menuitem>
<menuseparator />
<menuitem id="share" data-l10n-id="share"></menuitem>
<menuseparator />
<menuitem id="backup" data-l10n-id="backup"></menuitem>
<menuitem id="restore" data-l10n-id="restore"></menuitem>
<menuseparator />

View File

@ -0,0 +1,58 @@
<?xml version="1.0"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://zotero/skin/zotero.css" type="text/css"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://zotero-platform/content/zotero.css" type="text/css"?>
<!-- prettier-ignore -->
<?xml-stylesheet href="chrome://__addonRef__/content/styles/templatePicker.css" type="text/css"?>
<!-- prettier-ignore -->
<!DOCTYPE window>
<window
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
id="bn-note-picker"
data-l10n-id="title"
windowtype="__addonRef__-templatePicker"
persist="screenX screenY width height sizemode"
style="min-width: 20em"
drawintitlebar-platforms="mac"
>
<xul:linkset>
<html:link rel="localization" href="browser/menubar.ftl" />
<html:link rel="localization" href="browser/browserSets.ftl" />
<html:link rel="localization" href="toolkit/global/textActions.ftl" />
<html:link rel="localization" href="zotero.ftl" />
<html:link rel="localization" href="__addonRef__-templatePicker.ftl" />
</xul:linkset>
<xul:commandset id="mainCommandSet">
<xul:command id="cmd_close" oncommand="window.close();" />
</xul:commandset>
<xul:keyset id="mainKeyset">
<xul:key
id="key_close"
data-l10n-id="close-shortcut"
command="cmd_close"
modifiers="accel"
reserved="true"
/>
</xul:keyset>
<script src="chrome://zotero/content/include.js"></script>
<script src="chrome://zotero/content/titlebar.js"></script>
<script src="resource://zotero/require.js"></script>
<script src="chrome://zotero/content/customElements.js"></script>
<script src="chrome://__addonRef__/content/scripts/customElements.js"></script>
<script src="chrome://__addonRef__/content/scripts/templatePicker.js"></script>
<dialog buttons="accept, cancel">
<hbox class="viewport-container">
<hbox id="list-container" class="viewport list-viewport">
<html:div id="table-container"></html:div>
</hbox>
</hbox>
</dialog>
</window>

View File

@ -412,7 +412,7 @@
? expandedStatus[node.model.name]
: node.model.level < expandLevel,
parentId:
node.parent.model.id > 0
node.parent.model.id !== -1
? String(node.parent.model.id)
: undefined,
});

View File

@ -1,7 +1,5 @@
pref-title = Better Notes
menuItem-exportNote = Export Note
menuEdit-exportTemplate = Export Template to File...
menuEdit-templateEditor = Template Editor
menuEdit-importTemplate = New Template from Clipboard
@ -18,7 +16,27 @@ menuEditor-resizeImage = Resize Image
menuHelp-openUserGuide = Open Better Notes User Guide
templateEditor-templateName = Template Name
templateEditor-templateType = Type
templateEditor-templateName = Name
templateEditor-templateDisplayName =
.QuickInsertV2 = Quick Insert (Link)
.QuickImportV2 = Quick Import (Embed)
.QuickNoteV5 = Quick Note (From Annotation)
.ExportMDFileNameV2 = Export MD File Name
.ExportMDFileHeaderV2 = Export MD File Header
.ExportMDFileContent = Export MD File Content
templateEditor-templateDisplayType =
.system = Builtin
.item = Item
.text = Text
.unknown = ?
templateEditor-templateHelp =
.system = For specific purposes, e.g., generating note link.
.item = Can generate note fragments from one or more selected items as input.
.text = Can generate note fragments. It doesn't require any input.
editor-resizeImage-title = Resize Image
editor-resizeImage-prompt = Resize image width to:
@ -65,7 +83,7 @@ editor-toolbar-settings-openAsTab = Open as tab
editor-toolbar-settings-openAsWindow = Open as window
editor-toolbar-settings-showInLibrary = Show in Library
editor-toolbar-settings-insertTemplate = Insert template
editor-toolbar-settings-refreshTemplates = Update content from templates (Beta)
editor-toolbar-settings-refreshTemplates = Update content from templates
editor-toolbar-settings-copyLink = Copy link (L{ $line })
editor-toolbar-settings-copyLinkAtSection = Copy link (Sec. { $section })
editor-toolbar-settings-openParent = Open Attachment
@ -83,6 +101,7 @@ alert-notValidParentItemError = No valid parent item.
alert-syncImportedNotes = Keep imported notes in sync with MarkDown files?
alert-linkCreator-emptyNote = Cannot create link from/to an empty note.
alert-templateEditor-shouldImport = Seems like you are trying to directly save a note template share code. Do you want to import it as a template?
alert-templateEditor-unsaved = You have unsaved changes in the template editor. Do you want to save them?
userGuide-start-title = Welcome to Better Notes!
userGuide-start-desc = Better Notes is a powerful note-taking tool that helps you organize your thoughts and ideas while reading papers. This guide will help you get started with Better Notes and show you how to make the most of its features.

View File

@ -1,25 +0,0 @@
title = Export Notes
options-linkMode = Linked Notes Mode
options-MD = MarkDown(.md)
options-Docx = MS Word(.docx)
options-PDF = PDF(.pdf)
options-mm = Mind Map
options-note = Zotero Note
embedLink = All Embedded in One Export
standaloneLink = Each Converted to Standalone Exports
keepLink = Keep Zotero Links(zotero://note/)
exportMD = Export MD File(s)
setAutoSync = Set Auto-Sync
.title = Auto-Sync is available for "Each Converted to Standalone Exports" mode.
withYAMLHeader = With YAML Header
autoMDFileName = Auto Generate MD File Name
exportDocx = Export Docx File
exportPDF = Export PDF File
exportFreeMind = Export FreeMind File
exportNote = Export to New Zotero Note Item
confirm = Export
cancel = Close
target = Target: {$title}{ $left ->
[0]{ "" }
*[other] { " " }and {$left} more.
}

View File

@ -0,0 +1,37 @@
title =
.title = Export Notes with Better Notes
target =
.value = Target: {$title}{ $left ->
[0]{ "" }
*[other] { " " }and {$left} more.
}
format =
.value = Format:
format-markdown =
.label = MarkDown(.md)
format-msword =
.label = MS Word(.docx)
format-pdf =
.label = PDF(.pdf)
format-freemind =
.label = Mind Map
format-note =
.label = Zotero Note
links-keep =
.label = Keep note links(zotero://note/)
links-embed =
.label = Embed linked notes in the content
links-standalone =
.label = Convert linked notes to standalone exports
links-remove =
.label = Remove note links
markdown-autoSync =
.label = Set auto-sync for each note
.title = Auto-sync is available for "Convert linked notes to standalone exports" mode.
markdown-withYAMLHeader =
.label = With YAML header
markdown-autoFilename =
.label = Auto generate file name

View File

@ -3,13 +3,27 @@ basic-openNote-takeover =
.label = Take over opening note
basic-openNote-defaultAsWindow =
.label = Open note as window by default
basic-exportNotes-takeover =
.label = Take over exporting notes
editor-title = Note Editor
editor-expandLevel-label = Outline expand to heading level
editor-keepLinks =
.label = Show note links in outline
editor-noteLinkPreview =
.label = Show note link preview on hover
editor-noteLinkPreviewType = Show preview for note link when:
editor-noteLinkPreview-hover =
.label = Hover
editor-noteLinkPreview-ctrl =
.label = Press { PLATFORM() ->
[macos] ⌘
*[other] Ctrl
}
editor-noteLinkPreview-disable =
.label = Never
editor-useMagicKey =
.label = Use magic key "/" to show command palette
editor-useMarkdownPaste =
.label = Use enhanced markdown paste
sync-title = Sync
sync-period-label = Auto-sync period (seconds)
@ -23,6 +37,10 @@ annotation-title = PDF Annotation
annotation-autoAnnotation =
.label = Automatically add new annotations to workspace note
annotationNote-title = Note from Annotation
annotationNote-enableTagSync =
.label = Keep tags of note from annotation in sync with the original annotation
about-title = About
help =
.value = { $name } VERSION { $version } Build { $time }

View File

@ -1,5 +1,19 @@
title = Template Editor
templateType = Template Type
templateType-item =
.label = Item
templateType-text =
.label = Text
templateType-system =
.label = Builtin
templateType-unknown =
.label = ?
templateType-help =
.label = ?
.title = Detailed explanation of template types
templateName = Template Name
previewContainer =
@ -12,6 +26,9 @@ delete =
.label = Delete
reset =
.label = Reset
share =
.label = Share
.tooltiptext = Copy template share code to clipboard
more =
.label = More Templates
.title = Get more templates online
@ -22,11 +39,134 @@ importClipboard =
.label = Import template: from template share code in clipboard
importNote =
.label = Import template: from existing note
share =
.label = Copy template share code to clipboard
backup =
.label = Export backup file
restore =
.label = Restore from backup file
help =
.label = Help
format-bold =
.title = Bold
format-italic =
.title = Italic
format-strikethrough =
.title = Strike-through
format-underline =
.title = Underline
format-superscript =
.title = Superscript
format-subscript =
.title = Subscript
format-textColor =
.title = Text color
format-link =
.title = Link
format-quote =
.title = Quote
format-monospaced =
.title = Monospace
format-code =
.title = Code block
format-table =
.title = Table
format-h1 =
.title = Level 1 heading
format-h2 =
.title = Level 2 heading
format-h3 =
.title = Level 3 heading
format-bullet =
.title = Bullet list
format-numbered =
.title = Numbered list
format-inlineMath =
.title = Inline math formula
format-blockMath =
.title = Multi-line math formula
format-inlineScript =
.title = Add an inline JS script, the result of which will be embedded in the note
format-blockScript =
.title = Add a multi-line async JS script, the return value of which will be embedded in the note
snippet-useMarkdown = use markdown
.title = Parse the template as markdown
snippet-useRefresh = use refresh
.title = Allow the content generated by the template to be refreshed
snippet-dryRunFlag = dry run flag
.title = Check if the template is running in dry run mode, e.g. for preview. In dry run mode, the script should not have side effects.
snippet-itemBeforeLoop = before loop
.title = Content to be rendered before the loop of items
snippet-itemInLoop = in loop
.title = Content to be rendered for each item in the loop
snippet-itemAfterLoop = after loop
.title = Content to be rendered after the loop of items
-variable-type = Type
-variable-item = Zotero.Item
-variable-note = Zotero.NoteItem
-variable-annotation = Zotero.AnnotationItem
-variable-string = string
-variable-object = object
-variable-function = function
snippet-itemItems = items
.title = { -variable-type }: { -variable-item }[]. The array of items to be rendered, available in beforeLoop and afterLoop stage
snippet-itemItem = item
.title = { -variable-type }: { -variable-item }. The current item to be rendered, available in inLoop stage
snippet-itemTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `item`, available in inLoop stage
snippet-itemTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached, available in any stage
snippet-itemCopyNoteImage = copy note image
.title = { -variable-type }: { -variable-function }. Copy the image of the note to the clipboard, available in any stage
snippet-itemSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data across different stages
snippet-itemFieldTitle = title
.title = { -variable-type }: { -variable-string }. The title of the top item
snippet-itemFieldAbstract = abstract
.title = { -variable-type }: { -variable-string }. The abstract of the top item
snippet-itemFieldCitKey = citation key
.title = { -variable-type }: { -variable-string }. The citation key of the top item
snippet-itemFieldDate = date
.title = { -variable-type }: { -variable-string }. The publication date of the top item
snippet-itemFieldDOI = DOI
.title = { -variable-type }: { -variable-string }. The DOI of the top item
snippet-itemFieldDOIURL = DOI or URL
.title = { -variable-type }: { -variable-string }. The DOI or URL of the top item
snippet-itemFieldAuthors = authors
.title = { -variable-type }: { -variable-string }. The authors of the top item
snippet-itemFieldJournal = journal
.title = { -variable-type }: { -variable-string }. The journal of the top item
snippet-itemFieldTitleTranslation = title translation
.title = { -variable-type }: { -variable-string }. The title translation of the top item
snippet-textTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-textSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data
snippet-quickInsertLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be linked
snippet-quickInsertLinkText = link text
.title = { -variable-type }: { -variable-string }. The default label of the link
snippet-quickInsertSubNoteItem = linked note
.title = { -variable-type }: { -variable-note }. The note item to be linked to
snippet-quickInsertNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickImportLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be imported
snippet-quickImportNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickNoteAnnotationItem = annotation
.title = { -variable-type }: { -variable-annotation }. The annotation item to be converted to a note
snippet-quickNoteTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `annotationItem`
snippet-quickNoteNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-exportMDFileNameNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileHeaderNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentMDContent = markdown content
.title = { -variable-type }: { -variable-string }. The markdown content to be exported

View File

@ -1,7 +1,5 @@
pref-title = Better Notes
menuItem-exportNote = Esporta nota
menuEdit-exportTemplate = Esporta il template su file...
menuEdit-templateEditor = Editor dei template
menuEdit-importTemplate = Nuovo template dagli appunti
@ -16,9 +14,29 @@ menuAddReaderNote-newTemplateNote = Nuova nota dell'elemento da template
menuEditor-resizeImage = Ridimensiona immagine
menuHelp-openUserGuide = Open Better Notes User Guide
menuHelp-openUserGuide = Apri la guida utente di Better Notes
templateEditor-templateName = Template Name
templateEditor-templateType = Tipo
templateEditor-templateName = Nome
templateEditor-templateDisplayName =
.QuickInsertV2 = Inserimento rapido (Link)
.QuickImportV2 = Importazione rapida (Inserisci)
.QuickNoteV5 = Nota rapida (Da annotazione)
.ExportMDFileNameV2 = Esporta il nome del file MD
.ExportMDFileHeaderV2 = Esporta l'intestazione del file MD
.ExportMDFileContent = Esporta il contenuto del file MD
templateEditor-templateDisplayType =
.system = Integrato
.item = Elemento
.text = Testo
.unknown = ?
templateEditor-templateHelp =
.system = Per scopi specifici, ad esempio generare link a una nota.
.item = Può generare una porzione di nota da uno o più elementi di origine.
.text = Può generare una porzione di nota. Non richiede alcun input.
syncManager-noteName = Nome nota
syncManager-lastSync = Ultima sincronizzazione
@ -61,7 +79,7 @@ editor-toolbar-settings-openAsTab = Apri come scheda
editor-toolbar-settings-openAsWindow = Apri in nuova finestra
editor-toolbar-settings-showInLibrary = Mostra nella biblioteca
editor-toolbar-settings-insertTemplate = Inserisci template
editor-toolbar-settings-refreshTemplates = Aggiorna il contenuto dal template (Beta)
editor-toolbar-settings-refreshTemplates = Aggiorna il contenuto dal template
editor-toolbar-settings-copyLink = Copia link (L{ $line })
editor-toolbar-settings-copyLinkAtSection = Copia link (Sez. { $section })
editor-toolbar-settings-openParent = Apri allegato
@ -79,9 +97,10 @@ alert-notValidParentItemError = Nessun elemento genitore valido.
alert-syncImportedNotes = Si desidera sincronizzare le note importate con i file markdown?
alert-linkCreator-emptyNote = Non è possibile creare un link da/a una nota vuota.
alert-templateEditor-shouldImport = Sembra che tu stia cercando di salvare direttamente un codice di condivisione di un template di nota. Vuoi importarlo come template?
alert-templateEditor-unsaved = You have unsaved changes in the template editor. Do you want to save them?
userGuide-start-title = Questo è Better Notes!
userGuide-start-desc = Better Notes è un potente strumento di gestione delle note che ti può aiutare a organizzare pensieri e idee mentre leggi articoli. Questa guida ti aiuterà a prendere confidenza con Better Notes e ti mostrerà come usare al meglio le sue funzioni.
userGuide-start-desc = Better Notes è un potente strumento di gestione delle note che ti può aiutare a organizzare pensieri e idee durante la lettura di articoli scientifici. Questa guida ti aiuterà a prendere confidenza con Better Notes e ti mostrerà come usare al meglio le sue funzioni.
userGuide-start-close = Ricordami più tardi
userGuide-createNoteButton-title = Crea una nuova nota
userGuide-createNoteButton-desc = Puoi creare una nuova nota da qui: vuota o da un template.
@ -112,4 +131,4 @@ userGuide-workspaceNoteInfo-title = Informazioni della nota
userGuide-workspaceNoteInfo-desc = Puoi vedere, modificare e gestire i tag della nota, le relazioni e i link.
userGuide-finish-title = Fine del tutorial!
userGuide-finish-desc = Divertiti a usare Better Notes!
You can always run this guide again from the Help menu.
Puoi visualizzare nuovamente il tutorial dal menu aiuto.

View File

@ -1,25 +0,0 @@
title = Esporta note
options-linkMode = Modalità note collegate
options-MD = MarkDown(.md)
options-Docx = MS Word(.docx)
options-PDF = PDF(.pdf)
options-mm = Mappa mentale
options-note = Nota Zotero
embedLink = Tutte incorporate in un'unica esportazione
standaloneLink = Ciascuna convertita in esportazioni indipendenti
keepLink = Mantieni i link Zotero (zotero://note/)
exportMD = Esporta file MD
setAutoSync = Imposta sincronizzazione automatica
.title = Auto-Sync is available for "Each Converted to Standalone Exports" mode.
withYAMLHeader = Con header YAML
autoMDFileName = Genera automaticamente il nome del file MD
exportDocx = Esporta file Docx
exportPDF = Esporta file PDF
exportFreeMind = Esporta file FreeMind
exportNote = Esporta in una nuova nota dell'elemento Zotero
confirm = Esporta
cancel = Chiudi
target = Oggetto: {$title}{ $left ->
[0]{ "" }
*[other] { " " }e {$left} altri
}

View File

@ -0,0 +1,37 @@
title =
.title = Esporta Note con Better Notes
target =
.value = Destinazione: {$title}{ $left ->
[0]{ "" }
*[other] { " " }e {$left} in più.
}
format =
.value = Formato:
format-markdown =
.label = MarkDown(.md)
format-msword =
.label = MS Word(.docx)
format-pdf =
.label = PDF(.pdf)
format-freemind =
.label = Mappa Mentale
format-note =
.label = Nota Zotero
links-keep =
.label = Mantieni collegamenti alle note(zotero://note/)
links-embed =
.label = Incorpora note collegate nel contenuto
links-standalone =
.label = Converti note collegate in esportazioni autonome
links-remove =
.label = Rimuovi collegamenti alle note
markdown-autoSync =
.label = Imposta sincronizzazione automatica per ogni nota
.title = La sincronizzazione automatica è disponibile per la modalità "Converti note collegate in esportazioni autonome".
markdown-withYAMLHeader =
.label = Con intestazione YAML
markdown-autoFilename =
.label = Genera automaticamente il nome del file

View File

@ -3,13 +3,27 @@ basic-openNote-takeover =
.label = Gestisci l'apertura delle note
basic-openNote-defaultAsWindow =
.label = Apri note come finestra per impostazione predefinita
basic-exportNotes-takeover =
.label = Take over exporting notes
editor-title = Editor delle note
editor-expandLevel-label = Espansione dello schema al livello delle intestazioni
editor-keepLinks =
.label = Mostra i collegamenti delle note nello schema
editor-noteLinkPreview =
.label = Mostra l'anteprima del link alla nota al passaggio del mouse
editor-noteLinkPreviewType = Show preview for note link when:
editor-noteLinkPreview-hover =
.label = Hover
editor-noteLinkPreview-ctrl =
.label = Press { PLATFORM() ->
[macos] ⌘
*[other] Ctrl
}
editor-noteLinkPreview-disable =
.label = Never
editor-useMagicKey =
.label = Usa il tasto magico "/" per mostrare il pannello dei comandi
editor-useMarkdownPaste =
.label = Usa l'incolla markdown avanzato
sync-title = Sincronizzazione
sync-period-label = Intervallo della sincronizzazione automatica (secondi)
@ -23,6 +37,10 @@ annotation-title = Annotazione PDF
annotation-autoAnnotation =
.label = Aggiungi automaticamente le nuove annotazioni alla nota di lavoro
annotationNote-title = Note from Annotation
annotationNote-enableTagSync =
.label = Mantieni i tag di una nota derivata da un'annotazione sincronizzati con l'annotazione di origine
about-title = Informazioni su Better Notes
help =
.value = { $name } VERSION { $version } Build { $time }

View File

@ -1,5 +1,19 @@
title = Editor dei template
templateType = Tipo di Template
templateType-item =
.label = Elemento
templateType-text =
.label = Testo
templateType-system =
.label = Integrato
templateType-unknown =
.label = ?
templateType-help =
.label = ?
.title = Spiegazioni dettagliate sui tipi di template
templateName = Nome template
previewContainer =
@ -12,6 +26,9 @@ delete =
.label = Elimina
reset =
.label = Ripristina
share =
.label = Share
.tooltiptext = Copia codice di condivisione template negli appunti
more =
.label = Altri Template
.title = Ottieni altri template online
@ -22,11 +39,196 @@ importClipboard =
.label = Importa template: da il codice di condivisione template negli appunti
importNote =
.label = Importa template: da nota esistente
share =
.label = Copia codice di condivisione template negli appunti
backup =
.label = Esporta file di backup
restore =
.label = Ripristina da file di backup
help =
.label = Aiuto
format-bold =
.title = Grassetto
format-italic =
.title = Corsivo
format-strikethrough =
.title = Barrato
format-underline =
.title = Sottolineato
format-superscript =
.title = Apice
format-subscript =
.title = Pedice
format-textColor =
.title = Colore del testo
format-link =
.title = Link
format-quote =
.title = Citazione
format-monospaced =
.title = Testo monospaziato
format-code =
.title = Codice
format-table =
.title = Tabella
format-h1 =
.title = Intestazione di livello 1
format-h2 =
.title = Intestazione di livello 2
format-h3 =
.title = Intestazione di livello 3
format-bullet =
.title = Elenco puntato
format-numbered =
.title = Elenco numerato
format-inlineMath =
.title = Formula matematica in linea
format-blockMath =
.title = Formula matematica multilinea
format-inlineScript =
.title = Aggiungi uno script JS in-linea, e inserisci il risultato nella nota
format-blockScript =
.title = Aggiungi uno script JS multi-linea, e inserisci il valore risultante nella nota
snippet-useMarkdown = usa markdown
.title = Elabora il template come markdown
snippet-useRefresh = abilita aggiornamento
.title = Permetti al contenuto generato dal template di essere aggiornato
snippet-dryRunFlag = esecuzione simulata
.title = Verifica che il template sia in modalità simulata, ad esempio come anteprima. In modalità di esecuzione simulata, lo script non apporta modifiche e quindi non dovrebbe avere effetti indesiderati.
snippet-itemBeforeLoop = prima del loop
.title = Contenuto da renderizzare prima del loop degli elementi
snippet-itemInLoop = nel loop
.title = Contenuto da renderizzare per ogni elemento del loop
snippet-itemAfterLoop = dopo il loop
.title = Contenuto da renderizzare dopo il loop degli elementi
.title = Markdown link, type `[` at the beginning and `](url)` at the end of your text. Should be used in markdown mode
-variable-type = Type
-variable-item = Zotero.Item
-variable-note = Zotero.NoteItem
-variable-annotation = Zotero.AnnotationItem
-variable-string = string
-variable-object = object
-variable-function = function
snippet-itemItems = elementi
.title = { -variable-type }: { -variable-item }[]. L'array di elementi da renderizzare, disponibile negli stadi prima o dopo il loop
snippet-itemItem = elemento
.title = { -variable-type }: { -variable-item }. L'elemento da renderizzare, disponibile nello stadio nel loop
snippet-itemTopItem = elemento superiore
.title = { -variable-type }: { -variable-item }. Il genitore della variabile `elemento`, disponibile nello stadio nel loop
snippet-itemTargetNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota a cui è allegato il template, disponibile a qualsiasi stadio
snippet-itemCopyNoteImage = copia l'immagine della nota
.title = { -variable-type }: { -variable-function }. Copia l'immagine della nota negli appunti, disponibile a qualsiasi stadio
snippet-itemSharedObj = oggetto condiviso
.title = { -variable-type }: { -variable-object }. Un oggetto condiviso che può essere usato per memorizzare informazioni attraverso stadi differenti
snippet-itemFieldTitle = titolo
.title = { -variable-type }: { -variable-string }. Il titolo dell'elemento superiore
snippet-itemFieldAbstract = abstract
.title = { -variable-type }: { -variable-string }. L'abstract dell'elemento superiore
snippet-itemFieldCitKey = chiave di citazione
.title = { -variable-type }: { -variable-string }. La chiave di citazione dell'elemento superiore
snippet-itemFieldDate = data
.title = { -variable-type }: { -variable-string }. La data di pubblicazione dell'elemento superiore
snippet-itemFieldDOI = DOI
.title = { -variable-type }: { -variable-string }. Il DOI dell'elemento superiore
snippet-itemFieldDOIURL = DOI o URL
.title = { -variable-type }: { -variable-string }. Il DOI o l'URLdell'elemento superiore
snippet-itemFieldAuthors = autori
.title = { -variable-type }: { -variable-string }. Gli autori dell'elemento superiore
snippet-itemFieldJournal = rivista
.title = { -variable-type }: { -variable-string }. La rivista dell'elemento superiore
snippet-itemFieldTitleTranslation = traduzione del titolo
.title = { -variable-type }: { -variable-string }. La traduzione del titolo dell'elemento superiore
snippet-textTargetNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota bersaglio dell'elemento superiore
snippet-textSharedObj = oggetto condiviso
.title = { -variable-type }: { -variable-object }. Un oggetto condiviso che può essere usato per memorizzare informazioni
snippet-quickInsertLink = link della nota
.title = { -variable-type }: { -variable-string }. Il link della nota da collegare
snippet-quickInsertLinkText = testo del link
.title = { -variable-type }: { -variable-string }. L'etichetta predefinita del link
snippet-quickInsertSubNoteItem = nota collegata
.title = { -variable-type }: { -variable-note }. La nota a cui puntare il link
snippet-quickInsertNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota a cui allegare il template
snippet-quickImportLink = link della nota
.title = { -variable-type }: { -variable-string }. Il link della nota da importare
snippet-quickImportNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota a cui allegare il template
snippet-quickNoteAnnotationItem = annotazione
.title = { -variable-type }: { -variable-annotation }. L'annotazione da convertire in nota
snippet-quickNoteTopItem = elemento superiore
.title = { -variable-type }: { -variable-item }. L'elemento superiore della variabile `annotationItem`
snippet-quickNoteNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota a cui allegare il template
snippet-exportMDFileNameNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota da esportare
snippet-exportMDFileHeaderNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota da esportare
snippet-exportMDFileContentNoteItem = nota bersaglio
.title = { -variable-type }: { -variable-note }. La nota da esportare
snippet-exportMDFileContentMDContent = contenuto markdown
.title = { -variable-type }: { -variable-string }. Il contenuto markdown da esportare
snippet-itemItems = items
.title = { -variable-type }: { -variable-item }[]. The array of items to be rendered, available in beforeLoop and afterLoop stage
snippet-itemItem = item
.title = { -variable-type }: { -variable-item }. The current item to be rendered, available in inLoop stage
snippet-itemTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `item`, available in inLoop stage
snippet-itemTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached, available in any stage
snippet-itemCopyNoteImage = copy note image
.title = { -variable-type }: { -variable-function }. Copy the image of the note to the clipboard, available in any stage
snippet-itemSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data across different stages
snippet-itemFieldTitle = title
.title = { -variable-type }: { -variable-string }. The title of the top item
snippet-itemFieldAbstract = abstract
.title = { -variable-type }: { -variable-string }. The abstract of the top item
snippet-itemFieldCitKey = citation key
.title = { -variable-type }: { -variable-string }. The citation key of the top item
snippet-itemFieldDate = date
.title = { -variable-type }: { -variable-string }. The publication date of the top item
snippet-itemFieldDOI = DOI
.title = { -variable-type }: { -variable-string }. The DOI of the top item
snippet-itemFieldDOIURL = DOI or URL
.title = { -variable-type }: { -variable-string }. The DOI or URL of the top item
snippet-itemFieldAuthors = authors
.title = { -variable-type }: { -variable-string }. The authors of the top item
snippet-itemFieldJournal = journal
.title = { -variable-type }: { -variable-string }. The journal of the top item
snippet-itemFieldTitleTranslation = title translation
.title = { -variable-type }: { -variable-string }. The title translation of the top item
snippet-textTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-textSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data
snippet-quickInsertLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be linked
snippet-quickInsertLinkText = link text
.title = { -variable-type }: { -variable-string }. The default label of the link
snippet-quickInsertSubNoteItem = linked note
.title = { -variable-type }: { -variable-note }. The note item to be linked to
snippet-quickInsertNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickImportLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be imported
snippet-quickImportNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickNoteAnnotationItem = annotation
.title = { -variable-type }: { -variable-annotation }. The annotation item to be converted to a note
snippet-quickNoteTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `annotationItem`
snippet-quickNoteNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-exportMDFileNameNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileHeaderNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentMDContent = markdown content
.title = { -variable-type }: { -variable-string }. The markdown content to be exported

View File

@ -1,7 +1,5 @@
pref-title=Better Notes
menuItem-exportNote=Экспорт заметки
menuEdit-exportTemplate=Экспорт шаблона в файл...
menuEdit-templateEditor=Редактор шаблонов
menuEdit-importTemplate=Новый шаблон из буфера обмена
@ -18,7 +16,27 @@ menuEditor-resizeImage=Изменить размер изображения
menuHelp-openUserGuide = Open Better Notes User Guide
templateEditor-templateName = Template Name
templateEditor-templateType = Type
templateEditor-templateName = Name
templateEditor-templateDisplayName =
.QuickInsertV2 = Quick Insert (Link)
.QuickImportV2 = Quick Import (Embed)
.QuickNoteV5 = Quick Note (From Annotation)
.ExportMDFileNameV2 = Export MD File Name
.ExportMDFileHeaderV2 = Export MD File Header
.ExportMDFileContent = Export MD File Content
templateEditor-templateDisplayType =
.system = Builtin
.item = Item
.text = Text
.unknown = ?
templateEditor-templateHelp =
.system = For specific purposes, e.g., generating note link.
.item = Can generate note fragments from one or more selected items as input.
.text = Can generate note fragments. It doesn't require any input.
editor-resizeImage-title = Resize Image
editor-resizeImage-prompt = Resize image width to:
@ -65,7 +83,7 @@ editor-toolbar-settings-openAsTab = Open as tab
editor-toolbar-settings-openAsWindow = Open as window
editor-toolbar-settings-showInLibrary = Show in Library
editor-toolbar-settings-insertTemplate=Вставить шаблон
editor-toolbar-settings-refreshTemplates = Update content from templates (Beta)
editor-toolbar-settings-refreshTemplates = Update content from templates
editor-toolbar-settings-copyLink = Копировать Ссылку (L{ $line })
editor-toolbar-settings-copyLinkAtSection = Копировать Ссылку (Sec. { $section })
editor-toolbar-settings-openParent=Открыть вложение
@ -83,6 +101,7 @@ alert-notValidParentItemError=Нет валидного родительског
alert-syncImportedNotes = Синхронизировать импортированные заметки с файлами MarkDown?
alert-linkCreator-emptyNote = Cannot create link from/to an empty note.
alert-templateEditor-shouldImport = Вы пытаетесь сохранить код шаблона заметки. Хотите импортировать его как шаблон?
alert-templateEditor-unsaved = You have unsaved changes in the template editor. Do you want to save them?
userGuide-start-title = Welcome to Better Notes!
userGuide-start-desc = Better Notes is a powerful note-taking tool that helps you organize your thoughts and ideas while reading papers. This guide will help you get started with Better Notes and show you how to make the most of its features.

View File

@ -0,0 +1,37 @@
title =
.title = Экспорт заметок с Better Notes
target =
.value = Цель: {$title}{ $left ->
[0]{ "" }
*[other] { " " }и еще {$left}.
}
format =
.value = Формат:
format-markdown =
.label = MarkDown(.md)
format-msword =
.label = MS Word(.docx)
format-pdf =
.label = PDF(.pdf)
format-freemind =
.label = Карта разума
format-note =
.label = Заметка Zotero
links-keep =
.label = Сохранить ссылки на заметки(zotero://note/)
links-embed =
.label = Встроить связанные заметки в содержимое
links-standalone =
.label = Преобразовать связанные заметки в автономные экспорты
links-remove =
.label = Удалить ссылки на заметки
markdown-autoSync =
.label = Установить авто-синхронизацию для каждой заметки
.title = Авто-синхронизация доступна в режиме "Преобразовать связанные заметки в автономные экспорты".
markdown-withYAMLHeader =
.label = С YAML заголовком
markdown-autoFilename =
.label = Автоматически генерировать имя файла

View File

@ -3,13 +3,27 @@ basic-openNote-takeover =
.label = Take over opening note
basic-openNote-defaultAsWindow =
.label = Open note as window by default
basic-exportNotes-takeover =
.label = Take over exporting notes
editor-title = Note Editor
editor-expandLevel-label = Outline расширить до уровня заголовка
editor-keepLinks =
.label = Сохранить ссылки
editor-noteLinkPreview =
.label = Show note link preview on hover
editor-noteLinkPreviewType = Show preview for note link when:
editor-noteLinkPreview-hover =
.label = Hover
editor-noteLinkPreview-ctrl =
.label = Press { PLATFORM() ->
[macos] ⌘
*[other] Ctrl
}
editor-noteLinkPreview-disable =
.label = Never
editor-useMagicKey =
.label = Использовать магическую клавишу "/" для отображения панели команд
editor-useMarkdownPaste =
.label = Использовать расширенное вставление Markdown
sync-title = Синк
sync-period-label = Авто-синк период (сек)
@ -23,6 +37,10 @@ annotation-title = PDF Аннотация
annotation-autoAnnotation =
.label = Автодобавлять новые аннотации к заметкам раб.пространства
annotationNote-title = Note from Annotation
annotationNote-enableTagSync =
.label = Keep tags of note from annotation in sync with the original annotation
about-title = About
help =
.value = { $name } VERSION { $version } Build { $time }

View File

@ -1,5 +1,19 @@
title = Редактор шаблонов
templateType = Template Type
templateType-item =
.label = Item
templateType-text =
.label = Text
templateType-system =
.label = Builtin
templateType-unknown =
.label = ?
templateType-help =
.label = ?
.title = Detailed explanation of template types
templateName = Имя шаблона
previewContainer =
@ -12,6 +26,9 @@ delete =
.label = Удалить
reset =
.label = Сброс
share =
.label = Share
.tooltiptext = Copy template share code to clipboard
more =
.label = Больше шаблонов
.title = Get more templates online
@ -22,11 +39,134 @@ importClipboard =
.label = Import template: from template share code in clipboard
importNote =
.label = Import template: from existing note
share =
.label = Copy template share code to clipboard
backup =
.label = Export backup file
restore =
.label = Restore from backup file
help =
.label = Помощь
format-bold =
.title = Bold
format-italic =
.title = Italic
format-strikethrough =
.title = Strike-through
format-underline =
.title = Underline
format-superscript =
.title = Superscript
format-subscript =
.title = Subscript
format-textColor =
.title = Text color
format-link =
.title = Link
format-quote =
.title = Quote
format-monospaced =
.title = Monospace
format-code =
.title = Code block
format-table =
.title = Table
format-h1 =
.title = Level 1 heading
format-h2 =
.title = Level 2 heading
format-h3 =
.title = Level 3 heading
format-bullet =
.title = Bullet list
format-numbered =
.title = Numbered list
format-inlineMath =
.title = Inline math formula
format-blockMath =
.title = Multi-line math formula
format-inlineScript =
.title = Add an inline JS script, the result of which will be embedded in the note
format-blockScript =
.title = Add a multi-line async JS script, the return value of which will be embedded in the note
snippet-useMarkdown = use markdown
.title = Parse the template as markdown
snippet-useRefresh = use refresh
.title = Allow the content generated by the template to be refreshed
snippet-dryRunFlag = dry run flag
.title = Check if the template is running in dry run mode, e.g. for preview. In dry run mode, the script should not have side effects.
snippet-itemBeforeLoop = before loop
.title = Content to be rendered before the loop of items
snippet-itemInLoop = in loop
.title = Content to be rendered for each item in the loop
snippet-itemAfterLoop = after loop
.title = Content to be rendered after the loop of items
-variable-type = Type
-variable-item = Zotero.Item
-variable-note = Zotero.NoteItem
-variable-annotation = Zotero.AnnotationItem
-variable-string = string
-variable-object = object
-variable-function = function
snippet-itemItems = items
.title = { -variable-type }: { -variable-item }[]. The array of items to be rendered, available in beforeLoop and afterLoop stage
snippet-itemItem = item
.title = { -variable-type }: { -variable-item }. The current item to be rendered, available in inLoop stage
snippet-itemTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `item`, available in inLoop stage
snippet-itemTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached, available in any stage
snippet-itemCopyNoteImage = copy note image
.title = { -variable-type }: { -variable-function }. Copy the image of the note to the clipboard, available in any stage
snippet-itemSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data across different stages
snippet-itemFieldTitle = title
.title = { -variable-type }: { -variable-string }. The title of the top item
snippet-itemFieldAbstract = abstract
.title = { -variable-type }: { -variable-string }. The abstract of the top item
snippet-itemFieldCitKey = citation key
.title = { -variable-type }: { -variable-string }. The citation key of the top item
snippet-itemFieldDate = date
.title = { -variable-type }: { -variable-string }. The publication date of the top item
snippet-itemFieldDOI = DOI
.title = { -variable-type }: { -variable-string }. The DOI of the top item
snippet-itemFieldDOIURL = DOI or URL
.title = { -variable-type }: { -variable-string }. The DOI or URL of the top item
snippet-itemFieldAuthors = authors
.title = { -variable-type }: { -variable-string }. The authors of the top item
snippet-itemFieldJournal = journal
.title = { -variable-type }: { -variable-string }. The journal of the top item
snippet-itemFieldTitleTranslation = title translation
.title = { -variable-type }: { -variable-string }. The title translation of the top item
snippet-textTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-textSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data
snippet-quickInsertLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be linked
snippet-quickInsertLinkText = link text
.title = { -variable-type }: { -variable-string }. The default label of the link
snippet-quickInsertSubNoteItem = linked note
.title = { -variable-type }: { -variable-note }. The note item to be linked to
snippet-quickInsertNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickImportLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be imported
snippet-quickImportNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickNoteAnnotationItem = annotation
.title = { -variable-type }: { -variable-annotation }. The annotation item to be converted to a note
snippet-quickNoteTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `annotationItem`
snippet-quickNoteNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-exportMDFileNameNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileHeaderNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentMDContent = markdown content
.title = { -variable-type }: { -variable-string }. The markdown content to be exported

View File

@ -1,7 +1,5 @@
pref-title = Better Notes
menuItem-exportNote = Notu Dışa Aktar
menuEdit-exportTemplate = Şablonu Dosya Olarak Dışa Aktar...
menuEdit-templateEditor = Şablon Düzenleyici
menuEdit-importTemplate = Panodan Yeni Şablon Al
@ -18,7 +16,27 @@ menuEditor-resizeImage = Resmi Boyutlandır
menuHelp-openUserGuide = Better Notes Kullanıcı Rehberini Aç
templateEditor-templateName = Şablon Adı
templateEditor-templateType = Type
templateEditor-templateName = Name
templateEditor-templateDisplayName =
.QuickInsertV2 = Quick Insert (Link)
.QuickImportV2 = Quick Import (Embed)
.QuickNoteV5 = Quick Note (From Annotation)
.ExportMDFileNameV2 = Export MD File Name
.ExportMDFileHeaderV2 = Export MD File Header
.ExportMDFileContent = Export MD File Content
templateEditor-templateDisplayType =
.system = Builtin
.item = Item
.text = Text
.unknown = ?
templateEditor-templateHelp =
.system = For specific purposes, e.g., generating note link.
.item = Can generate note fragments from one or more selected items as input.
.text = Can generate note fragments. It doesn't require any input.
editor-resizeImage-title = Resmi Boyutlandır
editor-resizeImage-prompt = Resmi Şuna Boyutlandır:
@ -65,7 +83,7 @@ editor-toolbar-settings-openAsTab = Sekme Olarak Aç
editor-toolbar-settings-openAsWindow = Pencere Olarak Aç
editor-toolbar-settings-showInLibrary = Kitaplıkta Göster
editor-toolbar-settings-insertTemplate = Şablon Uygula
editor-toolbar-settings-refreshTemplates = İçeriği Şablona Göre Güncelle (Beta)
editor-toolbar-settings-refreshTemplates = İçeriği Şablona Göre Güncelle
editor-toolbar-settings-copyLink = Bağlantıyı Kopyala (Satır { $line })
editor-toolbar-settings-copyLinkAtSection = Bağlantıyı Kopyala (Başlık { $section })
editor-toolbar-settings-openParent = Eki Aç
@ -83,6 +101,7 @@ alert-notValidParentItemError = Geçerli ana eser yok.
alert-syncImportedNotes = İçe aktarılmış notları Markdown dosyalarıyla eşitlemede tutmak ister misiniz?
alert-linkCreator-emptyNote = Boş bir nota/nottan bağlantı oluşturulamaz. note.
alert-templateEditor-shouldImport = Şablon kodunu doğrudan kaydetmeye çalışıyorsunuz gibi görünüyor. Şablon olarak içe aktarmak ister misiniz?
alert-templateEditor-unsaved = You have unsaved changes in the template editor. Do you want to save them?
userGuide-start-title = Better Notes'a hoş geldiniz!
userGuide-start-desc = Better Notes düşüncelerinizi ve tasarılarınızı düzenlemenize yardımcı olan güçlü bir not alma aracıdır. Kullanımı kolay ve yalın biçimde tasarlanmış olsa da karmaşık not alma işlerini görebilecek kadar da esnektir. Bu rehber size Better Notes'u kullanmaya başlamanıza ve ileri düzey işlevleri verimli kullanmanıza yardımcı olacaktır.

View File

@ -1,25 +0,0 @@
title = Notları Dışa Aktar
options-linkMode = Bağlantılı Notlar Modu
options-MD = MarkDown(.md)
options-Docx = MS Word(.docx)
options-PDF = PDF(.pdf)
options-mm = Zihin Haritası
options-note = Zotero Notu
embedLink = Hepsi Tek Bir Dışarı Aktarma İçerisinde
standaloneLink = Her Biri Bağımsız Olarak Dışa Aktarıldı
keepLink = Zotero Linkleri Kalsın (zotero://note/)
exportMD = MD Dosya(lar)sını Dışa Aktar
setAutoSync = Otomatik Eşitlemeye Ayarla
.title = Otomatik Eşitleme "Her Birini Bağımsız Dışa Aktar" seçeneği için kullanılabilir.
withYAMLHeader = YAML Başlığı İle
autoMDFileName = MD Dosya Adını Otomatik Oluştur
exportDocx = Docx Dosyası Olarak Dışa Aktar
exportPDF = PDF Dosyası Olarak Dışa Aktar
exportFreeMind = FreeMind Dosyası Olarak Dışa Aktar
exportNote = Yeni Zotero Notuna Aktar
confirm = Dışa Aktar
cancel = Kapat
target = Hedef: {$title}{ $left ->
[0]{ "" }
*[other] { " " }and {$left} more
}

View File

@ -0,0 +1,37 @@
title =
.title = Notları Better Notes ile Dışa Aktar
target =
.value = Hedef: {$title}{ $left ->
[0]{ "" }
*[other] { " " }ve {$left} daha.
}
format =
.value = Biçim:
format-markdown =
.label = MarkDown(.md)
format-msword =
.label = MS Word(.docx)
format-pdf =
.label = PDF(.pdf)
format-freemind =
.label = Zihin Haritası
format-note =
.label = Zotero Notu
links-keep =
.label = Not bağlantılarını koru(zotero://note/)
links-embed =
.label = Bağlantılı notları içeriğe göm
links-standalone =
.label = Bağlantılı notları bağımsız dışa aktarımlara dönüştür
links-remove =
.label = Not bağlantılarını kaldır
markdown-autoSync =
.label = Her not için otomatik senkronizasyon ayarla
.title = Otomatik senkronizasyon "Bağlantılı notları bağımsız dışa aktarımlara dönüştür" modu için kullanılabilir.
markdown-withYAMLHeader =
.label = YAML başlığı ile
markdown-autoFilename =
.label = Dosya adını otomatik oluştur

View File

@ -3,13 +3,27 @@ basic-openNote-takeover =
.label = Notları açmayı devral
basic-openNote-defaultAsWindow =
.label = Notları her zaman pencere olarak aç
basic-exportNotes-takeover =
.label = Take over exporting notes
editor-title = Not Düzenleyici
editor-expandLevel-label = Anahatta gösterilecek başlık düzeyleri
editor-keepLinks =
.label = Not bağlantılarını anahatta göster
editor-noteLinkPreview =
.label = İmleci bağlantının üzerine getirdiğinde ön izlemeyi göster
editor-noteLinkPreviewType = Show preview for note link when:
editor-noteLinkPreview-hover =
.label = Hover
editor-noteLinkPreview-ctrl =
.label = Press { PLATFORM() ->
[macos] ⌘
*[other] Ctrl
}
editor-noteLinkPreview-disable =
.label = Never
editor-useMagicKey =
.label = Komut panelini göstermek için sihirli tuş "/" kullan
editor-useMarkdownPaste =
.label = Gelişmiş markdown yapıştırma kullan
sync-title = Eşitle
sync-period-label = Otomatik Eşitleme Sıklığı (saniye)
@ -23,6 +37,10 @@ annotation-title = PDF Ek Açıklamaları
annotation-autoAnnotation =
.label = Çalışma alanı notuna otomatik olarak yeni ek açıklamaları ekle
annotationNote-title = Note from Annotation
annotationNote-enableTagSync =
.label = Keep tags of note from annotation in sync with the original annotation
about-title = Hakkında
help =
.value = { $name } Sürüm { $version } Yapı Numarası { $time }

View File

@ -1,5 +1,19 @@
title = Şablon Düzenleyici
templateType = Template Type
templateType-item =
.label = Item
templateType-text =
.label = Text
templateType-system =
.label = Builtin
templateType-unknown =
.label = ?
templateType-help =
.label = ?
.title = Detailed explanation of template types
templateName = Şablon Adı
previewContainer =
@ -12,6 +26,9 @@ delete =
.label = Sil
reset =
.label = Sıfırla
share =
.label = Share
.tooltiptext = Şablon paylaşım kodunu panoya kopyala
more =
.label = Daha Fazla Şablon
.title = Daha Fazla Çevrimiçi Şablon Bul
@ -22,11 +39,134 @@ importClipboard =
.label = Şablonu İçe Aktar: panodaki şablon paylaşım kodu ile
importNote =
.label = Şablonu İçe Aktar: var olan bir nottan
share =
.label = Şablon paylaşım kodunu panoya kopyala
backup =
.label = Yedek dosyasını dışa aktar
restore =
.label = Yedek dosyasından geri yükle
help =
.label = Yardım
format-bold =
.title = Bold
format-italic =
.title = Italic
format-strikethrough =
.title = Strike-through
format-underline =
.title = Underline
format-superscript =
.title = Superscript
format-subscript =
.title = Subscript
format-textColor =
.title = Text color
format-link =
.title = Link
format-quote =
.title = Quote
format-monospaced =
.title = Monospace
format-code =
.title = Code block
format-table =
.title = Table
format-h1 =
.title = Level 1 heading
format-h2 =
.title = Level 2 heading
format-h3 =
.title = Level 3 heading
format-bullet =
.title = Bullet list
format-numbered =
.title = Numbered list
format-inlineMath =
.title = Inline math formula
format-blockMath =
.title = Multi-line math formula
format-inlineScript =
.title = Add an inline JS script, the result of which will be embedded in the note
format-blockScript =
.title = Add a multi-line async JS script, the return value of which will be embedded in the note
snippet-useMarkdown = use markdown
.title = Parse the template as markdown
snippet-useRefresh = use refresh
.title = Allow the content generated by the template to be refreshed
snippet-dryRunFlag = dry run flag
.title = Check if the template is running in dry run mode, e.g. for preview. In dry run mode, the script should not have side effects.
snippet-itemBeforeLoop = before loop
.title = Content to be rendered before the loop of items
snippet-itemInLoop = in loop
.title = Content to be rendered for each item in the loop
snippet-itemAfterLoop = after loop
.title = Content to be rendered after the loop of items
-variable-type = Type
-variable-item = Zotero.Item
-variable-note = Zotero.NoteItem
-variable-annotation = Zotero.AnnotationItem
-variable-string = string
-variable-object = object
-variable-function = function
snippet-itemItems = items
.title = { -variable-type }: { -variable-item }[]. The array of items to be rendered, available in beforeLoop and afterLoop stage
snippet-itemItem = item
.title = { -variable-type }: { -variable-item }. The current item to be rendered, available in inLoop stage
snippet-itemTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `item`, available in inLoop stage
snippet-itemTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached, available in any stage
snippet-itemCopyNoteImage = copy note image
.title = { -variable-type }: { -variable-function }. Copy the image of the note to the clipboard, available in any stage
snippet-itemSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data across different stages
snippet-itemFieldTitle = title
.title = { -variable-type }: { -variable-string }. The title of the top item
snippet-itemFieldAbstract = abstract
.title = { -variable-type }: { -variable-string }. The abstract of the top item
snippet-itemFieldCitKey = citation key
.title = { -variable-type }: { -variable-string }. The citation key of the top item
snippet-itemFieldDate = date
.title = { -variable-type }: { -variable-string }. The publication date of the top item
snippet-itemFieldDOI = DOI
.title = { -variable-type }: { -variable-string }. The DOI of the top item
snippet-itemFieldDOIURL = DOI or URL
.title = { -variable-type }: { -variable-string }. The DOI or URL of the top item
snippet-itemFieldAuthors = authors
.title = { -variable-type }: { -variable-string }. The authors of the top item
snippet-itemFieldJournal = journal
.title = { -variable-type }: { -variable-string }. The journal of the top item
snippet-itemFieldTitleTranslation = title translation
.title = { -variable-type }: { -variable-string }. The title translation of the top item
snippet-textTargetNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-textSharedObj = shared object
.title = { -variable-type }: { -variable-object }. A shared object that can be used to store data
snippet-quickInsertLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be linked
snippet-quickInsertLinkText = link text
.title = { -variable-type }: { -variable-string }. The default label of the link
snippet-quickInsertSubNoteItem = linked note
.title = { -variable-type }: { -variable-note }. The note item to be linked to
snippet-quickInsertNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickImportLink = note link
.title = { -variable-type }: { -variable-string }. The link of the note item to be imported
snippet-quickImportNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-quickNoteAnnotationItem = annotation
.title = { -variable-type }: { -variable-annotation }. The annotation item to be converted to a note
snippet-quickNoteTopItem = top item
.title = { -variable-type }: { -variable-item }. The top-level parent of the variable `annotationItem`
snippet-quickNoteNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to which the template is attached
snippet-exportMDFileNameNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileHeaderNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentNoteItem = target note
.title = { -variable-type }: { -variable-note }. The note item to be exported
snippet-exportMDFileContentMDContent = markdown content
.title = { -variable-type }: { -variable-string }. The markdown content to be exported

View File

@ -1,7 +1,5 @@
pref-title=Better Notes
menuItem-exportNote=导出笔记
menuEdit-exportTemplate=运行模板并导出为文件...
menuEdit-templateEditor=模板编辑器
menuEdit-importTemplate=从剪贴板导入笔记模板
@ -18,7 +16,27 @@ menuEditor-resizeImage=缩放图片
menuHelp-openUserGuide = 打开Better Notes用户指南
templateEditor-templateName = 模板名称
templateEditor-templateType = 类型
templateEditor-templateName = 名称
templateEditor-templateDisplayName =
.QuickInsertV2 = Quick Insert (插入链接)
.QuickImportV2 = Quick Import (嵌入链接笔记)
.QuickNoteV5 = Quick Note (从批注创建笔记)
.ExportMDFileNameV2 = Export MD File Name (导出MD文件名)
.ExportMDFileHeaderV2 = Export MD File Header (导出MD头)
.ExportMDFileContent = Export MD File Content (导出MD正文)
templateEditor-templateDisplayType =
.system = 内置
.item = 条目
.text = 文本
.unknown = ?
templateEditor-templateHelp =
.system = 用于特定目的,例如生成笔记链接。
.item = 可以从一个或多个选定的条目生成笔记片段。
.text = 可以生成笔记片段。不需要任何输入。
editor-resizeImage-title = 缩放图片
editor-resizeImage-prompt = 缩放图片宽度为:
@ -65,7 +83,7 @@ editor-toolbar-settings-openAsTab = 在标签页中打开
editor-toolbar-settings-openAsWindow = 在窗口中打开
editor-toolbar-settings-showInLibrary = 在文库中显示
editor-toolbar-settings-insertTemplate=插入模板
editor-toolbar-settings-refreshTemplates = 更新模板生成内容 (Beta)
editor-toolbar-settings-refreshTemplates = 更新模板生成内容
editor-toolbar-settings-copyLink=复制行(L{ $line })
editor-toolbar-settings-copyLinkAtSection=复制节(Sec. { $section })
editor-toolbar-settings-openParent=打开附件
@ -83,6 +101,7 @@ alert-notValidParentItemError=无效的父条目。
alert-syncImportedNotes = 保持导入的笔记与 MarkDown 文件同步?
alert-linkCreator-emptyNote = 无法从/向空笔记创建链接。
alert-templateEditor-shouldImport = 似乎您正在尝试直接保存一个笔记模板分享代码。您想要将其导入为模板吗?
alert-templateEditor-unsaved = 您在模板编辑器中有未保存的更改。您想要保存它们吗?
userGuide-start-title = 欢迎使用Better Notes
userGuide-start-desc = Better Notes是一个强大的笔记工具帮助您组织阅读论文时的概念和想法。本指南将帮助您开始使用Better Notes并向您展示如何充分利用其功能。

View File

@ -1,25 +0,0 @@
title=导出笔记
options-linkMode=链接笔记模式
options-MD=MarkDown(.md)
options-Docx=MS Word(.docx)
options-PDF=PDF(.pdf)
options-mm=思维导图
options-note=Zotero笔记
embedLink=全部嵌入为一个导出
standaloneLink=分别单独导出
keepLink=保留Zotero链接(zotero://note/)
exportMD=导出MD文件
setAutoSync=设置自动同步
.title=自动同步仅能在"分别单独导出模式"使用
withYAMLHeader=带有YAML头
autoMDFileName=自动生成MD文件名
exportDocx=导出Word文件
exportPDF=导出PDF文件
exportFreeMind=导出FreeMind文件
exportNote=导出为Zotero笔记条目
confirm=导出
cancel=关闭
target=目标: {$title}{ $left ->
[0]{ "" }
*[other] { " " }和其他{$left}个
}

View File

@ -0,0 +1,37 @@
title =
.title = 使用 Better Notes 导出笔记
target =
.value = 目标: {$title}{ $left ->
[0]{ "" }
*[other] { " " } 以及其他 {$left} 个。
}
format =
.value = 格式:
format-markdown =
.label = MarkDown(.md)
format-msword =
.label = MS Word(.docx)
format-pdf =
.label = PDF(.pdf)
format-freemind =
.label = 思维导图
format-note =
.label = Zotero 笔记
links-keep =
.label = 保留笔记链接(zotero://note/)
links-embed =
.label = 嵌入链接的笔记内容
links-standalone =
.label = 将链接的笔记分别导出
links-remove =
.label = 移除笔记链接
markdown-autoSync =
.label = 为每个笔记设置自动同步
.title = 自动同步适用于“将链接的笔记分别导出”模式。
markdown-withYAMLHeader =
.label = 包含 YAML 头
markdown-autoFilename =
.label = 自动生成文件名

View File

@ -3,13 +3,27 @@ basic-openNote-takeover =
.label = 接管打开笔记
basic-openNote-defaultAsWindow =
.label = 默认在窗口打开笔记
basic-exportNotes-takeover =
.label = 接管导出笔记
editor-title = 笔记编辑器
editor-expandLevel-label = 大纲展开至标题层级
editor-keepLinks =
.label = 在大纲中显示笔记链接
editor-noteLinkPreview =
.label = 鼠标悬停时显示笔记链接预览
editor-noteLinkPreviewType = 笔记链接预览触发方式:
editor-noteLinkPreview-hover =
.label = 鼠标悬停
editor-noteLinkPreview-ctrl =
.label = 按下 { PLATFORM() ->
[macos] ⌘
*[other] Ctrl
}
editor-noteLinkPreview-disable =
.label = 从不
editor-useMagicKey =
.label = 使用魔法键 "/" 显示命令面板
editor-useMarkdownPaste =
.label = 使用增强的Markdown粘贴
sync-title = 同步
sync-period-label = 自动同步周期 (秒)
@ -23,6 +37,10 @@ annotation-title = PDF批注
annotation-autoAnnotation =
.label = 自动添加新批注到工作区笔记
annotationNote-title = 从注释生成笔记
annotationNote-enableTagSync =
.label = 保持注释生成的笔记的标签与原始注释同步
about-title = 关于
help =
.value = { $name } 版本 { $version } 构建 { $time }

View File

@ -1,5 +1,19 @@
title = 模板编辑器
templateType = 模板{ -variable-type }
templateType-item =
.label = 条目
templateType-text =
.label = 文本
templateType-system =
.label = 内置
templateType-unknown =
.label = ?
templateType-help =
.label = ?
.title = 模板{ -variable-type }的详细解释
templateName = 模板名称
previewContainer =
@ -12,6 +26,9 @@ delete =
.label = 删除
reset =
.label = 重置
share =
.label = 分享
.tooltiptext = 复制模板分享代码到剪贴板
more =
.label = 更多模板
@ -21,11 +38,134 @@ importClipboard =
.label = 导入笔记模板: 剪贴板中的模板分享代码
importNote =
.label = 导入笔记模板: 从现有笔记
share =
.label = 复制模板分享代码到剪贴板
backup =
.label = 导出模板备份文件
restore =
.label = 从备份文件恢复
help =
.label = 帮助
format-bold =
.title = 加粗
format-italic =
.title = 斜体
format-strikethrough =
.title = 删除线
format-underline =
.title = 下划线
format-superscript =
.title = 上标
format-subscript =
.title = 下标
format-textColor =
.title = 文本颜色
format-link =
.title = 添加链接
format-quote =
.title = 引用文本
format-monospaced =
.title = 单行
format-code =
.title = 多行代码
format-table =
.title = 添加表格
format-h1 =
.title = 一级标题
format-h2 =
.title = 二级标题
format-h3 =
.title = 三级标题
format-bullet =
.title = 无序列表
format-numbered =
.title = 有序列表
format-inlineMath =
.title = 行内数学公式
format-blockMath =
.title = 多行数学公式
format-inlineScript =
.title = 添加行内JS脚本结果将嵌入到笔记中
format-blockScript =
.title = 添加多行异步JS脚本返回值将嵌入到笔记中
snippet-useMarkdown = 使用 markdown
.title = 将模板解析为 markdown
snippet-useRefresh = 允许内容刷新
.title = 允许模板生成的内容刷新
snippet-dryRunFlag = dry run标志
.title = 检查模板是否在dry run模式下运行例如用于预览。在dry run模式下脚本不应有副作用。
snippet-itemBeforeLoop = 循环前
.title = 在条目循环之前渲染的内容
snippet-itemInLoop = 循环中
.title = 为循环中的每个条目渲染的内容
snippet-itemAfterLoop = 循环后
.title = 在条目循环之后渲染的内容
-variable-type = 类型
-variable-item = Zotero.Item
-variable-note = Zotero.NoteItem
-variable-annotation = Zotero.AnnotationItem
-variable-string = 字符串
-variable-object = 对象
-variable-function = 函数
snippet-itemItems = 所有条目
.title = { -variable-type }{ -variable-item }[]。要渲染的条目数组,可在 beforeLoop 和 afterLoop 阶段使用
snippet-itemItem = 当前条目
.title = { -variable-type }{ -variable-item }。要渲染的当前条目,可在 inLoop 阶段使用
snippet-itemTopItem = 顶级条目
.title = { -variable-type }{ -variable-item }。变量 `item` 的顶级父级,可在 inLoop 阶段使用
snippet-itemTargetNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。模板插入到的笔记条目,可在任何阶段使用
snippet-itemCopyNoteImage = 复制笔记图片
.title = { -variable-type }{ -variable-function }。将笔记的图片复制到剪贴板,可在任何阶段使用
snippet-itemSharedObj = 共享对象
.title = { -variable-type }{ -variable-object }。可用于在不同阶段存储数据的共享对象
snippet-itemFieldTitle = 标题
.title = { -variable-type }{ -variable-string }。顶级条目的标题。可在 inLoop 阶段使用
snippet-itemFieldAbstract = 摘要
.title = { -variable-type }{ -variable-string }。顶级条目的摘要。可在 inLoop 阶段使用
snippet-itemFieldCitKey = citation key
.title = { -variable-type }{ -variable-string }。顶级条目的 citation key。可在 inLoop 阶段使用
snippet-itemFieldDate = 日期
.title = { -variable-type }{ -variable-string }。顶级条目的发布日期。可在 inLoop 阶段使用
snippet-itemFieldDOI = DOI
.title = { -variable-type }{ -variable-string }。顶级条目的DOI。可在 inLoop 阶段使用
snippet-itemFieldDOIURL = DOI或URL
.title = { -variable-type }{ -variable-string }。顶级条目的DOI或URL。可在 inLoop 阶段使用
snippet-itemFieldAuthors = 作者
.title = { -variable-type }{ -variable-string }。顶级条目的作者。可在 inLoop 阶段使用
snippet-itemFieldJournal = 期刊
.title = { -variable-type }{ -variable-string }。顶级条目的期刊。可在 inLoop 阶段使用
snippet-itemFieldTitleTranslation = 标题翻译
.title = { -variable-type }{ -variable-string }。顶级条目的标题翻译*需要Translate for Zotero插件。可在 inLoop 阶段使用
snippet-textTargetNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。模板插入到的笔记条目
snippet-textSharedObj = 共享对象
.title = { -variable-type }{ -variable-object }。可用于存储数据的共享对象
snippet-quickInsertLink = 笔记链接
.title = { -variable-type }{ -variable-string }。要链接的笔记条目的链接
snippet-quickInsertLinkText = 链接文本
.title = { -variable-type }{ -variable-string }。链接的默认标签
snippet-quickInsertSubNoteItem = 链接的笔记
.title = { -variable-type }{ -variable-note }。要链接到的笔记条目
snippet-quickInsertNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。模板插入到的笔记条目
snippet-quickImportLink = 笔记链接
.title = { -variable-type }{ -variable-string }。要导入的笔记条目的链接
snippet-quickImportNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。模板插入到的笔记条目
snippet-quickNoteAnnotationItem = 注释
.title = { -variable-type }{ -variable-annotation }。要转换为笔记的注释条目
snippet-quickNoteTopItem = 顶级条目
.title = { -variable-type }{ -variable-item }。变量 `annotationItem` 的顶级父级
snippet-quickNoteNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。模板插入到的笔记条目
snippet-exportMDFileNameNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。要导出的笔记条目
snippet-exportMDFileHeaderNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。要导出的笔记条目
snippet-exportMDFileContentNoteItem = 目标笔记
.title = { -variable-type }{ -variable-note }。要导出的笔记条目
snippet-exportMDFileContentMDContent = markdown 内容
.title = { -variable-type }{ -variable-string }。要导出的 markdown 内容

View File

@ -14,7 +14,7 @@
"id": "__addonID__",
"update_url": "__updateURL__",
"strict_min_version": "7.0.0-beta.70",
"strict_max_version": "7.0.*"
"strict_max_version": "7.1.*"
}
}
}

View File

@ -6,22 +6,15 @@ pref("__prefsPrefix__.autoAnnotation", false);
pref("__prefsPrefix__.insertLinkPosition", "end");
pref("__prefsPrefix__.embedLink", true);
pref("__prefsPrefix__.standaloneLink", false);
pref("__prefsPrefix__.keepLink", true);
pref("__prefsPrefix__.exportMD", true);
pref("__prefsPrefix__.setAutoSync", false);
pref("__prefsPrefix__.withYAMLHeader", false);
pref("__prefsPrefix__.autoMDFileName", false);
pref("__prefsPrefix__.exportDocx", false);
pref("__prefsPrefix__.exportPDF", false);
pref("__prefsPrefix__.exportFreeMind", false);
pref("__prefsPrefix__.exportNote", false);
pref("__prefsPrefix__.workspace.outline.expandLevel", 2);
pref("__prefsPrefix__.workspace.outline.keepLinks", true);
pref("__prefsPrefix__.editor.noteLinkPreview", true);
pref("__prefsPrefix__.editor.noteLinkPreviewType", "hover");
pref("__prefsPrefix__.editor.useMagicKey", true);
pref("__prefsPrefix__.editor.useMarkdownPaste", true);
pref("__prefsPrefix__.openNote.takeover", true);
pref("__prefsPrefix__.openNote.defaultAsWindow", false);
pref("__prefsPrefix__.exportNotes.takeover", true);
pref("__prefsPrefix__.annotationNote.enableTagSync", true);

View File

@ -13,7 +13,7 @@ One-click to import.
```yaml
# This template is specifically for importing/sharing, using better
# notes 'import from clipboard': copy the content and
# goto Zotero menu bar, click Edit->New Template from Clipboard.
# goto Zotero menu bar, click Tools->New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: "[Text] Current Time"
content: |-
@ -32,7 +32,7 @@ content: |-
</details>
2. Goto Zotero menubar, click `Edit`->`New Template from Clipboard`.
2. Goto Zotero menubar, click `Tools`->`New Template from Clipboard`.
3. Click OK.
Now you can open a note/the workspace and in editor toolbar, click `Insert Template to cursor line`. Select the template, it is inserted to the note.
@ -83,13 +83,14 @@ Pragmas are lines start with `// @`. They have special effect and will not be re
Let the compiler know you are using markdown. Otherwise the template will be processed as HTML.
### `// @use-update`
### `// @use-refresh`
Allow the generated content to be updated using the `Update content from templates` in the note editor.
The generated content will be wrapped in separators with a YAML metadata section for update.
This is a beta feature and can be changed/removed in the future.
> The template with this pragma should not contain any separator (`---` or `<hr>`) in the content.
The template with this pragma should not contain any separator (`---` or `<hr>`) in the content.
> Since the first line of the content is a separator, the note generated from a template with this pragma will have a blank note title. See the solution [here](https://github.com/windingwind/zotero-better-notes/issues/1247#issuecomment-2573739339).
### `// @author`
@ -149,7 +150,7 @@ If no stage pragma is given, the whole template will be processed on the default
```yaml
# This template is specifically for importing/sharing, using better
# notes 'import from clipboard': copy the content and
# goto Zotero menu bar, click Edit->New Template from Clipboard.
# goto Zotero menu bar, click Tools->New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: "[Item] Example Item Template"
content: |-
@ -215,7 +216,6 @@ The name of builtin templates are not allowed to be modified.
| Name | Description | Variables |
| ------------------- | -------------------------------------------------------- | ------------------------------------- |
| QuickInsert | For forward link. | link, linkText, subNoteItem, noteItem |
| QuickBackLink | For back link. | link, linkText, subNoteItem, noteItem |
| QuickImport | For importing note link content. | link, noteItem |
| QuickNote | For generating note from annotation. | annotationItem, topItem, noteItem |
| ExportMDFileName | For generating Markdown file name when exporting. | noteItem |
@ -305,10 +305,10 @@ ${{
}
key = att.key;
if (att.libraryID === 1) {
return `zotero://open-pdf/library/items/${key}`;
return `zotero://open/library/items/${key}`;
} else {
groupID = Zotero.Libraries.get(att.libraryID).id;
return `zotero://open-pdf/groups/${groupID}/items/${key}`;
return `zotero://open/groups/${groupID}/items/${key}`;
}
}
sharedObj.getPDFLink = getPDFLink;
@ -409,7 +409,7 @@ A template snippet should be in YAML format (YAML has better support for multi-l
```yaml
# This template is specifically for importing/sharing, using better
# notes 'import from clipboard': copy the content and
# goto Zotero menu bar, click Edit->New Template from Clipboard.
# goto Zotero menu bar, click Tools->New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: "[TYPE] TEMPLATE NAME"
content: |-

8645
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "zotero-better-notes",
"version": "1.1.4-beta.109",
"version": "2.2.5",
"description": "Everything about note management. All in Zotero.",
"config": {
"addonName": "Better Notes for Zotero",
@ -14,9 +14,11 @@
"scripts": {
"start": "zotero-plugin serve",
"build": "tsc --noEmit && zotero-plugin build",
"build-dev": "tsc --noEmit && zotero-plugin build --dev && cd build/addon && zip -r ../zotero-better-notes-dev.xpi .",
"release": "zotero-plugin release",
"lint": "prettier --write . && eslint . --ext .ts --fix",
"test": "echo \"Error: no test specified\" && exit 1",
"test": "zotero-plugin test --abort-on-fail --exit-on-finish",
"test-dev": "zotero-plugin test --abort-on-fail",
"update-deps": "npm update --save"
},
"repository": {
@ -30,16 +32,16 @@
},
"homepage": "https://github.com/windingwind/zotero-better-notes#readme",
"dependencies": {
"asciidoctor": "^3.0.2",
"dexie": "^4.0.4",
"diff": "^5.1.0",
"hast-util-to-html": "^9.0.0",
"asciidoctor": "^3.0.4",
"dexie": "^4.0.11",
"diff": "^5.2.0",
"hast-util-to-html": "^9.0.4",
"hast-util-to-mdast": "^8.4.1",
"hast-util-to-text": "^4.0.0",
"hast-util-to-text": "^4.0.2",
"hastscript": "^8.0.0",
"html-docx-js": "^0.3.1",
"html-docx-js-typescript": "^0.1.5",
"katex": "^0.16.9",
"katex": "^0.16.21",
"path-browserify": "^1.0.1",
"rehype-format": "^4.0.1",
"rehype-parse": "^8.0.5",
@ -56,36 +58,38 @@
"unist-util-visit": "^5.0.0",
"unist-util-visit-parents": "^6.0.1",
"yamljs": "^0.3.0",
"zotero-plugin-toolkit": "^2.3.37"
"zotero-plugin-toolkit": "^4.1.1"
},
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"@prettier/plugin-xml": "^3.2.2",
"@prettier/plugin-xml": "^3.4.1",
"@types/browser-or-node": "^1.3.2",
"@types/diff": "^5.0.9",
"@types/chai": "^5.0.1",
"@types/diff": "^5.2.3",
"@types/html-docx-js": "^0.3.4",
"@types/katex": "^0.16.7",
"@types/node": "^20.10.4",
"@types/path-browserify": "^1.0.2",
"@types/mocha": "^10.0.10",
"@types/node": "^20.17.14",
"@types/path-browserify": "^1.0.3",
"@types/seedrandom": "^3.0.8",
"@types/yamljs": "^0.2.34",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"chokidar-cli": "^3.0.0",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3",
"eslint": "^8.56.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.1.1",
"prosemirror-model": "^1.19.4",
"prettier": "^3.4.2",
"prosemirror-model": "^1.24.1",
"prosemirror-state": "^1.4.3",
"prosemirror-transform": "^1.8.0",
"prosemirror-view": "^1.32.6",
"prosemirror-transform": "^1.10.2",
"prosemirror-view": "^1.37.1",
"replace-in-file": "^7.2.0",
"typescript": "^5.3.3",
"xslt3": "^2.6.0",
"zotero-plugin-scaffold": "^0.0.32",
"zotero-types": "^2.0.1"
"typescript": "^5.7.3",
"xslt3": "^2.7.0",
"zotero-plugin-scaffold": "^0.2.0-beta.20",
"zotero-types": "^3.1.6"
},
"eslintConfig": {
"env": {

View File

@ -1,23 +1,20 @@
import { Prompt } from "zotero-plugin-toolkit/dist/managers/prompt";
import {
ColumnOptions,
VirtualizedTableHelper,
} from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { LargePrefHelper } from "zotero-plugin-toolkit/dist/helpers/largePref";
import ToolkitGlobal from "zotero-plugin-toolkit/dist/managers/toolkitGlobal";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit";
import { LargePrefHelper } from "zotero-plugin-toolkit";
import { getPref, setPref } from "./utils/prefs";
import { SyncDataType } from "./modules/sync/managerWindow";
import hooks from "./hooks";
import api from "./api";
import { createZToolkit } from "./utils/ztoolkit";
import { MessageHelper } from "zotero-plugin-toolkit/dist/helpers/message";
import type { handlers as parsingHandlers } from "./extras/parsingWorker";
import type { handlers as relationHandlers } from "./extras/relationWorker";
class Addon {
public data: {
uid: string;
alive: boolean;
// Env type, see build.js
env: "development" | "production";
env: "development" | "production" | "test";
initialized?: boolean;
ztoolkit: ZToolkit;
// ztoolkit: ZoteroToolkit;
locale?: {
@ -27,7 +24,7 @@ class Addon {
window: Window;
};
export: {
pdf: { promise?: _ZoteroTypes.PromiseObject };
pdf: { promise?: _ZoteroTypes.Promise.PromiseObject };
};
sync: {
data?: LargePrefHelper;
@ -65,18 +62,22 @@ class Addon {
window?: Window;
tableHelper?: VirtualizedTableHelper;
editor?: any;
monaco?: any;
templates: string[];
};
picker: {
mode: "insert" | "create" | "export";
mode: "insert" | "create" | "export" | "pick";
data: Record<string, any>;
};
};
relation: {
worker?: Worker;
server?: MessageHelper<typeof relationHandlers>;
};
parsing: {
server?: MessageHelper<typeof parsingHandlers>;
};
imageCache: Record<number, string>;
readonly prompt?: Prompt;
hint: {
silent: boolean;
};
@ -123,10 +124,8 @@ class Addon {
},
},
relation: {},
parsing: {},
imageCache: {},
get prompt() {
return ToolkitGlobal.getInstance().prompt.instance;
},
hint: {
silent: false,
},

View File

@ -34,6 +34,7 @@ import {
runTemplate,
runTextTemplate,
runItemTemplate,
runQuickInsertTemplate,
} from "./modules/template/api";
import {
getTemplateKeys,
@ -81,6 +82,8 @@ import {
updateNoteLinkRelation,
} from "./utils/relation";
import { getWorkspaceByTabID, getWorkspaceByUID } from "./utils/workspace";
import { getString } from "./utils/locale";
import { showRestartHint } from "./utils/hint";
const workspace = {
getWorkspaceByTabID,
@ -122,6 +125,7 @@ const template = {
runTemplate,
runTextTemplate,
runItemTemplate,
runQuickInsertTemplate,
getTemplateKeys,
getTemplateText,
setTemplate,
@ -178,6 +182,11 @@ const relation = {
getAnnotationByLinkTarget,
};
const utils = {
getString,
requireRestart: showRestartHint,
};
export default {
workspace,
sync,
@ -188,4 +197,5 @@ export default {
editor,
note,
relation,
utils,
};

View File

@ -5,6 +5,7 @@ export class PluginCEBase extends XULElementBase {
useShadowRoot = false;
connectedCallback(): void {
// @ts-ignore - plugin instance
this._addon = Zotero[config.addonInstance];
Zotero.UIProperties.registerRoot(this);
if (!this.useShadowRoot) {
@ -51,7 +52,7 @@ export class PluginCEBase extends XULElementBase {
const selector = `#${this._wrapID(key)}`;
return (this.querySelector(selector) ||
this.shadowRoot?.querySelector(selector)) as
| XUL.Element
| XULElement
| HTMLElement
| null;
}

View File

@ -66,10 +66,10 @@ export class InboundCreator extends PluginCEBase {
async accept(io: any) {
if (!this.targetNote) return;
const content = await this.getContentToInsert();
this.notePicker.saveRecentNotes();
io.targetNoteID = this.targetNote.id;
io.content = content;
io.sourceNoteIDs = [this.currentNote!.id];
io.lineIndex = this.getIndexToInsert();
}
@ -79,7 +79,7 @@ export class InboundCreator extends PluginCEBase {
await this.notePicker.load();
this.notePicker.addEventListener("selectionchange", (event: any) => {
this.targetNote = event.detail.selectedNote;
this.targetNote = event.detail.selectedNotes[0];
this.updatePickerTitle(this.targetNote);
this.noteOutline.item = this.targetNote;
this.noteOutline.render();
@ -215,21 +215,11 @@ export class InboundCreator extends PluginCEBase {
async getContentToInsert() {
if (!this.currentNote || !this.targetNote) return "";
const forwardLink = this._addon.api.convert.note2link(this.currentNote, {});
const content = await this._addon.api.template.runTemplate(
"[QuickInsertV2]",
"link, linkText, subNoteItem, noteItem",
[
forwardLink,
this.currentNote.getNoteTitle().trim() || forwardLink,
this.currentNote,
this.targetNote,
],
{
dryRun: true,
},
return await this._addon.api.template.runQuickInsertTemplate(
this.currentNote,
this.targetNote,
{ dryRun: true },
);
return content;
}
getIndexToInsert() {

View File

@ -1,7 +1,8 @@
import { config } from "../../../package.json";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit";
import { PluginCEBase } from "../base";
import {
getPref,
getPrefJSON,
registerPrefObserver,
setPref,
@ -19,17 +20,26 @@ export class NotePicker extends PluginCEBase {
itemsView!: _ZoteroTypes.ItemTree;
collectionsView!: _ZoteroTypes.CollectionTree;
openedNotesView!: VirtualizedTableHelper;
recentNotesView!: VirtualizedTableHelper;
_collectionsList!: XUL.Box;
_collectionsList!: XULBoxElement;
openedNotes: Zotero.Item[] = [];
activeSelectionType: "library" | "tabs" | "none" = "none";
recentNotes: Zotero.Item[] = [];
activeSelectionType: "library" | "tabs" | "recent" | "none" = "none";
uid = Zotero.Utilities.randomString(8);
_prefObserverID!: symbol;
_cachedLibraryIDs: number[] = [];
_cachedSelectedNoteIDs: number[] = [];
_disableSelectionChange = false;
get content() {
return MozXULElement.parseXULToFragment(`
<linkset>
@ -62,14 +72,20 @@ export class NotePicker extends PluginCEBase {
<html:div id="zotero-items-tree"></html:div>
</hbox>
</hbox>
<vbox id="bn-select-opened-notes-container" class="container">
<hbox id="bn-select-opened-notes-container" class="container">
<vbox
id="bn-select-opened-notes-content"
class="container virtualized-table-container"
class="container virtualized-table-container bn-note-list-container"
>
<html:div id="bn-select-opened-notes-tree-${this.uid}"></html:div>
</vbox>
</vbox>
<vbox
id="bn-select-recent-notes-content"
class="container virtualized-table-container bn-note-list-container"
>
<html:div id="bn-select-recent-notes-tree-${this.uid}"></html:div>
</vbox>
</hbox>
</vbox>
</vbox>
</vbox>
@ -91,7 +107,7 @@ export class NotePicker extends PluginCEBase {
this._collectionsList = this.querySelector(
"#zotero-collections-tree-container",
) as XUL.Box;
) as XULBoxElement;
this._restoreState();
@ -109,8 +125,8 @@ export class NotePicker extends PluginCEBase {
}
destroy(): void {
this.collectionsView.unregister();
if (this.itemsView) this.itemsView.unregister();
this.collectionsView?.unregister();
this.itemsView?.unregister();
unregisterPrefObserver(this._prefObserverID);
}
@ -118,6 +134,10 @@ export class NotePicker extends PluginCEBase {
await this.loadLibraryNotes();
this.loadQuickSearch();
await this.loadOpenedNotes();
this.recentNotes = this.getRecentNotes();
await this.loadRecentNotes();
}
async loadLibraryNotes() {
@ -250,6 +270,78 @@ export class NotePicker extends PluginCEBase {
// }
}
async loadRecentNotes() {
const renderLock = Zotero.Promise.defer();
this.recentNotesView = new VirtualizedTableHelper(window)
.setContainerId(`bn-select-recent-notes-tree-${this.uid}`)
.setProp({
id: `bn-select-recent-notes-table-${this.uid}`,
columns: [
{
dataKey: "title",
label: "Recent Notes",
flex: 1,
},
],
showHeader: true,
multiSelect: false,
staticColumns: true,
disableFontSizeScaling: true,
})
.setProp("getRowCount", () => this.recentNotes.length || 0)
.setProp("getRowData", (index) => {
const note = this.recentNotes[index];
return {
title: note.getNoteTitle(),
};
})
.setProp("onSelectionChange", (selection) => {
this.onRecentNoteSelected(selection);
})
// For find-as-you-type
.setProp(
"getRowString",
(index) => this.recentNotes[index].getNoteTitle() || "",
)
.setProp("renderItem", (index, selection, oldElem, columns) => {
let div;
if (oldElem) {
div = oldElem;
div.innerHTML = "";
} else {
div = document.createElement("div");
div.className = "row";
}
div.classList.toggle("selected", selection.isSelected(index));
div.classList.toggle("focused", selection.focused == index);
const rowData = this.recentNotes[index];
for (const column of columns) {
const span = document.createElement("span");
// @ts-ignore
span.className = `cell ${column?.className}`;
span.textContent = rowData.getNoteTitle();
const icon = getCSSItemTypeIcon("note");
icon.classList.add("cell-icon");
span.prepend(icon);
div.append(span);
}
return div;
})
.render(-1, () => {
renderLock.resolve();
});
await renderLock.promise;
if (this.recentNotes.length > 0) {
setTimeout(() => {
this.recentNotesView.treeInstance.selection.select(0);
this.onRecentNoteSelected(this.recentNotesView.treeInstance.selection);
}, 200);
}
}
onSearch() {
if (this.itemsView) {
const searchVal = (
@ -307,23 +399,98 @@ export class NotePicker extends PluginCEBase {
}
onItemSelected() {
if (this._disableSelectionChange) {
return;
}
this.activeSelectionType = "library";
const selectedIDs = this.itemsView.getSelectedItems(true) as number[];
// Compare the selected IDs with the cached IDs
// Since the library selection change can be triggered multiple times or with no change
if (arraysEqual(this._cachedLibraryIDs, selectedIDs)) {
return;
}
this.deselectOtherPanes();
this.dispatchSelectionChange();
}
onOpenedNoteSelected(selection: { selected: Set<number> }) {
if (this._disableSelectionChange) {
return;
}
this.activeSelectionType = "tabs";
this.deselectOtherPanes();
this.dispatchSelectionChange(selection);
}
onRecentNoteSelected(selection: { selected: Set<number> }) {
if (this._disableSelectionChange) {
return;
}
this.activeSelectionType = "recent";
this.deselectOtherPanes();
this.dispatchSelectionChange(selection);
}
deselectItemsPane() {
this.itemsView?.selection?.clearSelection();
}
deselectOpenedNotePane() {
this.openedNotesView?.treeInstance?.selection?.clearSelection();
}
deselectRecentNotePane() {
this.recentNotesView?.treeInstance?.selection?.clearSelection();
}
deselectOtherPanes() {
this._disableSelectionChange = true;
if (this.activeSelectionType !== "library") this.deselectItemsPane();
if (this.activeSelectionType !== "tabs") this.deselectOpenedNotePane();
if (this.activeSelectionType !== "recent") this.deselectRecentNotePane();
this._disableSelectionChange = false;
}
getRecentNotes() {
return ((getPref("linkCreator.recentNotes") as string) || "")
.split(",")
.map((id) => Zotero.Items.get(parseInt(id)))
.filter((item) => item && item.isNote());
}
saveRecentNotes() {
const selectedNotes = this.getSelectedNotes();
if (!selectedNotes.length) {
return;
}
const recentNotes: number[] = [...selectedNotes.map((note) => note.id)];
for (const note of this.recentNotes) {
if (!recentNotes.includes(note.id)) {
recentNotes.push(note.id);
}
}
// Save only 10 recent notes
setPref("linkCreator.recentNotes", recentNotes.slice(0, 10).join(","));
}
dispatchSelectionChange(selection?: { selected: Set<number> }) {
if (this._disableSelectionChange) {
return false;
}
const selectedNotes = this.getSelectedNotes(selection);
const selectedNoteIDs = selectedNotes.map((n) => n.id);
if (arraysEqual(this._cachedSelectedNoteIDs, selectedNoteIDs)) {
return false;
}
this._cachedSelectedNoteIDs = selectedNoteIDs;
this.dispatchEvent(
new CustomEvent("selectionchange", {
detail: {
selectedNote: this.getSelectedNotes(selection)[0],
selectedNotes,
},
}),
);
return true;
}
getSelectedNotes(selection?: { selected: Set<number> }): Zotero.Item[] {
@ -331,16 +498,22 @@ export class NotePicker extends PluginCEBase {
return [];
} else if (this.activeSelectionType == "library") {
return this.itemsView.getSelectedItems();
} else if (this.activeSelectionType == "tabs") {
return Array.from(
(selection || this.openedNotesView.treeInstance.selection).selected,
).map((index) => this.openedNotes[index]);
} else if (this.activeSelectionType == "recent") {
return Array.from(
(selection || this.recentNotesView.treeInstance.selection).selected,
).map((index) => this.recentNotes[index]);
}
return Array.from(
(selection || this.openedNotesView.treeInstance.selection).selected,
).map((index) => this.openedNotes[index]);
return [];
}
_persistState() {
let state = getPrefJSON(persistKey);
const collectionsListWidth = getComputedStyle(this._collectionsList).width;
const collectionsListWidth = getComputedStyle(this._collectionsList)?.width;
if (state?.collectionsListWidth === collectionsListWidth) {
return;
}
@ -358,9 +531,24 @@ export class NotePicker extends PluginCEBase {
if (
typeof state.collectionsListWidth === "string" &&
state.collectionsListWidth !==
Number(getComputedStyle(this._collectionsList).width)
Number(getComputedStyle(this._collectionsList)?.width)
) {
this._collectionsList.style.width = state.collectionsListWidth;
}
}
}
function arraysEqual(arr1: number[], arr2: number[]): boolean {
if (arr1.length !== arr2.length) return false;
const set1 = new Set(arr1);
const set2 = new Set(arr2);
if (set1.size !== set2.size) return false;
for (const item of set1) {
if (!set2.has(item)) return false;
}
return true;
}

View File

@ -1,5 +1,5 @@
import { config } from "../../../package.json";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit";
import { PluginCEBase } from "../base";
import TreeModel = require("tree-model");
import { waitUtilAsync } from "../../utils/wait";

View File

@ -13,7 +13,7 @@ export class OutboundCreator extends PluginCEBase {
// Where the link is inserted to
currentNote: Zotero.Item | undefined;
// Where the link is generated from
targetNote: Zotero.Item | undefined;
targetNotes: Zotero.Item[] | undefined;
positionData: NoteNodeData | undefined;
@ -68,10 +68,11 @@ export class OutboundCreator extends PluginCEBase {
}
async accept(io: any) {
if (!this.targetNote) return;
const content = await this.getContentToInsert();
if (!this.targetNotes) return;
this.notePicker.saveRecentNotes();
io.targetNoteID = this.currentNote!.id;
io.sourceNoteIDs = this.targetNotes.map((item) => item.id).filter(Boolean);
io.content = content;
io.lineIndex = this.getIndexToInsert();
}
@ -82,10 +83,10 @@ export class OutboundCreator extends PluginCEBase {
await this.notePicker.load();
this.notePicker.addEventListener("selectionchange", (event: any) => {
this.targetNote = event.detail.selectedNote;
this.updatePickerTitle(this.targetNote);
this.targetNotes = this.notePicker.getSelectedNotes();
this.updatePickerTitle(this.targetNotes);
this.updateNotePreview();
if (this.targetNote) this.scrollToSection("outline");
if (this.targetNotes) this.scrollToSection("outline");
});
const content = document.createElement("span");
@ -165,9 +166,22 @@ export class OutboundCreator extends PluginCEBase {
?.append(content, fromTitle, middleTitle, toTitle);
}
updatePickerTitle(noteItem?: Zotero.Item) {
const title = noteItem ? noteItem.getNoteTitle() : "";
this.querySelector("#selected-note-title")!.textContent = title;
getPickedNotesTitle(noteItems?: Zotero.Item[]) {
let title = "";
if (!noteItems?.length) {
title = "-";
}
if (noteItems?.length === 1) {
title = noteItems[0].getNoteTitle();
} else {
title = `${noteItems?.length} notes`;
}
return title;
}
updatePickerTitle(noteItems?: Zotero.Item[]) {
this.querySelector("#selected-note-title")!.textContent =
this.getPickedNotesTitle(noteItems);
}
updateOutlineTitle() {
@ -182,7 +196,7 @@ export class OutboundCreator extends PluginCEBase {
this.querySelector("#preview-note-middle-title") as HTMLElement
).dataset.l10nArgs = `{"show": "true"}`;
this.querySelector("#preview-note-to-title")!.textContent =
this.targetNote?.getNoteTitle() || "No title";
this.getPickedNotesTitle(this.targetNotes);
}
async updateNotePreview() {
@ -223,21 +237,17 @@ export class OutboundCreator extends PluginCEBase {
}
async getContentToInsert() {
if (!this.currentNote || !this.targetNote) return "";
const forwardLink = this._addon.api.convert.note2link(this.targetNote, {});
const content = await this._addon.api.template.runTemplate(
"[QuickInsertV2]",
"link, linkText, subNoteItem, noteItem",
[
forwardLink,
this.targetNote.getNoteTitle().trim() || forwardLink,
this.targetNote,
if (!this.currentNote || !this.targetNotes?.length) return "";
let content = "";
for (const note of this.targetNotes) {
content += await this._addon.api.template.runQuickInsertTemplate(
note,
this.currentNote,
],
{
dryRun: true,
},
);
{ dryRun: true },
);
content += "\n";
}
return content;
}

View File

@ -1,5 +1,5 @@
import { config } from "../../../package.json";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit/dist/helpers/virtualizedTable";
import { VirtualizedTableHelper } from "zotero-plugin-toolkit";
import { PluginCEBase } from "../base";
import TreeModel = require("tree-model");
@ -131,7 +131,9 @@ export class OutlinePicker extends PluginCEBase {
if (!this.item) {
return;
}
this.noteOutline = this._addon.api.note.getNoteTreeFlattened(this.item);
this.noteOutline = await this._addon.api.note.getNoteTreeFlattened(
this.item,
);
// Fake a cursor position
if (typeof this.lineIndex === "number") {
// @ts-ignore - formatValues is not in the types
@ -165,10 +167,11 @@ export class OutlinePicker extends PluginCEBase {
}
getSelectedSection(selection?: { selected: Set<number> }): NoteNodeData {
return this.noteOutline[
(selection || this.noteOutlineView.treeInstance.selection).selected
.values()
.next().value
]?.model;
const selected = (
selection || this.noteOutlineView.treeInstance.selection
).selected
.values()
.next().value;
return this.noteOutline[selected!]?.model;
}
}

View File

@ -1,4 +1,4 @@
import { FilePickerHelper } from "zotero-plugin-toolkit/dist/helpers/filePicker";
import { FilePickerHelper } from "zotero-plugin-toolkit";
import { config } from "../../../package.json";
import { formatPath } from "../../utils/str";
import { waitUtilAsync } from "../../utils/wait";
@ -148,7 +148,7 @@ export class OutlinePane extends PluginCEBase {
this._notifierID = Zotero.Notifier.registerObserver(
this,
["item"],
"attachmentsBox",
"bn-outline",
);
this._prefObserverID = registerPrefObserver(
@ -211,12 +211,13 @@ export class OutlinePane extends PluginCEBase {
"message",
this.messageHandler,
);
const nodes = await this._addon.api.note.getNoteTreeFlattened(this.item, {
keepLink: !!getPref("workspace.outline.keepLinks"),
});
this._outlineContainer.contentWindow?.postMessage(
{
type: "setMindMapData",
nodes: this._addon.api.note.getNoteTreeFlattened(this.item, {
keepLink: !!getPref("workspace.outline.keepLinks"),
}),
nodes,
expandLevel: getPref("workspace.outline.expandLevel"),
},
"*",
@ -235,7 +236,7 @@ export class OutlinePane extends PluginCEBase {
// Update set outline menu
this._queryID("setOutlinePopup")?.childNodes.forEach((elem) =>
(elem as XUL.MenuItem).removeAttribute("checked"),
(elem as XULMenuItemElement).removeAttribute("checked"),
);
this._queryID(
Object.keys(OutlinePane.outlineMenuIDs)[this.outlineType],
@ -267,7 +268,7 @@ export class OutlinePane extends PluginCEBase {
toolbarButtonCommandHandler = async (ev: Event) => {
if (!this.item) return;
const type = this._unwrapID((ev.target as XUL.ToolBarButton).id);
const type = this._unwrapID((ev.target as XULToolBarButtonElement).id);
switch (type) {
case "useTreeView":
case "useMindMap":
@ -316,13 +317,13 @@ export class OutlinePane extends PluginCEBase {
}
case "moveNode": {
if (!this.item) return;
const tree = this._addon.api.note.getNoteTree(this.item);
const fromNode = this._addon.api.note.getNoteTreeNodeById(
const tree = await this._addon.api.note.getNoteTree(this.item);
const fromNode = await this._addon.api.note.getNoteTreeNodeById(
this.item,
ev.data.fromID,
tree,
);
const toNode = this._addon.api.note.getNoteTreeNodeById(
const toNode = await this._addon.api.note.getNoteTreeNodeById(
this.item,
ev.data.toID,
tree,

View File

@ -21,11 +21,11 @@ export class Workspace extends PluginCEBase {
_editorElement!: EditorElement;
_outline!: OutlinePane;
_editorContainer!: XUL.Box;
_editorContainer!: XULBoxElement;
_context!: ContextPane;
_leftSplitter!: XUL.Splitter;
_rightSplitter!: XUL.Splitter;
_leftSplitter!: XULSplitterElement;
_rightSplitter!: XULSplitterElement;
resizeOb!: ResizeObserver;
@ -93,14 +93,14 @@ export class Workspace extends PluginCEBase {
this._outline = this._queryID("left-container") as unknown as OutlinePane;
this._editorContainer = this._queryID("center-container") as XUL.Box;
this._editorContainer = this._queryID("center-container") as XULBoxElement;
this._editorElement = this._queryID("editor-main") as EditorElement;
this._outline._editorElement = this._editorElement;
this._context = this._queryID("right-container") as unknown as ContextPane;
this._leftSplitter = this._queryID("left-splitter") as XUL.Splitter;
this._rightSplitter = this._queryID("right-splitter") as XUL.Splitter;
this._leftSplitter = this._queryID("left-splitter") as XULSplitterElement;
this._rightSplitter = this._queryID("right-splitter") as XULSplitterElement;
this._leftSplitter.addEventListener("mouseup", () => {
this._persistState();

View File

@ -0,0 +1,91 @@
import { insert } from "../../utils/editor";
export { formatMessage };
function formatMessage(message: string, locale: string) {
const stringObj = editorStrings[message as keyof typeof editorStrings];
if (!stringObj) {
return message;
}
return stringObj[locale as "en-US" | "zh-CN"] || message;
}
const editorStrings = {
insertTemplate: {
"en-US": "Insert Template",
"zh-CN": "插入模板",
},
outboundLink: {
"en-US": "Insert Outbound Link (Link to another note)",
"zh-CN": "插入出链 (链接到另一个笔记)",
},
inboundLink: {
"en-US": "Insert Inbound Link in another note (Link to this note)",
"zh-CN": "插入入链到另一笔记 (链接到本笔记)",
},
insertCitation: {
"en-US": "Insert Citation",
"zh-CN": "插入引用",
},
openAttachment: {
"en-US": "Open attachment of parent item",
"zh-CN": "打开父条目的附件",
},
copySectionLink: {
"en-US": "Copy Section Link",
"zh-CN": "复制章节链接",
},
copyLineLink: {
"en-US": "Copy Line Link",
"zh-CN": "复制行链接",
},
refreshTemplates: {
"en-US": "Update content from templates",
"zh-CN": "更新模板生成内容",
},
heading1: {
"en-US": "Heading 1",
"zh-CN": "一级标题",
},
heading2: {
"en-US": "Heading 2",
"zh-CN": "二级标题",
},
heading3: {
"en-US": "Heading 3",
"zh-CN": "三级标题",
},
paragraph: {
"en-US": "Paragraph",
"zh-CN": "段落",
},
monospaced: {
"en-US": "Monospaced",
"zh-CN": "等宽",
},
bulletList: {
"en-US": "Bullet List",
"zh-CN": "无序列表",
},
orderedList: {
"en-US": "Ordered List",
"zh-CN": "有序列表",
},
blockquote: {
"en-US": "Blockquote",
"zh-CN": "引用",
},
mathBlock: {
"en-US": "Math Block",
"zh-CN": "数学",
},
clearFormatting: {
"en-US": "Clear Format",
"zh-CN": "清除格式",
},
table: {
"en-US": "Table",
"zh-CN": "表格",
},
};

View File

@ -1,7 +1,7 @@
import { EditorState, Plugin, PluginKey } from "prosemirror-state";
import { Popup } from "./popup";
export { initLinkPreviewPlugin };
export { initLinkPreviewPlugin, LinkPreviewOptions };
declare const _currentEditorInstance: {
_editorCore: EditorCore;
@ -14,9 +14,11 @@ interface LinkPreviewOptions {
) => void;
openURL: (url: string) => void;
previewType: "hover" | "ctrl" | "disable";
}
class LinkPreviewState {
class PluginState {
state: EditorState;
options: LinkPreviewOptions;
@ -38,6 +40,10 @@ class LinkPreviewState {
update(state: EditorState, prevState?: EditorState) {
this.state = state;
if (this.options.previewType === "disable") {
return;
}
if (
prevState &&
prevState.doc.eq(state.doc) &&
@ -56,6 +62,10 @@ class LinkPreviewState {
}
handleMouseMove = async (event: MouseEvent) => {
if (this.options.previewType === "disable") {
return;
}
const { target } = event;
let isValid = false;
@ -67,7 +77,7 @@ class LinkPreviewState {
this.node = target;
this.currentLink = href;
this.hasHover = true;
this.tryOpenPopup();
this.tryOpenPopupByHover();
}
}
}
@ -79,7 +89,26 @@ class LinkPreviewState {
}
};
tryOpenPopup() {
handleKeydown = async (event: KeyboardEvent) => {
if (this.options.previewType !== "ctrl") {
return;
}
if (!this.hasHover || !this.currentLink) {
return;
}
const isMac =
typeof navigator != "undefined" ? /Mac/.test(navigator.platform) : false;
if ((isMac && event.metaKey) || (!isMac && event.ctrlKey)) {
this.tryTogglePopupByKey();
}
};
tryOpenPopupByHover() {
if (this.options.previewType !== "hover") {
return;
}
const href = this.currentLink!;
setTimeout(() => {
if (this.currentLink === href) {
@ -88,6 +117,14 @@ class LinkPreviewState {
}, 300);
}
tryTogglePopupByKey() {
if (this._hasPopup()) {
this._closePopup();
} else {
this._openPopup();
}
}
_openPopup() {
console.log("Enter Link Preview", this.currentLink, this.options);
document.querySelectorAll(".link-preview").forEach((el) => el.remove());
@ -106,6 +143,9 @@ class LinkPreviewState {
max-width: 100%;
height: auto;
}
.link-preview .primary-editor li {
white-space: normal;
}
</style>`),
]);
this.popup.popup.classList.add("primary-editor");
@ -155,41 +195,61 @@ class LinkPreviewState {
document.querySelectorAll(".link-preview").forEach((el) => el.remove());
this.popup = null;
}
_hasPopup() {
return !!document.querySelector(".link-preview");
}
}
function initLinkPreviewPlugin(options: LinkPreviewOptions) {
function initLinkPreviewPlugin(
plugins: readonly Plugin[],
options: LinkPreviewOptions,
) {
const core = _currentEditorInstance._editorCore;
console.log("Init BN Link Preview Plugin");
const key = new PluginKey("linkPreviewPlugin");
const newState = core.view.state.reconfigure({
plugins: [
...core.view.state.plugins,
new Plugin({
key,
state: {
init(config, state) {
return new LinkPreviewState(state, options);
return [
...plugins,
new Plugin({
key,
state: {
init(config, state) {
return new PluginState(state, options);
},
apply: (tr, pluginState, oldState, newState) => {
pluginState.update(newState, oldState);
return pluginState;
},
},
props: {
handleDOMEvents: {
mousemove: (view, event) => {
const pluginState = key.getState(view.state) as PluginState;
pluginState.update(view.state);
pluginState.handleMouseMove(event);
},
apply: (tr, pluginState, oldState, newState) => {
pluginState.update(newState, oldState);
return pluginState;
keydown: (view, event) => {
const pluginState = key.getState(view.state) as PluginState;
pluginState.handleKeydown(event);
},
wheel: (view, event) => {
const pluginState = key.getState(view.state) as PluginState;
pluginState.popup?.layoutPopup(pluginState);
},
},
props: {
handleDOMEvents: {
mousemove: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.update(view.state);
pluginState.handleMouseMove(event);
},
wheel: (view, event) => {
const pluginState = key.getState(view.state) as LinkPreviewState;
pluginState.popup?.layoutPopup(pluginState);
},
},
view: (editorView) => {
return {
update(view, prevState) {
const pluginState = key.getState(view.state) as PluginState;
pluginState.update(view.state, prevState);
},
},
}),
],
});
core.view.updateState(newState);
destroy() {
const pluginState = key.getState(editorView.state) as PluginState;
pluginState.destroy();
},
};
},
}),
];
}

View File

@ -0,0 +1,643 @@
import { EditorState, Plugin, PluginKey, Transaction } from "prosemirror-state";
import { Popup } from "./popup";
import { formatMessage } from "./editorStrings";
export { initMagicKeyPlugin, MagicKeyOptions };
declare const _currentEditorInstance: {
_editorCore: EditorCore;
};
interface MagicKeyOptions {
insertTemplate?: () => void;
refreshTemplates?: () => void;
insertLink?: (type: "inbound" | "outbound") => void;
copyLink?: (mode: "section" | "line") => void;
openAttachment?: () => void;
canOpenAttachment?: () => boolean;
enable?: boolean;
}
interface MagicCommand {
messageId?: string;
searchParts?: string[];
title?: string;
icon?: string;
command: (state: EditorState) => void | Transaction;
enabled?: (state: EditorState) => boolean;
}
class PluginState {
state: EditorState;
options: MagicKeyOptions;
_commands: MagicCommand[] = [
{
messageId: "insertTemplate",
searchParts: ["it", "insertTemplate"],
command: (state) => {
this.options.insertTemplate?.();
},
},
{
messageId: "outboundLink",
searchParts: ["ol", "obl", "outboundLink"],
command: (state) => {
this.options.insertLink?.("outbound");
},
},
{
messageId: "inboundLink",
searchParts: ["il", "ibl", "inboundLink"],
command: (state) => {
this.options.insertLink?.("inbound");
},
},
{
messageId: "insertCitation",
searchParts: ["ic", "insertCitation"],
command: (state) => {
getPlugin("citation")?.insertCitation();
},
},
{
messageId: "openAttachment",
searchParts: ["oa", "openAttachment"],
command: (state) => {
this.options.openAttachment?.();
},
enabled: (state) => {
return this.options.canOpenAttachment?.() || false;
},
},
{
messageId: "copySectionLink",
searchParts: ["csl", "copySectionLink"],
command: (state) => {
this.options.copyLink?.("section");
},
},
{
messageId: "copyLineLink",
searchParts: ["cll", "copyLineLink"],
command: (state) => {
this.options.copyLink?.("line");
},
},
{
messageId: "refreshTemplates",
searchParts: ["rt", "refreshTemplates"],
command: (state) => {
this.options.refreshTemplates?.();
},
},
{
messageId: "table",
searchParts: ["t", "tb", "table"],
command: (state) => {
const input = prompt(
"Enter the number of rows and columns, separated by a comma (e.g., 3,3)",
);
if (!input) {
return state.tr;
}
const splitter = input.includes("x")
? "x"
: input.includes(",")
? ","
: " ";
const [rows, cols] = input.split(splitter).map((n) => parseInt(n, 10));
if (isNaN(rows) || isNaN(cols)) {
return state.tr;
}
const { tr, selection } = state;
const { $from, $to } = selection;
const { pos } = $from;
const table = state.schema.nodes.table.createAndFill(
{},
Array.from(
{ length: rows },
() =>
state.schema.nodes.table_row.createAndFill(
{},
Array.from(
{ length: cols },
() => state.schema.nodes.table_cell.createAndFill()!,
),
)!,
),
)!;
tr.replaceWith(pos, pos, table);
_currentEditorInstance._editorCore.view.dispatch(tr);
},
},
{
messageId: "heading1",
searchParts: ["h1", "heading1"],
command: (state) => {
getPlugin()?.heading1.run();
},
},
{
messageId: "heading2",
searchParts: ["h2", "heading2"],
command: (state) => {
getPlugin()?.heading2.run();
},
},
{
messageId: "heading3",
searchParts: ["h3", "heading3"],
command: (state) => {
getPlugin()?.heading3.run();
},
},
{
messageId: "paragraph",
searchParts: ["p", "paragraph"],
command: (state) => {
getPlugin()?.paragraph.run();
},
},
{
messageId: "monospaced",
searchParts: ["m", "monospaced"],
command: (state) => {
getPlugin()?.codeBlock.run();
},
},
{
messageId: "bulletList",
searchParts: ["ul", "bulletList", "unorderedList"],
command: (state) => {
getPlugin()?.bulletList.run();
},
},
{
messageId: "orderedList",
searchParts: ["ol", "orderedList"],
command: (state) => {
getPlugin()?.orderedList.run();
},
},
{
messageId: "blockquote",
searchParts: ["bq", "blockquote"],
command: (state) => {
getPlugin()?.blockquote.run();
},
},
{
messageId: "mathBlock",
searchParts: ["mb", "mathBlock"],
command: (state) => {
getPlugin()?.math_display.run();
},
},
{
messageId: "clearFormatting",
searchParts: ["cf", "clearFormatting"],
command: (state) => {
getPlugin()?.clearFormatting.run();
},
},
];
get commands() {
return this._commands.filter((command) => {
if (command.enabled) {
return command.enabled(this.state);
}
return true;
});
}
popup: Popup | null = null;
selectedCommandIndex = 0;
get node() {
const node =
// @ts-ignore - private API
_currentEditorInstance._editorCore.view.domSelection().anchorNode;
if (node.nodeType === Node.TEXT_NODE) {
return node.parentElement;
}
return node;
}
popupClass = "command-palette";
constructor(state: EditorState, options: MagicKeyOptions) {
this.state = state;
this.options = options;
const locale = window.navigator.language || "en-US";
for (const key in this.commands) {
const command = this.commands[key];
if (command.messageId) {
command.title = formatMessage(command.messageId, locale);
}
}
this.update(state);
}
update(state: EditorState, prevState?: EditorState) {
this.state = state;
if (!prevState) {
return;
}
// Check if the selection has changed, then try to close the popup
if (!prevState.selection.eq(state.selection)) {
this._closePopup();
}
// If the document hasn't changed, we don't need to do anything
if (prevState.doc.eq(state.doc)) {
return;
}
// When `/` is pressed, we should open the command palette
const selectionText = state.doc.textBetween(
state.selection.from,
state.selection.to,
);
if (!selectionText) {
const { $from } = this.state.selection;
const { parent } = $from;
// Don't open the popup if we are in the document root
if (parent.type.name === "doc") {
return;
}
const text = parent.textContent;
if (text.endsWith("/") && !text.endsWith("//")) {
this._openPopup(state);
} else {
this._closePopup();
}
}
}
destroy() {
this.popup?.remove();
}
handleKeydown = async (event: KeyboardEvent) => {
if (!this._hasPopup()) {
return;
}
if (event.key === "Escape") {
this._closePopup();
}
};
_openPopup(state: EditorState) {
if (this._hasPopup()) {
return;
}
this.popup = new Popup(document, this.popupClass, [
document.createRange().createContextualFragment(`
<style>
.${this.popupClass} > .popup {
max-width: 360px;
max-height: 360px;
overflow: hidden;
}
.${this.popupClass} > .popup input {
padding: 0 7px;
background: var(--material-background);
border-radius: 5px;
border: var(--material-border-quinary);
width: 100%;
outline: none;
height: 28px;
flex-shrink: 0;
}
.${this.popupClass} > .popup input:focus {
outline: none;
border-color: rgba(0, 0, 0, 0);
box-shadow: 0 0 0 var(--width-focus-border) var(--color-focus-search);
}
.${this.popupClass} .popup-content {
display: flex;
flex-direction: column;
gap: 6px;
padding: 6px;
}
.${this.popupClass} .popup-list {
display: flex;
flex-direction: column;
gap: 4px;
overflow: hidden auto;
}
.${this.popupClass} .popup-item {
padding: 6px;
cursor: pointer;
border-radius: 5px;
}
.${this.popupClass} .popup-item:hover {
background-color: var(--fill-senary);
}
.${this.popupClass} .popup-item.selected {
background-color: var(--color-accent);
color: #fff;
}
</style>
<div class="popup-content">
<input type="text" class="popup-input" placeholder="Search commands" />
<div class="popup-list" tabindex="-1">
${Object.entries(this.commands)
.map(
([id, command]) => `
<div class="popup-item" data-command-id="${id}">
<div class="popup-item-icon">${command.icon || ""}</div>
<div class="popup-item-title">${command.title}</div>
</div>`,
)
.join("")}
</div>
</div>`),
]);
this.popup.layoutPopup(this);
// Focus the input
const input = this.popup.container.querySelector(
".popup-input",
) as HTMLInputElement;
input.focus();
// Handle input
input.addEventListener("input", (event) => {
const target = event.target as HTMLInputElement;
const value = target.value;
for (const [id, command] of Object.entries(this.commands)) {
const item = this.popup!.container.querySelector(
`.popup-item[data-command-id="${id}"]`,
) as HTMLElement;
if (!value) {
item.hidden = false;
continue;
}
const matchedIndex = command
.title!.toLowerCase()
.indexOf(value.toLowerCase());
if (
matchedIndex < 0 &&
// Try to match the search parts
!command.searchParts?.some((part) =>
part.toLowerCase().includes(value.toLowerCase()),
)
) {
item.hidden = true;
} else {
item.hidden = false;
}
if (matchedIndex >= 0) {
// Change the matched part to bold
const title = command.title!;
item.querySelector(".popup-item-title")!.innerHTML =
title.slice(0, matchedIndex) +
`<b>${title.slice(matchedIndex, matchedIndex + value.length)}</b>` +
title.slice(matchedIndex + value.length);
}
}
this._selectCommand();
});
input.addEventListener("keydown", (event) => {
if (event.key === "ArrowUp") {
this._selectCommand(this.selectedCommandIndex - 1, "up");
event.preventDefault();
} else if (event.key === "ArrowDown") {
this._selectCommand(this.selectedCommandIndex + 1, "down");
event.preventDefault();
} else if (event.key === "ArrowLeft") {
// Select the first command
this._selectCommand(this.commands.length, "up");
event.preventDefault();
} else if (event.key === "ArrowRight") {
// Select the last command
this._selectCommand(-1, "down");
event.preventDefault();
} else if (event.key === "Tab") {
// If has input, autocomplete the selected command to the first space
const command = this.commands[this.selectedCommandIndex];
if (!command) {
return;
}
if (!input.value) {
return;
}
const title = command.title!;
// Compute after the matched part
const matchedIndex = title
.toLowerCase()
.indexOf(input.value.toLowerCase());
const spaceIndex = title.indexOf(
" ",
matchedIndex + input.value.length,
);
if (spaceIndex >= 0) {
input.value = title.slice(0, spaceIndex);
} else {
input.value = title;
}
event.preventDefault();
} else if (event.key === "Enter") {
event.preventDefault();
const command = this.commands[this.selectedCommandIndex];
if (!command) {
this._closePopup();
return;
}
this._executeCommand(this.selectedCommandIndex, state);
} else if (event.key === "Escape") {
event.preventDefault();
this._closePopup();
} else if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
this._closePopup();
this.removeInputSlash(state);
}
});
this.popup.container.addEventListener("click", (event) => {
event.preventDefault();
event.stopPropagation();
const target = event.target as HTMLElement;
// Find the command
const item = target.closest(".popup-item") as HTMLElement;
if (!item) {
return;
}
const index = parseInt(item.dataset.commandId || "-1", 10);
this._executeCommand(index, state);
});
this._selectCommand(0);
}
_closePopup() {
if (!this._hasPopup()) {
return;
}
document
.querySelectorAll(`.${this.popupClass}`)
.forEach((el) => el.remove());
this.popup = null;
window.BetterNotesEditorAPI.refocusEditor();
}
_hasPopup() {
return !!document.querySelector(`.${this.popupClass}`);
}
_selectCommand(index?: number, direction: "up" | "down" = "down") {
if (typeof index === "undefined") {
index = this.selectedCommandIndex;
}
// Unselect the previous command
this.popup!.container.querySelectorAll(".popup-item.selected").forEach(
(el) => {
el.classList.remove("selected");
},
);
if (!this._hasPopup()) {
return;
}
const items = this.popup!.container.querySelectorAll(
".popup-item",
) as NodeListOf<HTMLElement>;
if (items[index]?.hidden) {
// Will find the next visible item in the specified direction
if (direction === "up") {
for (let i = index - 1; i >= 0; i--) {
if (!items[i].hidden) {
index = i;
break;
}
}
} else if (direction === "down") {
for (let i = index + 1; i < items.length; i++) {
if (!items[i].hidden) {
index = i;
break;
}
}
}
}
if (index >= items.length) {
// Find the first visible item with :first-of-type
const item = this.popup!.container.querySelector(
".popup-item:not([hidden])",
) as HTMLElement;
index = parseInt(item?.dataset.commandId || "-1", 10);
} else if (index < 0) {
// Find the last visible item with :last-of-type
const visibleItems = this.popup!.container.querySelectorAll(
".popup-item:not([hidden])",
);
const item = visibleItems[visibleItems.length - 1] as HTMLElement;
index = parseInt(item?.dataset.commandId || "-1", 10);
}
if (index < 0) {
this.selectedCommandIndex = -1;
return;
}
this.selectedCommandIndex = index;
items[index].classList.add("selected");
// Record the scroll position of the top document
const scrollTop = document.querySelector(".editor-core")!.scrollTop;
items[index].scrollIntoView({
block: "center",
});
// Restore the scroll position
document.querySelector(".editor-core")!.scrollTop = scrollTop;
}
_executeCommand(index: number, state: EditorState) {
const command = this.commands[index];
if (!command) {
return;
}
// Remove the current input `/`
this.removeInputSlash(state);
const newState = _currentEditorInstance._editorCore.view.state;
// Apply the command
try {
const mightBeTr = command.command(newState);
if (mightBeTr) {
_currentEditorInstance._editorCore.view.dispatch(mightBeTr);
}
} catch (error) {
console.error("Error applying command", error);
}
this._closePopup();
}
removeInputSlash(state: EditorState) {
const { $from } = state.selection;
const { pos } = $from;
const tr = state.tr.delete(pos - 1, pos);
_currentEditorInstance._editorCore.view.dispatch(tr);
}
}
function initMagicKeyPlugin(
plugins: readonly Plugin[],
options: MagicKeyOptions,
) {
console.log("Init BN Magic Key Plugin");
const key = new PluginKey("linkPreviewPlugin");
return [
...plugins,
new Plugin({
key,
state: {
init(config, state) {
return new PluginState(state, options);
},
apply: (tr, pluginState, oldState, newState) => {
pluginState.update(newState, oldState);
return pluginState;
},
},
props: {
handleDOMEvents: {
keydown: (view, event) => {
const pluginState = key.getState(view.state) as PluginState;
pluginState.handleKeydown(event);
},
},
},
view: (editorView) => {
return {
update(view, prevState) {
const pluginState = key.getState(view.state) as PluginState;
pluginState.update(view.state, prevState);
},
destroy() {
const pluginState = key.getState(editorView.state) as PluginState;
pluginState.destroy();
},
};
},
}),
];
}
function getPlugin(key = "menu") {
return _currentEditorInstance._editorCore.pluginState[key] as any;
}

View File

@ -0,0 +1,137 @@
import { Plugin, PluginKey } from "prosemirror-state";
import { md2html } from "../../utils/convert";
export { initMarkdownPastePlugin, MarkdownPasteOptions };
declare const _currentEditorInstance: {
_editorCore: EditorCore;
};
interface MarkdownPasteOptions {
enable: boolean;
}
function initMarkdownPastePlugin(plugins: readonly Plugin[]) {
const core = _currentEditorInstance._editorCore;
console.log("Init BN Markdown Paste Plugin");
const key = new PluginKey("pasteDropPlugin");
const oldPastePluginIndex = plugins.findIndex(
(plugin) => plugin.props.handlePaste && plugin.props.handleDrop,
);
if (oldPastePluginIndex === -1) {
console.error("Paste plugin not found");
return plugins;
}
const oldPastePlugin = plugins[oldPastePluginIndex];
return [
...plugins.slice(0, oldPastePluginIndex),
new Plugin({
key,
props: {
handlePaste: (view, event, slice) => {
if (!event.clipboardData) {
return false;
}
const markdown = getMarkdown(event.clipboardData);
if (!markdown) {
// Try the old paste plugin
return oldPastePlugin.props.handlePaste?.apply(oldPastePlugin, [
view,
event,
slice,
]);
}
md2html(markdown).then((html: string) => {
const slice = window.BetterNotesEditorAPI.getSliceFromHTML(
view.state,
html,
);
const tr = view.state.tr.replaceSelection(slice);
view.dispatch(tr);
});
return true;
},
handleDrop: (view, event, slice, moved) => {
if (!event.dataTransfer) {
return false;
}
const markdown = getMarkdown(event.dataTransfer);
if (!markdown) {
// Try the old drop plugin first
return oldPastePlugin.props.handleDrop?.apply(oldPastePlugin, [
view,
event,
slice,
moved,
]);
}
md2html(markdown).then((html: string) => {
const slice = window.BetterNotesEditorAPI.getSliceFromHTML(
view.state,
html,
);
const pos = view.posAtCoords({
left: event.clientX,
top: event.clientY,
});
if (!pos) {
return;
}
// Insert the slice to the current position
const tr = view.state.tr.insert(pos.pos, slice);
view.dispatch(tr);
});
return true;
},
},
view: (editorView) => {
return {
destroy() {},
};
},
}),
...plugins.slice(oldPastePluginIndex + 1),
];
}
function getMarkdown(clipboardData: DataTransfer) {
// If the clipboard contains HTML, don't handle it
if (clipboardData.types.includes("text/html")) {
return false;
}
if (clipboardData.types.includes("text/markdown")) {
return clipboardData.getData("text/markdown");
}
// For Typora
if (clipboardData.types.includes("text/x-markdown")) {
return clipboardData.getData("text/x-markdown");
}
// Match markdown patterns
if (clipboardData.types.includes("text/plain")) {
const text = clipboardData.getData("text/plain");
const markdownPatterns = [
/^#/m, // Headers: Lines starting with #
/^\s*[-+*]\s/m, // Unordered lists: Lines starting with -, +, or *
/^\d+\.\s/m, // Ordered lists: Lines starting with numbers followed by a dot
/\[.*\]\(.*\)/, // Links: [text](url)
/`[^`]+`/, // Inline code: `code`
/^> /m, // Blockquotes: Lines starting with >
/```/, // Code blocks: Triple backticks
];
for (const pattern of markdownPatterns) {
if (pattern.test(text)) {
return text;
}
}
}
return false;
}

View File

@ -0,0 +1,28 @@
import { initLinkPreviewPlugin, LinkPreviewOptions } from "./linkPreview";
import { initMagicKeyPlugin, MagicKeyOptions } from "./magicKey";
import { initMarkdownPastePlugin, MarkdownPasteOptions } from "./markdownPaste";
export { initPlugins };
declare const _currentEditorInstance: {
_editorCore: EditorCore;
};
function initPlugins(options: {
linkPreview: LinkPreviewOptions;
magicKey: MagicKeyOptions;
markdownPaste: MarkdownPasteOptions;
}) {
const core = _currentEditorInstance._editorCore;
let plugins = core.view.state.plugins;
if (options.linkPreview.previewType !== "disable")
plugins = initLinkPreviewPlugin(plugins, options.linkPreview);
if (options.markdownPaste.enable) plugins = initMarkdownPastePlugin(plugins);
if (options.magicKey.enable)
plugins = initMagicKeyPlugin(plugins, options.magicKey);
// Collect all plugins and reconfigure the state only once
const newState = core.view.state.reconfigure({
plugins,
});
core.view.updateState(newState);
}

View File

@ -5,6 +5,8 @@ class Popup {
hasHover = false;
className: string;
get container() {
return this._popup;
}
@ -18,6 +20,7 @@ class Popup {
className?: string,
children: (HTMLElement | DocumentFragment)[] = [],
) {
this.className = className || "";
this._popup = doc.createElement("div");
this._popup.className = `popup-container ${className}`;
this._popup.innerHTML = `
@ -58,7 +61,7 @@ class Popup {
// Bottom
const otherPopupHeight = Array.from(
popupParent.querySelectorAll(
".popup-container:not(.link-preview) > .popup.popup-bottom",
`.popup-container:not(.${this.className}) > .popup.popup-bottom`,
),
).reduce((acc, el) => acc + (el as HTMLElement).offsetHeight, 0);
top =
@ -72,7 +75,7 @@ class Popup {
// Top
const otherPopupHeight = Array.from(
popupParent.querySelectorAll(
".popup-container:not(.link-preview) > .popup.popup-top",
`.popup-container:not(.${this.className}) > .popup.popup-top`,
),
).reduce((acc, el) => acc + (el as HTMLElement).offsetHeight, 0);
top =

View File

@ -11,7 +11,7 @@ import {
} from "prosemirror-model";
import { EditorState, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { initLinkPreviewPlugin } from "./editor/linkPreview";
import { initPlugins } from "./editor/plugins";
declare const _currentEditorInstance: {
_editorCore: EditorCore;
@ -377,7 +377,7 @@ export const BetterNotesEditorAPI = {
getSliceFromHTML,
getNodeFromHTML,
setSelection,
initLinkPreviewPlugin,
initPlugins,
};
// @ts-ignore

185
src/extras/exportNotes.ts Normal file
View File

@ -0,0 +1,185 @@
import { getPref, setPref } from "../utils/prefs";
let io: {
targetData: {
left: number;
title: string;
};
accepted: boolean;
useBuiltInExport: boolean;
deferred: _ZoteroTypes.Promise.DeferredPromise<void>;
embedLink: boolean;
standaloneLink: boolean;
exportNote: boolean;
exportMD: boolean;
setAutoSync: boolean;
autoMDFileName: boolean;
withYAMLHeader: boolean;
exportDocx: boolean;
exportPDF: boolean;
exportFreeMind: boolean;
};
window.onload = async function () {
if (document.readyState === "complete") {
setTimeout(init, 0);
return;
}
document.addEventListener("DOMContentLoaded", init, { once: true });
};
window.onunload = function () {
io.deferred && io.deferred.resolve();
};
function init() {
const dialog = document.querySelector("dialog")!;
Zotero.UIProperties.registerRoot(dialog);
io = window.arguments[0];
window.addEventListener("dialogaccept", doAccept);
window.addEventListener("dialogextra1", () => doUseBuiltInExport());
document
.querySelector("#format")!
.addEventListener("command", onFormatChange);
document
.querySelector("#linkMode")!
.addEventListener("command", updateMarkdownOptions);
document
.querySelector("#markdown-autoSync")!
.addEventListener("command", updateMarkdownOptions);
(document.querySelector("#target") as XULElement).dataset.l10nArgs =
JSON.stringify(io.targetData);
restore();
onFormatChange();
updateMarkdownOptions();
}
function restore() {
let format = getPref("export.format") as string;
if (!["markdown", "msword", "pdf", "freemind", "note"].includes(format)) {
format = "markdown";
}
(document.querySelector("#format") as XULMenuListElement).value = format;
let linkMode = getPref("export.linkMode") as string;
if (!["keep", "embed", "standalone", "remove"].includes(linkMode)) {
linkMode = "keep";
}
(document.querySelector("#linkMode") as XULRadioGroupElement).value =
linkMode;
const markdownPrefs = ["autoSync", "withYAMLHeader", "autoFilename"];
for (const pref of markdownPrefs) {
(
document.querySelector(`#markdown-${pref}`) as XULCheckboxElement
).checked = getPref(`export.markdown-${pref}`) as boolean;
}
}
function cache() {
setPref(
"export.format",
(document.querySelector("#format") as XULMenuListElement).value,
);
setPref(
"export.linkMode",
(document.querySelector("#linkMode") as XULRadioGroupElement).value,
);
const markdownPrefs = ["autoSync", "withYAMLHeader", "autoFilename"];
for (const pref of markdownPrefs) {
setPref(
`export.markdown-${pref}`,
(document.querySelector(`#markdown-${pref}`) as XULCheckboxElement)
.checked,
);
}
}
function onFormatChange() {
const format = (document.querySelector("#format") as XULMenuListElement)
.value;
const isMD = format === "markdown";
(document.querySelector("#markdown-options") as XULBoxElement).hidden = !isMD;
window.sizeToContent();
}
function updateMarkdownOptions() {
const linkModeRadio = document.querySelector(
"#linkMode",
) as XULRadioGroupElement;
const autoSyncRadio = document.querySelector(
"#markdown-autoSync",
) as XULCheckboxElement;
if (linkModeRadio.value !== "standalone") {
autoSyncRadio.checked = false;
autoSyncRadio.disabled = true;
} else {
autoSyncRadio.disabled = false;
}
const autoFilename = document.querySelector(
"#markdown-autoFilename",
) as XULCheckboxElement;
const withYAMLHeader = document.querySelector(
"#markdown-withYAMLHeader",
) as XULCheckboxElement;
if (autoSyncRadio.checked) {
autoFilename.checked = true;
autoFilename.disabled = true;
withYAMLHeader.checked = true;
withYAMLHeader.disabled = true;
} else {
autoFilename.disabled = false;
withYAMLHeader.disabled = false;
}
}
function doAccept() {
cache();
// Format
const format = (document.querySelector("#format") as XULMenuListElement)
.value;
io.exportMD = format === "markdown";
io.exportDocx = format === "msword";
io.exportPDF = format === "pdf";
io.exportFreeMind = format === "freemind";
io.exportNote = format === "note";
// Markdown options
io.autoMDFileName = (
document.querySelector("#markdown-autoFilename") as XULCheckboxElement
).checked;
io.withYAMLHeader = (
document.querySelector("#markdown-withYAMLHeader") as XULCheckboxElement
).checked;
io.setAutoSync = (
document.querySelector("#markdown-autoSync") as XULCheckboxElement
).checked;
// Link mode
const linkMode = (document.querySelector("#linkMode") as XULRadioGroupElement)
.value;
io.embedLink = linkMode === "embed";
io.standaloneLink = linkMode === "standalone";
io.accepted = true;
}
function doUseBuiltInExport() {
io.useBuiltInExport = true;
window.close();
}

View File

@ -2,7 +2,7 @@ import { getPref, setPref } from "../utils/prefs";
import { InboundCreator } from "../elements/linkCreator/inboundCreator";
import { OutboundCreator } from "../elements/linkCreator/outboundCreator";
let tabbox: XUL.TabBox;
let tabbox: XULTabBoxElement;
let inboundCreator: InboundCreator;
let outboundCreator: OutboundCreator;
@ -10,11 +10,12 @@ let io: {
currentNoteID: number;
currentLineIndex?: number;
openedNoteIDs?: number[];
deferred: _ZoteroTypes.DeferredPromise<void>;
deferred: _ZoteroTypes.Promise.DeferredPromise<void>;
targetNoteID?: number;
content?: string;
lineIndex?: number;
mode?: "inbound" | "outbound";
};
window.onload = async function () {
@ -39,7 +40,7 @@ window.onunload = function () {
function init() {
// Set font size from pref
const sbc = document.getElementById("top-container");
Zotero.UIProperties.registerRoot(sbc);
Zotero.UIProperties.registerRoot(sbc!);
setTimeout(() => {
const size = ((getPref("windows.linkCreator.size") as string) || "").split(
@ -50,9 +51,20 @@ function init() {
io = window.arguments[0];
if (!io.deferred) {
// @ts-ignore
io = io.wrappedJSObject;
}
tabbox = document.querySelector("#top-container")!;
tabbox.selectedIndex =
(getPref("windows.linkCreator.tabIndex") as number) || 0;
if (io.mode) {
tabbox.selectedIndex = io.mode === "inbound" ? 0 : 1;
} else {
tabbox.selectedIndex =
(getPref("windows.linkCreator.tabIndex") as number) || 0;
}
tabbox.addEventListener("select", loadSelectedPanel);
inboundCreator = document.querySelector(

112
src/extras/parsingWorker.ts Normal file
View File

@ -0,0 +1,112 @@
import { MessageHelper } from "zotero-plugin-toolkit";
export { handlers };
function parseHTMLLines(html: string): string[] {
const randomString: string = `${Math.random()}`;
console.time(`parseHTMLLines-${randomString}`);
// Remove container with one of the attrs named data-schema-version if exists
if (html.includes("data-schema-version")) {
html = html.replace(/<div[^>]*data-schema-version[^>]*>/, "");
html = html.replace(/<\/div>/, "");
}
const noteLines = html.split("\n").filter((e) => e);
// A cache for temporarily stored lines
let previousLineCache = [];
let nextLineCache = [];
const forceInline = ["table", "blockquote", "pre", "ol", "ul"];
const selfInline: string[] = [];
const forceInlineStack = [];
let forceInlineFlag = false;
let selfInlineFlag = false;
const parsedLines = [];
for (const line of noteLines) {
// restore self inline flag
selfInlineFlag = false;
// For force inline tags, set flag to append lines to current line
for (const tag of forceInline) {
const startReg = `<${tag}`;
const isStart = line.includes(startReg);
const endReg = `</${tag}>`;
const isEnd = line.includes(endReg);
if (isStart && !isEnd) {
forceInlineStack.push(tag);
// console.log("push", tag, line, forceInlineStack);
forceInlineFlag = true;
break;
}
if (isEnd && !isStart) {
forceInlineStack.pop();
// console.log("pop", tag, line, forceInlineStack);
// Exit force inline mode if the stack is empty
if (forceInlineStack.length === 0) {
forceInlineFlag = false;
}
break;
}
}
if (forceInlineFlag) {
nextLineCache.push(line);
} else {
// For self inline tags, cache start as previous line and end as next line
for (const tag of selfInline) {
const isStart = line.includes(`<${tag}`);
const isEnd = line.includes(`</${tag}>`);
if (isStart && !isEnd) {
selfInlineFlag = true;
nextLineCache.push(line);
break;
}
if (!isStart && isEnd) {
selfInlineFlag = true;
previousLineCache.push(line);
break;
}
}
if (!selfInlineFlag) {
// Append cache to previous line
if (previousLineCache.length) {
parsedLines[parsedLines.length - 1] += `\n${previousLineCache.join(
"\n",
)}`;
previousLineCache = [];
}
let nextLine = "";
// Append cache to next line
if (nextLineCache.length) {
nextLine = nextLineCache.join("\n");
nextLineCache = [];
}
if (nextLine) {
nextLine += "\n";
}
nextLine += `${line}`;
parsedLines.push(nextLine);
}
}
}
console.timeEnd(`parseHTMLLines-${randomString}`);
return parsedLines;
}
const handlers = {
parseHTMLLines,
};
const messageServer = new MessageHelper({
canBeDestroyed: true,
dev: true,
name: "parsingWorker",
target: self,
handlers,
});
messageServer.start();

Some files were not shown because too many files have changed in this diff Show More