blob: 7cbc8da44a740f674ea58fc9692781808b2d5b39 [file] [log] [blame]
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#" class="default">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
<title>Apache Annotator (incubating)</title>
<meta property="og:title" content="Apache Annotator" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://annotator.apache.org/" />
<meta property="og:image:url" content="https://annotator.apache.org/images/annotator-logo.svg" />
<meta property="og:image:alt" content="Apache Annotator (incubating) logo" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="alternate" title="DOAP" href="doap.rdf" type="application/rdf+xml" />
<link rel="stylesheet" href="//semantic-ui.com/dist/semantic.min.css" />
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/prism-themes/themes/prism-vs.css" />
<style>
html {
font-size: 17px;
}
p, pre[class*="language-"] {
margin: .8em 0 1.25em;
}
</style>
</head>
<body>
<div class="ui borderless stackable top attached main menu">
<div class="ui container">
<a class="item" href="/" style="color: rgba(0,0,0,.87);">
<img class="ui small image" src="/images/annotator-logo.svg" alt="Apache Annotator (incubating)" />
</a>
<nav class="right menu">
<a class="item" href="/">Home</a>
<a class="item" href="/demo/"><span class="ui positive button">Demo!</span></a>
<a class="active item" href="/docs/">Documentation</a>
<a class="item" rel="external" href="https://github.com/apache/incubator-annotator">Code&nbsp;<i class="small external icon"></i></a>
<a class="item" rel="external" href="https://github.com/apache/incubator-annotator/issues">Issue tracker&nbsp;<i class="small external icon"></i></a>
</nav>
</div>
</div>
<div class="ui basic segment container">
<nav class="ui secondary stackable pointing menu" style="justify-content: center;">
<span class="item" style="background: #ff08">This documentation is for v0.2 (in development)</span>
<span class="item"></span>
<a href="/docs/" class="item">Overview</a>
<a href="/docs/getting-started/" class="active item">Getting Started</a>
<a href="/docs/develop/" class="item">Develop</a>
<a href="/docs/api/" class="item">API reference</a>
</nav>
<main class="ui basic segment container">
<h1 style="margin-bottom: 2rem">Getting Started</h1>
<div class="ui mobile reversed stackable grid">
<div class="twelve wide column">
<h2 id="install-via-npm">Install via NPM</h2>
<p>Currently we only support installation through NPM packages. You will need to use a bundler (such as <a href="https://webpack.js.org/">webpack</a>) to use the modules in a web browser.</p>
<p>The project is made up of multiple modules. Each module is <a href="https://www.npmjs.com/org/apache-annotator">available on the NPM registry</a> as individual packages in the <code>@apache-annotator</code> scope, and all of them together in the <a href="https://www.npmjs.com/package/apache-annotator"><code>apache-annotator</code></a> ‘meta-package’. You can install either and then import packages in your code as <code>@apache-annotator/package</code> or <code>apache-annotator/package</code>, respectively.</p>
<p>For example, for the latest official release:</p>
<pre class="language-shell"><code class="language-shell">$ <span class="token function">yarn</span> <span class="token function">add</span> @apache-annotator/dom</code></pre>
<p>For the latest development version, get the <code>dev</code> tag. For example:</p>
<pre class="language-shell"><code class="language-shell">$ <span class="token function">yarn</span> <span class="token function">add</span> @apache-annotator/dom@dev</code></pre>
<p>And in your code import what you need:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> highlightText <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@apache-annotator/dom'</span><span class="token punctuation">;</span></code></pre>
<h2 id="install-from-source">Install from source</h2>
<p>See <a href="/docs/develop/">Develop</a>.</p>
<h2 id="usage-example%3A-a-text-quote-highlighter">Usage example: a text quote highlighter</h2>
<p>A typical goal of web annotation is to let users highlight a phrase of text in a web page, and perhaps add a note to it. The example code below creates such a highlighter (without note-taking functionality).</p>
<p>First, we define the way to describe the user’s selection as a <a href="https://www.w3.org/TR/2017/REC-annotation-model-20170223/#text-quote-selector">TextQuoteSelector</a>.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> describeTextQuote <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@apache-annotator/dom'</span><span class="token punctuation">;</span><br><br><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">describeCurrentSelection</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> userSelection <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">getSelection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?.</span><span class="token function">getRangeAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>userSelection <span class="token operator">||</span> userSelection<span class="token punctuation">.</span>isCollapsed<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span><br> <span class="token keyword">return</span> <span class="token function">describeTextQuote</span><span class="token punctuation">(</span>userSelection<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>If the user had selected the word <em>“ipsum”</em> in the befamed <em>“Lorem ipsum dolor amet …”</em>, the return value of describeCurrentSelection() might resolve to this:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br> type<span class="token operator">:</span> 'TextQuoteSelector'<span class="token punctuation">,</span><br> exact<span class="token operator">:</span> 'ipsum'<span class="token punctuation">,</span><br> prefix<span class="token operator">:</span> 'Lorem '<span class="token punctuation">,</span><br> suffix<span class="token operator">:</span> ' dolor'<br><span class="token punctuation">}</span></code></pre>
<p>The <em>prefix</em> and <em>suffix</em> attributes are there to know which of multiple occurrences of <em>“ipsum”</em> the Selector points to. They will include just enough surrounding words to make the selector unambiguous.</p>
<p>Next, we define roughly the inverse function: given a TextQuoteSelector, we highlight the text it points to.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> createTextQuoteSelectorMatcher<span class="token punctuation">,</span> highlightText <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@apache-annotator/dom'</span><span class="token punctuation">;</span><br><br><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">highlightSelectorTarget</span><span class="token punctuation">(</span><span class="token parameter">textQuoteSelector</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> matches <span class="token operator">=</span> <span class="token function">createTextQuoteSelectorMatcher</span><span class="token punctuation">(</span>textQuoteSelector<span class="token punctuation">)</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token comment">// Modifying the DOM while searching can mess up; see issue #112.</span><br> <span class="token comment">// Therefore, we first collect all matches before highlighting them.</span><br> <span class="token keyword">const</span> matchList <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br> <span class="token keyword">for</span> <span class="token keyword">await</span> <span class="token punctuation">(</span><span class="token keyword">const</span> match <span class="token keyword">of</span> matches<span class="token punctuation">)</span> matchList<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>match<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> match <span class="token keyword">of</span> matchList<span class="token punctuation">)</span> <span class="token function">highlightText</span><span class="token punctuation">(</span>match<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>As the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of"><code>for await … of</code></a> statement suggests, the matcher does not return just one match, but a stream (an async iterable) of matches. This is because it cannot be certain that a selector only has a single match (even when it includes a prefix &amp; suffix, perhaps the document changed!).</p>
<p>We could use the functions defined above in many ways; keeping highlighted quotes in local storage, or in one’s bookmarks, or sharing them with others, and so on. For this example, we keep it simple and highlight each selection upon release of the mouse button; and store the selector to make it appear again after a page reload.</p>
<pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'mouseup'</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> selector <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">describeCurrentSelection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">const</span> existingSelectors <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>localStorage<span class="token punctuation">[</span>document<span class="token punctuation">.</span><span class="token constant">URL</span><span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token string">'[]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> localStorage<span class="token punctuation">[</span>document<span class="token punctuation">.</span><span class="token constant">URL</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>existingSelectors<span class="token punctuation">,</span> selector<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">await</span> <span class="token function">highlightSelectorTarget</span><span class="token punctuation">(</span>selector<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token comment">// Highlight the last selection that was stored, if any.</span><br><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">highlightStoredSelectors</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>localStorage<span class="token punctuation">[</span>document<span class="token punctuation">.</span><span class="token constant">URL</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> selectors <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>localStorage<span class="token punctuation">[</span>document<span class="token punctuation">.</span><span class="token constant">URL</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> selector <span class="token keyword">of</span> selectors<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">await</span> <span class="token function">highlightSelectorTarget</span><span class="token punctuation">(</span>selector<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><span class="token function">highlightStoredSelectors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>To see similar pieces of code in action, have a look at <a href="/demo/">the demo</a>.</p>
</div>
<aside class="ui four wide column">
<style>
.toc ol {
list-style-type: none;
padding-left: 1em;
}
.toc ol li {
margin: 0.25em 0;
}
</style>
<h1 class="ui small dividing header" style="margin: 0;">Contents</h1>
<nav class="toc">
<ol><li><a href="#install-via-npm">Install via NPM</a></li><li><a href="#install-from-source">Install from source</a></li><li><a href="#usage-example%3A-a-text-quote-highlighter">Usage example: a text quote highlighter</a></li></ol></nav>
</aside>
</div>
</main>
</div>
<footer class="ui bottom attached segment">
<div class="ui container">
<div class="ui equal height divided stackable grid">
<div class="four wide column">
<a class="ui left floated medium image" href="https://apache.org/" target="_blank">
<img src="https://incubator.apache.org/images/incubator_feather_egg_logo_sm.png" alt="logo of the Apache Incubator" />
</a>
<p>
<em>Copyright © 2016-2018 The Apache Software Foundation, Licensed under
the <a href="https://www.apache.org/licenses/LICENSE-2.0" rel="license external">Apache License, Version 2.0</a>.
|
<a rel="external" href="https://www.apache.org/foundation/policies/privacy">Privacy Policy</a>
</em>
</p>
</div>
<div class="nine wide column">
<p>
<em>Apache Annotator is an effort undergoing incubation at <a target="_blank" href="https://apache.org/">The Apache Software Foundation (ASF)</a> sponsored by the Apache Incubator PMC. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.</em></p>
<p><em>Apache®, the names of Apache projects, and the feather logo are either <a rel="external" href="https://www.apache.org/foundation/marks/list/">registered trademarks or trademarks</a> of the Apache Software Foundation in the United States and/or other countries.</em></p>
</div>
<div class="three wide column">
<h4 class="header">The <abbr title="Apache Software Foundation">ASF</abbr></h4>
<div class="ui link list">
<a class="item" rel="external" href="https://incubator.apache.org/">Apache Incubator</a>
<a class="item" rel="external" href="https://www.apache.org/">About the ASF</a>
<a class="item" rel="external" href="https://www.apache.org/events/current-event">Events</a>
<a class="item" rel="external" href="https://www.apache.org/foundation/thanks.html">Thanks</a>
<a class="item" rel="external" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a>
<a class="item" rel="external" href="https://www.apache.org/security/">Security</a>
<a class="item" rel="external" href="https://www.apache.org/licenses/">License</a>
</div>
</div>
</div>
</div>
</footer>
</body>
</html>