Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

同步未过时的插件开发者文档 #125

Merged
merged 8 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/.vuepress/sidebar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { sidebar } from "vuepress-theme-hope";

export const zhSidebar = sidebar({
"/user-guide/": userGuide,
"/plugin-dev-guide/": "structure",
"/plugin-dev-guide/": pluginDevGuide,
"/csl-dev-guide/": cslDevGuide,
"/": [
"about",
Expand Down
34 changes: 33 additions & 1 deletion src/.vuepress/sidebar/plugin-dev-guide.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
import { arraySidebar } from "vuepress-theme-hope";

export const pluginDevGuide = arraySidebar([""]);
export const pluginDevGuide = arraySidebar([
"",
{
text: "从 Mark-It-Red 开始",
collapsible: true,
children: ["quick-start/"],
},
{
text: "使用社区框架",
collapsible: true,
children: ["use-template"],
},
{
text: "调试代码",
collapsible: true,
children: ["development/debug", "development/sideloading"],
},
{
text: "参考",
collapsible: true,
children: [
"reference/manifest",
"reference/bootstrap",
"reference/localization",
"reference/update",
"reference/zotero",
"reference/preference",
"reference/notify",
"reference/item",
"reference/more",
],
},
]);
47 changes: 47 additions & 0 deletions src/plugin-dev-guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
title: 插件开发指南
date: 2023-04-20 10:06:59
updated: 2023-07-20 16:51:54
author:
- name: windingwind
url: https://github.com/windingwind/
---

# 插件开发指南
Expand All @@ -11,3 +14,47 @@ updated: 2023-07-20 16:51:54
待完善,前托管于语雀的开发者文档主要针对 Zotero 6,鉴于插件在 Zotero 7 相对 Zotero 6 变动较大,因此插件开发者文档需要重写。

:::

本文档所述内容仅适用于 Zotero 7 插件开发,Zotero 6 插件开发文档请参阅 [Zotero 6 插件开发文档](https://zotero.yuque.com/staff-gkhviy/developer/)。

## 前置基础知识

Zotero 插件遵循 Firefox 插件的要求。此处列举了编写插件的基础知识。并非所有知识都需要掌握,只需要在遇到问题时能通过查阅文档找到解决方法即可。

### Firefox 插件

[Introduction: Welcome to Software Development the Mozilla Way](http://mb.eschew.org/intro)

[Web 浏览器扩展](https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions)

### HTML / XUL

关于 HTML,可参考网上的任意教程,只需理解基本的树结构,大致清楚元素类型与通用属性即可。
参考文档:[HTML 教程 | 菜鸟教程](https://www.runoob.com/html/html-tutorial.html)
关于 XUL,在了解 HTML 的基础上只需大概浏览文档即可。在使用时可随时查阅文档。
参考文档:[Huihoo - XML User Interface Language (XUL)](https://docs.huihoo.com/xul/),[XUL School Tutorial - Archive of obsolete content](https://udn.realityripple.com/docs/Archive/Add-ons/Overlay_Extensions/XUL_School)

### JavaScript / TypeScript

如果对其他编程语言有了解,上手 JavaScript 很快,看一下基本语法即可。
参考文档:[JavaScript 教程](https://www.w3school.com.cn/js/index.asp)

(非必需)也可以直接学习 TypeScript,它是 JS 的超集,提供了更多特性,并对习惯于 C++/JAVA 等强类型语言的开发者而言更加熟悉。第二章将要介绍的的 Zotero 插件框架支持 TS。
参考文档:[TypeScript 中文网 · TypeScript——JavaScript 的超集](https://www.tslang.cn/)

### Git

Git 是版本管理的常用工具。
参考文档:[Git 教程 | 菜鸟教程](https://www.runoob.com/git/git-tutorial.html)

### Zotero 官方资料

Zoero 文档(部分过时或不全):[start [Zotero Documentation]](https://www.zotero.org/support/)
Zotero 社区:[Recent Discussions](https://forums.zotero.org/discussions)
Zotero 贡献文档:[Zotero | Get Involved](https://www.zotero.org/getinvolved/)
Zotero 开发者群组:[https://groups.google.com/g/zotero-dev](https://groups.google.com/g/zotero-dev)
社区维护的 Zotero Types 接口类型定义包:[windingwind / Zotero-types](https://github.com/windingwind/zotero-types) [Zotero-types](https://www.npmjs.com/package/zotero-types)

## 本文档的结构

> todo
49 changes: 49 additions & 0 deletions src/plugin-dev-guide/development/debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
author:
- name: windingwind
url: https://github.com/windingwind/
- name: ShareStuff
- name: northword
url: https://github.com/northword/
---

# 调试代码

## 通过 Run JavaScript 调试

从 `菜单栏` -> `工具` -> `开发者` -> `Run JavaScript` 打开界面。

在左侧键入代码,点击运行即可在右侧看到输出。

如果代码中包含异步语法(async),需要将结果 return 才能在右侧看见。

## 通过 Zotero.debug 输出日志

- 使用 `Zotero.debug` 输出到 `菜单栏` -> `帮助` -> `输出日志排错` -> `查看输出文件`;
- 使用 `Zotero.log` 输出到 `菜单栏` -> `工具` -> `开发者` -> `Error Console`。

## 通过开发者工具

如果你不熟悉开发者工具,可参看[什么是浏览器开发者工具? - 学习 Web 开发 | MDN](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/What_are_browser_developer_tools)

远程调试需要 [Zotero beta builds](https://www.zotero.org/support/beta_builds) 。Windows 开发者可下载 zip 版本,解压缩后即可使用,不会将正式版覆盖。

截止至最后编辑日期,Zotero 底层基于 Firefox 102 ESR。

1. 打开 Zotero Beta,打开 `菜单栏` -> `编辑` -> `首选项` -> `高级` -> `设置编辑器`,搜索 `debug` 并开启 `remote debugging`。
2. 使用 `--debugger` 参数启动 Zotero。
也可以将启动参数写入快捷方式。
3. 在 FireFox 102 ESR 中,找到`设置` -> `更多工具` -> `远程调试`(或者浏览器中输入:`about:debugging#/setup`),找到网络位置,输入 `localhost:6100`,点击确定添加即可。
4. 选择 `localhost:6100`,然后点击进程中的多线程工具箱进行检查,可进入控制台、无障碍环境等进行调试

::: tip 模板用户无需手动配置

模板的启动脚本中已经进行了相关配置,因此你无需再手动执行以上步骤,直接打开 FireFox 远程调试即可。

:::

::: tip Zotero 正在包含此功能

Zotero 团队正在将开发者工具嵌入 Zotero,见 [PR #3387](https://github.com/zotero/zotero/pull/3387),此 PR 合并后即可直接从菜单呼出开发者工具,而无需安装 FireFox。

:::
13 changes: 13 additions & 0 deletions src/plugin-dev-guide/development/sideloading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# 侧载插件

::: note Todo

此页说明如何将插件侧载入 Zotero,待完善,请参阅:[Setting Up a Plugin Development Environment](https://www.zotero.org/support/dev/client_coding/plugin_development#setting_up_a_plugin_development_environment)。

:::

::: tip

使用社区模板的开发者,无需配置这些环境,只需要按照模板要求配置 Zotero 可执行文件路径和配置文件地址即可。模板中的启动脚本将为你自动完成以上步骤。

:::
9 changes: 9 additions & 0 deletions src/plugin-dev-guide/quick-start/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 快速开始

此节以官方插件示例 [Make It Red](https://github.com/zotero/make-it-red/tree/main/src-2.0) 为例,说明 Zotero 插件的工作过程。

::: note Todo

待完善,请参阅插件仓库:[Make It Red](https://github.com/zotero/make-it-red/tree/main/src-2.0)

:::
1 change: 1 addition & 0 deletions src/plugin-dev-guide/reference/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# 参考
129 changes: 129 additions & 0 deletions src/plugin-dev-guide/reference/bootstrap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
author:
- name: windingwind
url: https://github.com/windingwind/
- name: northword
url: https://github.com/northword/
---

# 引导脚本

引导脚本即 `bootstrap.js`,这是 Zotero 插件的入口脚本文件,此文件必须存在,否则插件将无法被安装。

## 内容

这个文件里必须包含以下几个钩子,Zotero 将在对应动作发生时调用对应的钩子。

### 生命周期钩子

```js
// 插件被安装时调用
function install(data, reason) {}

// 插件启动时调用
function startup(data, reason) {}

// 插件被禁用时或 Zotero 被关闭时调用
function shutdown(data, reason) {}

// 插件被卸载时调用
function uninstall(data, reason) {}
```

插件生命周期挂钩传递两个参数:

- 具有以下属性的对象:
- `id` ,插件 ID
- `version` ,插件版本
- `rootURI` ,指向插件文件的字符串 URL。对于 XPI,这将是 `jar:file:///` URL。该值始终以斜杠结尾,因此您可以附加相对路径来获取与插件捆绑的文件的 URL(例如 `rootURI + 'style.css'` )。
- 表示事件原因的数字,可以根据以下常量进行检查: `APP_STARTUP` 、 `APP_SHUTDOWN` 、 `ADDON_ENABLE` 、 `ADDON_DISABLE` 、 `ADDON_INSTALL` 、 `ADDON_UNINSTALL` 、 `ADDON_UPGRADE` 、 `ADDON_DOWNGRADE`

任何与特定窗口无关的初始化都应由 `startup` 触发,删除应由 `shutdown` 触发。

### 窗口钩子

```js
// Zotero 主窗口加载完毕时调用
function onMainWindowLoad({ window }) {}

// Zotero 主窗口被关闭时调用
function onMainWindowUnload({ window }) {}
```

窗口钩子传递一个参数:

- 具有包含目标窗口的 window 属性的对象

在某些平台上,主窗口可以在 Zotero 会话期间多次打开和关闭,因此任何与窗口相关的活动,例如修改主 UI、添加菜单或绑定快捷方式都必须由 `onMainWindowLoad` 执行以便新的主窗口包含您的更改。

然后,当调用 `onMainWindowUnload` 时,您必须删除对窗口或其中的对象的所有引用,取消任何计时器等,否则每次关闭窗口时都会有造成内存泄漏的风险。添加到窗口的 DOM 元素会在窗口关闭时自动销毁,因此只需删除 `shutdown()` 中的元素即可,可以通过循环遍历所有窗口来完成:

```js
function shutdown() {
var windows = Zotero.getMainWindows();
for (let win of windows) {
win.document.getElementById("make-it-red-stylesheet")?.remove();
}
}
```

(目前仅支持一个主窗口,但有些用户可能会找到打开多个主窗口的方法,这将在未来版本中正式支持。)

::: tip

通常地,在 `startup` 中初始化插件地本地化系统、首选项、兼容性等,在 `onMainWindowLoad` 中初始化与 Zotero UI 有关的组件,如菜单、侧边栏、自定义列等。

:::

## 样例

关于 `bootstrap.js` 的样例,可参考前章提到的插件框架。它将插件的根对象注册到全局变量 `Zotero` 中,在任何引入了 Zotero 的位置均可使用。 或参考 Zutilo 插件。它将插件的根对象注册为一个全局变量。缺陷是在非主窗口内引入插件代码将较为复杂。

- [Zotero-addon-template/bootstrap.js at bootstrap · windingwind/Zotero-addon-template](https://github.com/windingwind/zotero-addon-template/blob/main/addon/bootstrap.js)
- [Zutilo/bootstrap.js at master · wshanks/Zutilo](https://github.com/wshanks/Zutilo/blob/master/addon/bootstrap.js)

下面是以官方示例 `Make It Red` 的 `bootstrap.js`,它在 `startup()` 中通过 `Services.scriptloader.loadSubScript(rootURI + "make-it-red.js");` 将插件脚本载入,在 `make-it-red.js` 中,在 `Zotero` 下定义了一个对象 `MakeItRed`。在 `make-it-red.js` 加载完成后,调用 `MakeItRed` 对象下的方法完成插件初始化。

```js
var MakeItRed;

function log(msg) {
Zotero.debug("Make It Red: " + msg);
}

function install() {
log("Installed 2.0");
}

async function startup({ id, version, rootURI }) {
log("Starting 2.0");

Services.scriptloader.loadSubScript(rootURI + "make-it-red.js");
MakeItRed.init({ id, version, rootURI });
MakeItRed.addToAllWindows();
await MakeItRed.main();
}

function onMainWindowLoad({ window }) {
MakeItRed.addToWindow(window);
}

function onMainWindowUnload({ window }) {
MakeItRed.removeFromWindow(window);
}

function shutdown() {
log("Shutting down 2.0");
MakeItRed.removeFromAllWindows();
MakeItRed = undefined;
}

function uninstall() {
log("Uninstalled 2.0");
}
```

## 参考资料

- [Zotero 7 for developers](https://www.zotero.org/support/dev/zotero_7_for_developers)
- [bootstrapped-extension framework](https://www.devdoc.net/web/developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Bootstrapped_Extensions.html#Bootstrap_entry_points)
69 changes: 69 additions & 0 deletions src/plugin-dev-guide/reference/item.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Zotero 条目

Item(条目)是 Zotero 中的基础数据元素。条目根据类型又可分为普通条目 (regular item),附件 (attachment item),笔记 (note item) 和注释 (annotation item)。Zotero 中,小到一个 PDF 附件中的一条高亮,大到一个集合(collection),都可以抽象为一个条目(Item)。

大多数插件的最终目的就是修改这些条目,例如,添加标签,修改信息,等等。

## 创建条目

```javascript
new Zotero.Item(itemType);
```

## 获取条目

```typescript
declare Zotero.Items.get: (ids: Number | Number[]) => ZoteroItem | ZoteroItem[];
declare Zotero.Items.getByLibraryAndKeyAsync: (
libraryID: Number,
itemKey: String
) => Promise<ZoteroItem>;
declare ZoteroPane.getSelectedItems: () => ZoteroItem[];
```

通过 `Zotero.Items.get` / `getByLibraryAndKeyAsync` 来从 ID 获取条目;
通过 `ZoteroPane.getSelectedItems` 获取当前选中的条目。

```javascript
ZoteroPane.itemsView.getRow(2).ref;
```

## 修改条目

对条目内容进行修改后,请使用 `item.save` / `item.saveTx()`来保存。

```javascript
var item = new Zotero.Item("computerProgram");
item.setType(Zotero.ItemTypes.getID("note"));
```

## PDF 批注

> Zotero 中的批注也是 Item 类型!

```javascript
Zotero.Items.getAll(1).then((i) => i.filter((t) => t.isAnnotation()));
```

注释的属性:

- annotationText:高亮注释的内容
- parentItem:获得 pdf 条目

```javascript
const annotations = Zotero.Items.get(reader.itemID).getAnnotations();
reader.navigate({ annotationKey: annotations[0].key });
```

## 从对话框选择条目

```javascript
let io = { dataIn: null, dataOut: null, deferred: Zotero.Promise.defer() };
window.openDialog(
"chrome://zotero/content/selectItemsDialog.xhtml",
"",
"chrome,dialog=no,centerscreen,resizable=yes",
io
);
io.deferred.promise.then(() => console.debug(io));
```
13 changes: 13 additions & 0 deletions src/plugin-dev-guide/reference/localization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# i18n

`locales/`

::: note Todo

Zotero 7 已全面使用 Fluent 作为本地化系统,请参考以下几个文档:

- [Zotero 7 for developers](https://www.zotero.org/support/dev/zotero_7_for_developers#localization)
- [Fluent for Firefox Developers](https://firefox-source-docs.mozilla.org/l10n/fluent/tutorial.html#markup-localization)
- [Fluent 文档](https://projectfluent.org/)

:::
Loading
Loading