{"id":20438441,"url":"https://github.com/tinymce/tinymce-xpath-annotations-example","last_synced_at":"2025-07-11T15:38:48.029Z","repository":{"id":64012826,"uuid":"144532657","full_name":"tinymce/tinymce-xpath-annotations-example","owner":"tinymce","description":"A reference implementation for integrating xpaths with TinyMCE annotations","archived":false,"fork":false,"pushed_at":"2022-11-30T14:33:51.000Z","size":19,"stargazers_count":2,"open_issues_count":0,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-12T22:37:46.438Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinymce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-13T05:18:09.000Z","updated_at":"2022-11-30T14:33:51.000Z","dependencies_parsed_at":"2022-12-04T12:19:10.512Z","dependency_job_id":null,"html_url":"https://github.com/tinymce/tinymce-xpath-annotations-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tinymce/tinymce-xpath-annotations-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinymce%2Ftinymce-xpath-annotations-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinymce%2Ftinymce-xpath-annotations-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinymce%2Ftinymce-xpath-annotations-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinymce%2Ftinymce-xpath-annotations-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinymce","download_url":"https://codeload.github.com/tinymce/tinymce-xpath-annotations-example/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinymce%2Ftinymce-xpath-annotations-example/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264841967,"owners_count":23671907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T09:11:04.092Z","updated_at":"2025-07-11T15:38:47.967Z","avatar_url":"https://github.com/tinymce.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tinymce-xpath-annnotations-example\n\nA reference implementation for integrating xpaths with TinyMCE annotations\n\n## Description\n\nThe `tinymce-xpath-annotations-example` plugin provides the ability to set and get annotations\nusing XPath selectors. It is based on the annotator API, available\nfrom TinyMCE 4.8.2. The xpath capability is provided by the npm library\n`xpath-range`. The supplied `example.html` file shows how to use the\nmajority of the plugin's capabilities.\n\n## Installation\n\n1. Clone this repo\n2. Run `npm install`\n3. Run `npx grunt webpack`\n\n## Running tests\n\n1. npm run test\n\n## Usage\n\n### Browser Compatibility\n\nAt the moment, the plugin only works on Safari, Chrome, and Firefox. There is no\ncurrent support for Microsoft Edge or Internet Explorer. Microsoft Edge support\nis more challenging than the other modern browsers because its normalization\napproaches are not as compatible with its range APIs. This is highlighted by\nthis fiddle: https://jsfiddle.net/jm2dv5Lw/17/\n\nInternet Explorer support is complicated by its different implementation of various\nAPIs that `xpath-range` relies upon. We tried some polyfills with limited success.\nMore investigation is required.\n\n### Running the example.\n\nThe example requires `tinymce 4.8.2` or higher. It should be listed in your\n`package.json` file. Then:\n\n1. Run `npm install`\n2. Run `npx http-server . \u0026\u003e /dev/null \u0026`\n3. Run `npx grunt`\n\nNavigate to `http://localhost:8080/dist/tinymce-xpath-annotations-example/example.html` (where `8080` is the port `http-server` is using).\n\nThe following sections outline the different parts of the example page:\n\n### Example.html\n\nThe supplied `example.html` file shows the various capabilities of the\n`tinymce-xpath-annotations-example` plugin. It contains:\n\na) a TinyMCE instance, with buttons to manage annotations\nb) a table showing the current annotations present in the content\n\nThe first button in the toolbar is used to add an annotation at the current\ncursor position. The second button performs three actions in sequence:\n\n1. get all the annotations from the content and store them in memory\n2. remove all annotations from the content\n3. five seconds later, restore all the annotations from step (1)\n\nThe table also shows the xpath. As you type in the document, this table should\nchange to show the current xpaths of the annotations. If the cursor is\ninside any annotation, that annotation will be highlighted in the table.\n\n### Understanding the Table\n\nIn the example page, there is a table showing real-time changes to all the annotations in the content. Each annotation\npresent is represented by a single row. A row has three columns:\n\na) a unique identifier (uid)\nb) an xpath\nc) a delete button\n\n#### UID Column\n\nThis uniquely identifies this annotation. It must not conflict with any other annotation. When calling the\n`xpath.add-annotation` command, you must supply the UID. A UID will not change.\n\n#### Xpath Column\n\nThe xpath column shows a possible xpath for locating this particular annotation. The format of the `xpath` is\nvery similar to a DOM range object. We are using the `xpath-range` library to calculate\nthe xpath. Essentially, it is:\n\n```\n{\n  start: XPath selector string,\n  startOffset: number,\n  end: XPath selector string,\n  endOffset: number\n}\n```\n\nThe xpaths calculated will assume no text fragmentation, and will assume that the annotation markers themselves are\nnot present.\n\nNote, the `xpath.annotation-moved` event on editor is fired every time we detect a change in the content. In the example,\nwe use that event to update the XPaths in the table. As you type in the document, you should see the xpaths change where\napplicable.\n\nThe code excerpt is something like this:\n\n```\nvar annotations = editor.plugins['tinymce-xpath-annotations-example'].getAnnotations();\n```\n\nNote, that the `xpath.annotation-moved` event will be fired separately for every annotation that has a new XPath\nlocation. The event will carry information about the UID and the new xpath. However, the example code is just\nretrieving all annotations again to show how that works.\n\n\n#### Delete Column\n\nFor each annotation, there is an 'X' button in the far right column. If you click this button, that is equivalent\nto executing `removeAnnotation(uid)` where uid is the identifier for that row. The annotation will be removed\nfrom the content, and the table in the example will be updated acccordingly.\n\n### APIS\n\nThe APIs are available on the `tinymce-xpath-annotations-example` plugin itself. Specifically, they can be accessed through\n`editor.plugins['tinymce-xpath-annotations-example']`. For example:\n\n```\nvar annotations = editor.plugins['tinymce-xpath-annotations-example'].getAnnotations();\n```\n\nAn explanation of the available APIs is below.\n\n#### getAnnotations: () =\u003e Array AnnotationInfo\n\nThe `getAnnotations` API returns an array of the annotations in the content. The array is ordered\nby the DOM position of the first annotation marker. Each annotation contains the following information:\n\n* uid: the unique identifier for the annotation\n* original: the first annotation marker in the content. We will probably stop including this soon. Consider\nit deprecated.\n* xpath: the xpath location of the entire annotation range in the format specified by the XPath section above\n\n#### removeAnnotation: (uid: string) =\u003e void\n\nThe `removeAnnotation` API removes a specified annotation from the content. The annotation is specified\nvia its unique identifier (uid). Any annotation markers associated with that anontation will also be removed.\n\n#### removeAllAnnotation: () =\u003e void\n\nThe `removeAllAnnotations` API removes every annotation from the content. All associated annotation markers\nwill also be removed.\n\n#### setAnnotations: (annotations: Array AnnotationInfo) =\u003e void\n\nThe `setAnnotations` API takes an array of ordered annotations (by DOM position), and applies them to the\ncontent. We currently don't handle if it can't resolve the xpath in the content. This would be a likely\nimprovement in the future.\n\n### Commands\n\nThe `tinymce-xpath-annotations-example` plugin also adds a single command to TinyMCE: `xpath.add-annotation`\n\n#### xpath.add-annotation\n\nThe `xpath.add-annotation` command creates a annotation with the specified `uid` **at the current cursor**.\nIf the selection is collapsed, it will try and grab the nearest 'word' first. This API differs from the other\nAPIs as it directly interacts with the user's current selection.\n\nThe format of the command is this:\n\n```\neditor.execComand('xpath.add-annotation', {\n  uid: 'this-is-the-identifier-I-want-to-use'\n});\n```\n\nThis API is built on the experimental Annotator API. You can pass through additional things as well as\nuid if you want, but at the moment, they won't do anything.\n\n### Events\n\nThe `tinymce-xpath-annotations-example` plugin adds several events to `editor`. These are:\n\n* xpath.annotation-moved\n* xpath.no-annotation-selected\n* xpath.annotation-selected\n\nNote, these event names are all expected to change in the future.\n\n#### xpath.annotation-moved\n\nThis event is fired when the xpath of a particular annotation has changed. The event will be\npassed the uid of the annotation, and its new xpath.\n\n```\ned.on('xpath.annotation-moved', function (data) {\n  console.log('Annotation: ' + data.uid, 'New xpath', data.xpath);\n})\n```\n\n#### xpath.no-annotation-selected\n\nThis event is fired when the user moves the cursor to a location in the content that is\nnot within a xpath annotation. No data is passed to it.\n\n```\neditor.on('xpath.no-annotation-selected', function () {\n  console.log('The cursor is not in an annotation');\n});\n```\n\n#### xpath.annotation-selected\n\nThis event is fired when the user moves the cursor to a location that **is** within\na xpath annotation. It is passed data containing the annotation uid.\n\n```\neditor.on('xpath.annotation-selected', function (data) {\n  console.log('The cursor in in annotation: ' + data.uid);\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinymce%2Ftinymce-xpath-annotations-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinymce%2Ftinymce-xpath-annotations-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinymce%2Ftinymce-xpath-annotations-example/lists"}