Git Product home page Git Product logo

Comments (12)

robertknight avatar robertknight commented on May 24, 2024

I can reproduce using https://hypothes.is/docs/help and selecting exactly the same text as in the screencast.

In doing so, I see this error in the browser console:

Uncaught (in promise) TypeError: Cannot read property 'nodeType' of undefined
    at Object.Util.getFirstTextNodeNotBefore (https://hypothes.is/assets/client/scripts/injector.bundle.js?bb3e58:4160:14)
    at BrowserRange.Range.BrowserRange.BrowserRange.normalize (https://hypothes.is/assets/client/scripts/injector.bundle.js?bb3e58:4531:24)
    at https://hypothes.is/assets/client/scripts/injector.bundle.js?bb3e58:1424:29
    at https://hypothes.is/assets/client/scripts/injector.bundle.js?bb3e58:1130:24

This is the same error I think as the PDF selection issue.

from client.

robertknight avatar robertknight commented on May 24, 2024

I just reproduced the issue a second time but didn't see any any error in the console.

from client.

robertknight avatar robertknight commented on May 24, 2024

I think the reason why the draft suddenly appears when switching groups may be related to the way that, when switching groups, we first unload all annotations and then reload drafts.unsaved().

That's unnecessary - we should just unload the saved annotations, but it also suggests that we're relying on possibly stale copies of the annotation which might be stored in the drafts service.

from client.

robertknight avatar robertknight commented on May 24, 2024

OK, I've confirmed the above. Changing the _resetAnnotations() function in widget-controller.js to only unload saved annotations when switching groups fixes the problem:

  function _resetAnnotations() {
    annotationMapper.unloadAnnotations(annotationUI.savedAnnotations());
  }

Where savedAnnotations() is a function that returns all annotations currently loaded that have an ID.

from client.

robertknight avatar robertknight commented on May 24, 2024

I can reproduce this issue in Chrome 54.0.2816.0 but not Firefox Nightly (v51.a1)

from client.

robertknight avatar robertknight commented on May 24, 2024

Error reported above is the same as #73 and #124

from client.

robertknight avatar robertknight commented on May 24, 2024

An error occurs when serializing the range to each type of selector in describe() in annotator/anchoring/html.coffee but this error gets swallowed and the result is a new annotation with no associated selectors. This is why the annotation turns into a Page Note after saving.

Error describing range with type RangeAnchor(root, range) {
    if (root == null) {
      missingParameter('root');
    }
    if (range == null) {
      missingParameter('range');
    }
    this.root = root;
    this.range =… TypeError: Cannot read property 'nodeType' of undefined
    at Object.Util.getLastTextNodeUpTo (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:4042:14)
    at BrowserRange.Range.BrowserRange.BrowserRange.normalize (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:4455:24)
    at new RangeAnchor (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:724:42)
    at Function.RangeAnchor.fromRange (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:728:12)
    at http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:370:23
    at Object.exports.describe (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:379:5)
    at getSelectors (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1409:29)
    at Array.map (native)
    at Sidebar.module.exports.Guest.createAnnotation (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1433:36)
    at Sidebar.module.exports.Sidebar.createAnnotation (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:2947:40)
html.coffee:110 Error describing range with type TextPositionAnchor(root, start, end) {
    _classCallCheck(this, TextPositionAnchor);

    if (root === undefined) {
      throw new Error('missing required parameter "root"');
    }
    if (… TypeError: Cannot read property 'nodeType' of null
    at isText (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8529:14)
    at seek (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8500:14)
    at Function.fromRange (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8288:50)
    at http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:370:23
    at Object.exports.describe (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:379:5)
    at getSelectors (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1409:29)
    at Array.map (native)
    at Sidebar.module.exports.Guest.createAnnotation (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1433:36)
    at Sidebar.module.exports.Sidebar.createAnnotation (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:2947:40)
    at Object.onAnnotate (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1062:14)
html.coffee:110 Error describing range with type TextQuoteAnchor(root, exact) {
    var context = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];

    _classCallCheck(this, TextQuoteAnchor);

    if (root === undefi… TypeError: Cannot read property 'nodeType' of null
    at isText (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8529:14)
    at seek (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8500:14)
    at Function.fromRange (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8288:50)
    at Function.fromRange (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:8436:57)
    at http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:370:23
    at Object.exports.describe (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:379:5)
    at getSelectors (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1409:29)
    at Array.map (native)
    at Sidebar.module.exports.Guest.createAnnotation (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:1433:36)
    at Sidebar.module.exports.Sidebar.createAnnotation (http://localhost:5000/assets/client/scripts/injector.bundle.js?06fae6:2947:40)

from client.

robertknight avatar robertknight commented on May 24, 2024

When clicking Annotate after triple-clicking to select the current sentence, the selected range in Chrome looks like this:

Range structure

  commonAncestorContainer: <section>
  startContainer: #text ("There are...")
  startOffset: 0
  endContainer: <h3>
  endOffset: 0

HTML Structure

<section>
<p><span>[START]There are</span>#text</p>
<div>
  <section class="feature-heading">
    <h3>[END]<i class="feature-icon ..."></i>Notes

The code in BrowserRange#normalize attempts to ensure that the range starts and ends at a text node, such that Text.splitText can be called on the start and end nodes.

If the end container is not a text node, it attempts to drill down through the children of this node, starting at endContainer[endOffset] and then iteratively visiting the first child of the current node, until it reaches a text node. It then sets the start of that text node as the end of the selection. In this case, the <h3> has no text child. A fallback code path then gets triggered which attempts to get the last text node in the subtree rooted at endContainer[endOffset-1]and uses the end text position of that node. Since endOffset is 0, there is no such node, so this logic fails.

from client.

robertknight avatar robertknight commented on May 24, 2024

For the text position anchor, there is also an assumption that the end node of the supplied range has a text node descendant, which is not the case here. The text quote anchor fails for the same reason, since it relies on the text position anchor.

// #fromRange method in dom-anchor-text-position

      // Drill down to a text node if the range ends at the container boundary.
      if (endNode.nodeType !== Node.TEXT_NODE) {
        if (endOffset === endNode.childNodes.length) {
          endNode = endNode.childNodes[endOffset - 1];
          endNode = getFirstTextNode(endNode);
          endOffset = endNode.textContent.length;
        } else {
          endNode = endNode.childNodes[endOffset];
          // **Assumes that `endNode` has a text node descendant, which is
          // not the case**
          endNode = getFirstTextNode(endNode);
          endOffset = 0;
        }
      }

      var iter = (0, _nodeIteratorShim2['default'])(root, SHOW_TEXT);
      var start = (0, _domSeek2['default'])(iter, startNode);
      var end = start + (0, _domSeek2['default'])(iter, endNode);

from client.

robertknight avatar robertknight commented on May 24, 2024

This is fixed by the upstream changes in tilgovi/dom-anchor-text-position@d0d11e3 which drastically simplify how range -> selector conversion works for text positions.

from client.

robertknight avatar robertknight commented on May 24, 2024

Fix error capturing selectors for certain selections

from client.

robertknight avatar robertknight commented on May 24, 2024

The cause of this error is that the new annotation, when initially created, has a range selector but no position or quote selectors.

Anchoring always fails for annotations without quote selectors.

The failure to create position and quote anchors is captured by a set of test cases in

['Full node contents with empty node at end.', {position: true, quote: true}],
. Randall has changed the way position and quote anchoring works in the latest version of the dom-anchor-text-{position, quote} libraries which fixed the problem when I tested briefly. The next step is to upgrade these libraries to the latest version, which always requires adapting to some API changes.

from client.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.