53 Matching Annotations
  1. Sep 2023
    1. Undocumented Hypothes.is Badge API (used by Chrome extension):

      ```python """ Return the number of public annotations on a given page.

      This is for the number that's displayed on the Chrome extension's badge.

      Certain pages are blocklisted so that the badge never shows a number on those pages. The Chrome extension is oblivious to this, we just tell it that there are 0 annotations. """ ```

      https://hypothes.is/api/badge?uri=* same as https://hypothes.is/api/search?limit=0&uri=*.

    1. Add a new, undocumented separate_replies=True option to the search API. If separate_replies=True option is _not_ given to the search API, then it reverts to its previous behaviour: _do_ include replies in the "rows" list returned. This is the same behaviour that the search API had befor: it returns both top-level annotations and replies in the one "rows" list, but without any guarantee that if some annotations/replies from a given thread are in the list then all annotations/replies from that thread will be in it. If separate_replies=True _is_ given then the API follows the new behaviour: "rows" contains top-level annotations only, and a separate "replies" list containing all replies to the annotations in rows is also inserted into the result.
  2. Jun 2023
  3. Apr 2023
  4. Feb 2023
  5. Nov 2022
  6. Aug 2022
    1. In line with the much-requested (and long-longed-for) feature of highlights in different colors (an exhaustive list given in #198), I would like to suggest allowing (automatic) coloring of highlights based on tags with designated patterns (like code:critiques, code:non-ergodicity in psychology, etc.), or alternatively, all tags (i.e., without specific patterns).
    1. ```js / Adapted from: https://github.com/openannotation/annotator/blob/v1.2.x/src/plugin/document.coffee Annotator v1.2.10 https://github.com/openannotation/annotator Copyright 2015, the Annotator project contributors. Dual licensed under the MIT and GPLv3 licenses. https://github.com/openannotation/annotator/blob/master/LICENSE /

      /* * nb. The DocumentMetadata type is renamed to avoid a conflict with the * DocumentMetadata class below. * * @typedef {import('../../types/annotator').DocumentMetadata} Metadata /

      import { normalizeURI } from '../util/url';

      /* * @typedef Link * @prop {string} link.href * @prop {string} [link.rel] * @prop {string} [link.type] /

      /* * Extension of the Metadata type with non-optional fields for dc, eprints etc. * * @typedef HTMLDocumentMetadata * @prop {string} title * @prop {Link[]} link * @prop {Record<string, string[]>} dc * @prop {Record<string, string[]>} eprints * @prop {Record<string, string[]>} facebook * @prop {Record<string, string[]>} highwire * @prop {Record<string, string[]>} prism * @prop {Record<string, string[]>} twitter * @prop {string} [favicon] * @prop {string} [documentFingerprint] /

      / * HTMLMetadata reads metadata/links from the current HTML document. */ export class HTMLMetadata { / * @param {object} [options] * @param {Document} [options.document] */ constructor(options = {}) { this.document = options.document || document; }

      /* * Returns the primary URI for the document being annotated * * @return {string} / uri() { let uri = decodeURIComponent(this._getDocumentHref());

      // Use the `link[rel=canonical]` element's href as the URL if present.
      const links = this._getLinks();
      for (let link of links) {
        if (link.rel === 'canonical') {
          uri = link.href;
        }
      }
      
      return uri;
      

      }

      / * Return metadata for the current page. * * @return {HTMLDocumentMetadata} */ getDocumentMetadata() { / @type {HTMLDocumentMetadata} */ const metadata = { title: document.title, link: [],

        dc: this._getMetaTags('name', 'dc.'),
        eprints: this._getMetaTags('name', 'eprints.'),
        facebook: this._getMetaTags('property', 'og:'),
        highwire: this._getMetaTags('name', 'citation_'),
        prism: this._getMetaTags('name', 'prism.'),
        twitter: this._getMetaTags('name', 'twitter:'),
      };
      
      const favicon = this._getFavicon();
      if (favicon) {
        metadata.favicon = favicon;
      }
      
      metadata.title = this._getTitle(metadata);
      metadata.link = this._getLinks(metadata);
      
      const dcLink = metadata.link.find(link => link.href.startsWith('urn:x-dc'));
      if (dcLink) {
        metadata.documentFingerprint = dcLink.href;
      }
      
      return metadata;
      

      }

      / * Return an array of all the content values of <meta> tags on the page * where the value of the attribute begins with <prefix>. * * @param {string} attribute * @param {string} prefix - it is interpreted as a regex * @return {Record<string,string[]>} */ _getMetaTags(attribute, prefix) { / @type {Record<string,string[]>} */ const tags = {}; for (let meta of Array.from(this.document.querySelectorAll('meta'))) { const name = meta.getAttribute(attribute); const { content } = meta; if (name && content) { const match = name.match(RegExp(^${prefix}(.+)$, 'i')); if (match) { const key = match[1].toLowerCase(); if (tags[key]) { tags[key].push(content); } else { tags[key] = [content]; } } } } return tags; }

      /* @param {HTMLDocumentMetadata} metadata / _getTitle(metadata) { if (metadata.highwire.title) { return metadata.highwire.title[0]; } else if (metadata.eprints.title) { return metadata.eprints.title[0]; } else if (metadata.prism.title) { return metadata.prism.title[0]; } else if (metadata.facebook.title) { return metadata.facebook.title[0]; } else if (metadata.twitter.title) { return metadata.twitter.title[0]; } else if (metadata.dc.title) { return metadata.dc.title[0]; } else { return this.document.title; } }

      / * Get document URIs from <link> and <meta> elements on the page. * * @param {Pick<HTMLDocumentMetadata, 'highwire'|'dc'>} [metadata] - * Dublin Core and Highwire metadata parsed from <meta> tags. * @return {Link[]} */ _getLinks(metadata = { dc: {}, highwire: {} }) { / @type {Link[]} */ const links = [{ href: this._getDocumentHref() }];

      // Extract links from `<link>` tags with certain `rel` values.
      const linkElements = Array.from(this.document.querySelectorAll('link'));
      for (let link of linkElements) {
        if (
          !['alternate', 'canonical', 'bookmark', 'shortlink'].includes(link.rel)
        ) {
          continue;
        }
      
        if (link.rel === 'alternate') {
          // Ignore RSS feed links.
          if (link.type && link.type.match(/^application\/(rss|atom)\+xml/)) {
            continue;
          }
          // Ignore alternate languages.
          if (link.hreflang) {
            continue;
          }
        }
      
        try {
          const href = this._absoluteUrl(link.href);
          links.push({ href, rel: link.rel, type: link.type });
        } catch (e) {
          // Ignore URIs which cannot be parsed.
        }
      }
      
      // Look for links in scholar metadata
      for (let name of Object.keys(metadata.highwire)) {
        const values = metadata.highwire[name];
        if (name === 'pdf_url') {
          for (let url of values) {
            try {
              links.push({
                href: this._absoluteUrl(url),
                type: 'application/pdf',
              });
            } catch (e) {
              // Ignore URIs which cannot be parsed.
            }
          }
        }
      
        // Kind of a hack to express DOI identifiers as links but it's a
        // convenient place to look them up later, and somewhat sane since
        // they don't have a type.
        if (name === 'doi') {
          for (let doi of values) {
            if (doi.slice(0, 4) !== 'doi:') {
              doi = `doi:${doi}`;
            }
            links.push({ href: doi });
          }
        }
      }
      
      // Look for links in Dublin Core data
      for (let name of Object.keys(metadata.dc)) {
        const values = metadata.dc[name];
        if (name === 'identifier') {
          for (let id of values) {
            if (id.slice(0, 4) === 'doi:') {
              links.push({ href: id });
            }
          }
        }
      }
      
      // Look for a link to identify the resource in Dublin Core metadata
      const dcRelationValues = metadata.dc['relation.ispartof'];
      const dcIdentifierValues = metadata.dc.identifier;
      if (dcRelationValues && dcIdentifierValues) {
        const dcUrnRelationComponent =
          dcRelationValues[dcRelationValues.length - 1];
        const dcUrnIdentifierComponent =
          dcIdentifierValues[dcIdentifierValues.length - 1];
        const dcUrn =
          'urn:x-dc:' +
          encodeURIComponent(dcUrnRelationComponent) +
          '/' +
          encodeURIComponent(dcUrnIdentifierComponent);
        links.push({ href: dcUrn });
      }
      
      return links;
      

      }

      _getFavicon() { let favicon = null; for (let link of Array.from(this.document.querySelectorAll('link'))) { if (['shortcut icon', 'icon'].includes(link.rel)) { try { favicon = this._absoluteUrl(link.href); } catch (e) { // Ignore URIs which cannot be parsed. } } } return favicon; }

      /* * Convert a possibly relative URI to an absolute one. This will throw an * exception if the URL cannot be parsed. * * @param {string} url / _absoluteUrl(url) { return normalizeURI(url, this.document.baseURI); }

      // Get the true URI record when it's masked via a different protocol. // This happens when an href is set with a uri using the 'blob:' protocol // but the document can set a different uri through a <base> tag. _getDocumentHref() { const { href } = this.document.location; const allowedSchemes = ['http:', 'https:', 'file:'];

      // Use the current document location if it has a recognized scheme.
      const scheme = new URL(href).protocol;
      if (allowedSchemes.includes(scheme)) {
        return href;
      }
      
      // Otherwise, try using the location specified by the <base> element.
      if (
        this.document.baseURI &&
        allowedSchemes.includes(new URL(this.document.baseURI).protocol)
      ) {
        return this.document.baseURI;
      }
      
      // Fall back to returning the document URI, even though the scheme is not
      // in the allowed list.
      return href;
      

      } } ```

    1. yaml definitions: Annotation: type: object required: - user - uri properties: id: type: string description: Unique ID for this Annotation. uri: type: string description: URI which is the target of this Annotation. target: type: array items: - type: object properties: scope: type: array items: - type: string selector: type: array items: - type: object properties: type: description: Type of Selector--see Web Annotation Data Model. type: string source: type: string user: type: string description: User URI in the form of an `acct` prefixed URI. document: type: object description: Target document metadata schema: $ref: '#/definitions/DocumentMetadata' permissions: type: object description: Permissions for this Annotation. created: type: string format: date-time updated: type: string format: date-time AnnotationList: type: object properties: total: type: number rows: type: array items: $ref: '#/definitions/Annotation' DocumentMetadata: type: object properties: eprints: type: object title: type: string twitter: type: object properties: image:src: type: array items: type: string title: type: array items: type: string description: type: array items: type: string card: type: array items: type: string site: type: array items: type: string dc: type: object favicon: type: string prism: type: object highwire: type: object link: type: array items: type: object properties: href: type: string facebook: type: object properties: site_name: type: array items: type: string description: type: array items: type: string title: type: array items: type: string url: type: array items: type: string image: type: array items: type: string type: type: array items: type: string

  7. Jun 2022
  8. May 2022
    1. The new lines you mention really are present in the text content of the element. HTML tags are not being replaced by new lines, they just get omitted entirely. If you look at the textContent property of the <p> element you selected in the browser console, and you'll see the same new lines. Also if you select the text and run window.getSelection().getRangeAt(0).toString() in the browser console you'll see the same new lines. In summary, this is working as it is currently expected to. What I think may have been surprising here is that the captured text is not the same as what would be copied to the clipboard. When copying to the clipboard, new lines in the source get replaced with spaces, and <br> tags get converted to new lines. Browser specifications distinguish the original text content of HTML "in the source" as returned by element.textContent from the text content "as rendered" returned by element.innerText. Hypothesis has always captured quotes from and searched for quotes in the "source" text content rather than the "rendered" text. This behavior causes issues with line breaks as well. It might make sense for us to look at capturing the rendered text (as copied to the clipboard) rather than the source text in future. We'd need to be careful to handle all the places where this distinction comes up, and also make sure that all existing annotations anchor properly. Also we should talk to other parties interested in the Web Annotations specifications to discuss how this impacts interoperability.
      What I think may have been surprising here is that the captured text is not the same as what would be copied to the clipboard. When <mark>copying to the clipboard, <mark style="background-color: #8000314f">new lines in the source</mark> get <mark style="background-color:#00800030">replaced with spaces</mark>, and <br> tags get converted to new lines</mark>. </br> <mark>Browser specifications distinguish <mark style="background-color: #00800036">the original text content of HTML "in the source"</mark> as returned by <mark style="background-color: #00800036"/>element.textContent</mark> from <mark style="background-color: #ffa500a1">the text content "as rendered" returned by element.innerText.</mark></mark> Hypothesis has always captured quotes from and searched for quotes in the "source" text content rather than the "rendered" text.
    1. <details open> <summary>
      Nanotate Annotations Samples
      </summary> ```json [ { "id":"d5JrdABbEeuatj9X3vvoXw", "authority":"__world__", "url":"https://protocolexchange.researchsquare.com/article/pex-1069/v1", "created":"2020-09-27T00:50:41.265044+00:00", "updated":"2020-09-27T00:50:41.265044+00:00", "title":[ "Sample preparation and imaging procedures for fast and multiplexed superresolution microscopy with DNA-PAINT-ERS" ], "refs":[ ], "isReply":false, "isPagenote":false, "user":"acct:miguel.ruano@hypothes.is", "displayName":null, "text":"", "prefix":"for 10 minutes. Wash with PBS3. ", "exact":"Add imaging buffer with desired ratios of Buffer C (500 mM), ethylene carbonate, and IS-CF660R at 1-2 nM final concentration. The exact concentration of IS may need to be adjusted depending on the target and based on the imaging kinetics.", "suffix":"", "start":15158, "end":15396, "tags":[ "step" ], "group":"__world__", "ontologies":[ ] }, { "id":"FrhgjABcEeu5B4dnXgvb_A", "authority":"__world__", "url":"https://protocolexchange.researchsquare.com/article/pex-1069/v1", "created":"2020-09-27T00:55:08.276888+00:00", "updated":"2020-10-05T14:15:00.764415+00:00", "title":[ "Sample preparation and imaging procedures for fast and multiplexed superresolution microscopy with DNA-PAINT-ERS" ], "refs":[ ], "isReply":false, "isPagenote":false, "user":"acct:miguel.ruano@hypothes.is", "displayName":null, "text":"my other text modificate", "prefix":"ed ratios of Buffer C (500 mM), ", "exact":"ethylene carbonate", "suffix":"", "start":15219, "end":15237, "tags":[ "reagent" ], "group":"__world__", "ontologies":[ "CHEBI" ], "settings":{ "bio_annotations":[ "" ] } }, { "id":"7Z1sugBbEeu9_wtvk1iAjw", "authority":"__world__", "url":"https://protocolexchange.researchsquare.com/article/pex-1069/v1", "created":"2020-09-27T00:53:59.317703+00:00", "updated":"2020-09-30T00:39:50.822216+00:00", "title":[ "Sample preparation and imaging procedures for fast and multiplexed superresolution microscopy with DNA-PAINT-ERS" ], "refs":[ ], "isReply":false, "isPagenote":false, "user":"acct:miguel.ruano@hypothes.is", "displayName":null, "text":"", "prefix":"10 minutes. Wash with PBS3. Add ", "exact":"imaging buffer", "suffix":"", "start":15162, "end":15176, "tags":[ "reagent" ], "group":"__world__", "ontologies":[ "CHEBI" ], "settings":{ "bio_annotations":[ "http://purl.obolibrary.org/obo/CHEBI_35225" ] } } ] </summary>
  9. Apr 2022
  10. Mar 2022
  11. Feb 2022
  12. Jan 2022
    1. Here’s an even more magical trick. Download that PDF to your file system, load it into a third tab, and annotate again. Now you’ll see all three annotations in all three tabs!

      Since Hypothesis doesn’t know that the local copy of the PDF came from http://journals.plos.org/plosone/article/file?id=10.1371/journal.pone.0168597&type=printable, or that it’s related to http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0168597, how is that possible?

      The answer is that the PDF standard defines a unique identifier, or “fingerprint,” that authoring tools encode into the PDFs they create. When you use the Hypothesis client to annotate web-hosted PDF, it captures the fingerprint and sends it to the server.

    2. It was already the case that you could search Hypothesis for the DOI, like so:

    3. First, here’s a magic trick you might not realize Hypothesis has up its sleeve. Consider this PLOS One article. Annotate it in one tab, then open a second tab and annotate the PDF version there. You’ll see both annotations in both tabs. How is that possible?

      The answer is that when scholarly publishers provide HTML versions of articles, they typically include metadata that points to PDF versions of the same articles. Here’s one way that happens:

      <meta name=”citation_pdf_url” content=”http://journals.plos.org/plosone/article/file?id=10.1371/journal.pone.0168597&type=printable”>
      

      Hypothesis remembers the correspondence between the HTML and PDF versions, and coalesces annotations across them.

  13. Dec 2021
    1. {
        "@context": {
          "oa": "http://www.w3.org/ns/oa#",
          "dc": "http://purl.org/dc/elements/1.1/",
          "dcterms": "http://purl.org/dc/terms/",
          "dctypes": "http://purl.org/dc/dcmitype/",
          "foaf": "http://xmlns.com/foaf/0.1/",
          "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
          "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
          "skos": "http://www.w3.org/2004/02/skos/core#",
          "text": {
            "@id": "oa:hasBody"
          },
          "target": {
            "@type": "@id",
            "@id": "oa:hasTarget"
          },
          "source": {
            "@type": "@id",
            "@id": "oa:hasSource"
          },
          "selector": {
            "@type": "@id",
            "@id": "oa:hasSelector"
          },
          "state": {
            "@type": "@id",
            "@id": "oa:hasState"
          },
          "scope": {
            "@type": "@id",
            "@id": "oa:hasScope"
          },
          "user": {
            "@type": "@id",
            "@id": "oa:annotatedBy"
          },
          "serializedBy": {
            "@type": "@id",
            "@id": "oa:serializedBy"
          },
          "motivation": {
            "@type": "@id",
            "@id": "oa:motivatedBy"
          },
          "stylesheet": {
            "@type": "@id",
            "@id": "oa:styledBy"
          },
          "cached": {
            "@type": "@id",
            "@id": "oa:cachedSource"
          },
          "conformsTo": {
            "@type": "@id",
            "@id": "dcterms:conformsTo"
          },
          "members": {
            "@type": "@id",
            "@id": "oa:membershipList",
            "@container": "@list"
          },
          "item": {
            "@type": "@id",
            "@id": "oa:item"
          },
          "related": {
            "@type": "@id",
            "@id": "skos:related"
          },
          "format": "dc:format",
          "language": "dc:language",
          "created": "oa:annotatedAt",
          "updated": "oa:serializedAt",
          "when": "oa:when",
          "value": "rdf:value",
          "start": "oa:start",
          "end": "oa:end",
          "exact": "oa:exact",
          "prefix": "oa:prefix",
          "suffix": "oa:suffix",
          "label": "rdfs:label",
          "name": "foaf:name",
          "mbox": "foaf:mbox",
          "nick": "foaf:nick",
          "styleClass": "oa:styleClass",
          "@base": "http://hypothes.is/api/annotations/",
          "id": "@id",
          "tags": "oa:Tag"
        },
        "updated": "2014-09-18T21:43:16.353744+00:00",
        "target": [
          {
            "source": "http://faculty.georgetown.edu/irvinem/theory/Berners-Lee-HTTP-proposal.pdf",
            "pos": {
              "top": 549.5,
              "height": 17
            },
            "selector": [
              {
                "type": "RangeSelector",
                "startContainer": "/div[1]/div[2]/div[4]/div[1]/div[1]/div[2]/div[16]",
                "endContainer": "/div[1]/div[2]/div[4]/div[1]/div[1]/div[2]/div[16]",
                "startOffset": 0,
                "endOffset": 7
              },
              {
                "start": 397,
                "end": 404,
                "type": "TextPositionSelector"
              },
              {
                "type": "TextQuoteSelector",
                "prefix": "information Hypermedia CERNDOC",
                "exact": "ENQUIRE",
                "suffix": "Tim Berners-Lee section group C"
              }
            ]
          }
        ],
        "created": "2014-09-18T21:32:13.492351+00:00",
        "text": "As featured in \"Weaving the Web\" by Tim Berners-Lee",
        "tags": [
          "web",
          "history"
        ],
        "uri": "http://faculty.georgetown.edu/irvinem/theory/Berners-Lee-HTTP-proposal.pdf",
        "user": "acct:BigBlueHat@hypothes.is",
        "document": {
          "eprints": {},
          "title": "Berners-Lee-HTTP-proposal.pdf",
          "twitter": {},
          "dc": {},
          "prism": {},
          "highwire": {},
          "facebook": {},
          "reply_to": [],
          "link": [
            {
              "href": "http://faculty.georgetown.edu/irvinem/theory/Berners-Lee-HTTP-proposal.pdf"
            }
          ]
        },
        "consumer": "00000000-0000-0000-0000-000000000000",
        "id": "Gk_TW9d_SyCG5cFH4UCy9A",
        "permissions": {
          "admin": [
            "acct:BigBlueHat@hypothes.is"
          ],
          "read": [
            "acct:BigBlueHat@hypothes.is",
            "group:__world__"
          ],
          "update": [
            "acct:BigBlueHat@hypothes.is"
          ],
          "delete": [
            "acct:BigBlueHat@hypothes.is"
          ]
        }
      }
      
  14. Nov 2021
  15. Oct 2021
    1. social annotation

      Had I known about Hypothesis at the time of my collaboration with Ilaria Forte, I likely would have suggested this as a tool for documenting the stream of consciousness, collecting stories in the context of the media that people are experiencing on the web.

  16. www.programmableweb.com www.programmableweb.com
    1. Hypothesis REST API

      The Hypothesis API integrates annotations into web services. Available to send HTTP requests and JSON responses, it aims to be useful for researchers, scientists, and educators.

  17. Jun 2021
  18. Aug 2020
  19. Feb 2019
  20. Feb 2017