xref: /plugin/annotations/README.md (revision 43d2073c014d8cf78420fa47c6568a01e7249305)
1# Annotations Plugin for DokuWiki
2
3Word- and sentence-level annotations on wiki pages, stored out-of-band with threaded replies. Inspired by [Hypothes.is](https://hypothes.is/) and [ep_comments_page](https://github.com/ether/ep_comments_page).
4
5## Features
6
7- **Text-quote anchoring** — select any word or sentence; the annotation is tied to the exact quoted text plus surrounding context, so it survives minor edits.
8- **Threaded replies** — any reader can reply to an existing annotation.
9- **Open / Resolved status** — mark discussions closed; resolved annotations turn green.
10- **Gutter markers** — small icons in the left margin show at a glance where annotations live.
11- **Orphan detection** — when the annotated text is removed from the page, the annotation is flagged as orphaned and accessible via the counter. Admins can bulk-delete orphans.
12- **Per-user toggle** — users can turn the annotation overlay on or off via the usersettings plugin.
13- **No page revisions** — annotations are stored in a separate JSON file per page; the wiki changelog is never touched.
14
15## Requirements
16
17- DokuWiki Librarian 2025-05-14b (or compatible release)
18- PHP 8.0 or later with `mbstring` extension
19- [usersettings plugin](https://github.com/tracker-user/dokuwiki-usersettings) *(optional — adds per-user on/off toggle)*
20
21## Installation
22
231. Copy the `annotations/` directory into `{DokuWiki}/lib/plugins/`.
242. If you want the per-user toggle, install the usersettings plugin too.
253. No additional configuration is required.
26
27## Usage
28
29### Reading annotations
30
31Annotated text is highlighted in **amber** (open) or **green** (resolved). Click any highlight to open the thread panel inline below that paragraph.
32
33The counter bar above the page content shows the total number of annotations. If there are orphaned annotations (text was deleted), a clickable "N orphaned" link opens a drawer at the bottom of the page.
34
35### Creating an annotation
36
371. Select any text on the page.
382. Click the **Annotate** button that appears.
393. Type your comment and click **Annotate** to save.
40
41> Requires: logged in + at least read access on the page.
42
43### Replying
44
45Open the thread panel for any annotation and use the **Reply** field at the bottom.
46
47### Resolving / Reopening
48
49Click **Resolve** on any annotation to mark the discussion closed. Any reader can resolve or reopen.
50
51### Editing and deleting
52
53- Authors can edit or delete their own annotations and replies.
54- Admins can edit or delete any annotation or reply.
55
56### Admin: bulk operations
57
58Admins see two extra buttons in the counter bar:
59
60| Button | Effect |
61|--------|--------|
62| **Clear resolved** | Permanently deletes all resolved annotations on the page |
63| **Clear orphaned** | Server-side re-check, then permanently deletes orphaned annotations |
64
65### Disabling the overlay
66
67Via **User Preferences** (usersettings plugin) → uncheck **Enable annotations**. The overlay is hidden for that user; annotations are still stored.
68
69## Permission model
70
71| Action | Who |
72|--------|-----|
73| Create annotation / reply | Logged in + AUTH_READ on page |
74| Resolve / Reopen | Logged in + AUTH_READ on page |
75| Edit / delete own annotation or reply | The author |
76| Edit / delete any annotation or reply | Admins |
77| Clear resolved / Clear orphaned (per-page) | Admins |
78
79Note: **edit access is not required** to create an annotation. Groups whose page edit access is blocked can still annotate.
80
81## Storage
82
83Each page's annotations are stored at:
84
85```
86{data}/meta/{namespace}/{page}.annotations
87```
88
89Format (JSON):
90
91```json
92{
93  "version": 1,
94  "annotations": [
95    {
96      "id": "a1b2c3d4e5f6g7h8",
97      "anchor": {
98        "exact": "lossless source",
99        "prefix": "must use a ",
100        "suffix": ". Transcodes",
101        "start": 21
102      },
103      "author": "alice",
104      "created": 1716336000,
105      "modified": 1716336000,
106      "body": "Does this cover remuxes?",
107      "status": "open",
108      "resolved_by": "",
109      "resolved_at": 0,
110      "replies": [
111        {
112          "id": "x1y2z3a4b5c6d7e8",
113          "author": "bob",
114          "created": 1716336100,
115          "modified": 1716336100,
116          "body": "Yes, remuxes count."
117        }
118      ]
119    }
120  ]
121}
122```
123
124## AJAX API
125
126All actions go to `/lib/exe/ajax.php?call=annotations`.
127
128| Action | Method | Token | Required fields |
129|--------|--------|-------|-----------------|
130| `load` | GET | — | `id` |
131| `create` | POST | ✓ | `id`, `anchor`, `body` |
132| `reply` | POST | ✓ | `id`, `annId`, `body` |
133| `edit_annotation` | POST | ✓ | `id`, `annId`, `body` |
134| `edit_reply` | POST | ✓ | `id`, `annId`, `replyId`, `body` |
135| `delete_annotation` | POST | ✓ | `id`, `annId` |
136| `delete_reply` | POST | ✓ | `id`, `annId`, `replyId` |
137| `resolve` | POST | ✓ | `id`, `annId`, `status` |
138| `clear_resolved` | POST | ✓ | `id` |
139| `clear_orphaned` | POST | ✓ | `id` |
140
141POST bodies are `application/json`. All responses: `{"success": true, ...}` or `{"success": false, "error": "..."}`.
142
143## Files
144
145```
146annotations/
147├── plugin.info.txt     Plugin manifest
148├── helper.php          Storage, CRUD, orphan detection, permission rules
149├── action.php          Event hooks, AJAX endpoint
150├── script.js           Front-end: selection, anchoring, highlights, panels, AJAX
151├── style.css           Theme-compatible CSS (uses DokuWiki __token__ vars)
152├── README.md           This file
153└── lang/
154    └── en/
155        └── lang.php    English strings
156```
157
158## Browser compatibility
159
160The JavaScript targets Firefox 78 ESR and later (no `#private` fields, no `??=`, no `<dialog>`, no `Array.at`). Should work in all modern browsers.
161
162## License
163
164GPL 2, matching DokuWiki.
165