Overlay decorations appear in the wrong location


#1

I’ve been tearing my hair out over this one for a couple of days now. I’m trying to add overlay decorations to certain parts of the editor, but they appear in the wrong locations. Each decoration is about 20px too far down and 60px too far to the right. Here’s the code I’m using:

let startPoint = [0, 0];
let endPoint = [0, 5];
let marker = editor.markBufferRange([startPoint, endPoint]);
let item = document.createElement('div');
item.style.cssText = 'width: 10px; height: 10px; background-color: #F00';
editor.decorateMarker(marker, { type: 'overlay', item: item });

Here’s what I see in Atom:

The overlay is supposed to start at the keyword module (i.e. character [0, 0]) but as you can see, it’s top and left positions are incorrect.

What am I doing wrong here?


#2

What’s the end result you’re looking for? Are you trying to cover up [0,0] through [0,5]? Because the overlay decoration places an overlay either above the head or below the tail of the range. It’s defaulting to tail, so the block is right below [0,5].


#3

@DamnedScholar ah ok that’s my misunderstanding of how overlays work then. I assumed they worked the same as highlights.

Yes, my ultimate goal is to cover up [0, 0] through [0, 5]. How should I go about doing that?


#4

If you make a highlight with z-index: 1, it will cover the text.


#5

@DamnedScholar Perhaps I should step back another level. I’m interested in denoting a region of the buffer that yes, does need to be styled, but what I’m really interested in is being able to click on the region, add popups to it, etc. As far as I know, the highlight decorations don’t expose a view to which I can attach event handlers, which is why I’m trying to use overlays instead.


#6

You can use addEventListener() on any element with a DOM node that you can find. Highlight decorations are just div tags, and if they’re not buried under something else, they’re clickable.


#7

@DamnedScholar is there a way to find the element using the return value of decorateMarker or something? I guess I could decorate markers one at a time and then find the last highlight div to attach handlers to…


#8

If you’re making more than one, you could make class unique and assigned programmatically. Something like this?

var list = {
  a: ([0,0],[0,5]),
  b: ([10,0],[12,5])
};

for (var key in list){
  let marker = editor.markBufferRange(list[key]);
  editor.decorateMarker(marker, { type: 'highlight', class: 'my_highlight_' + key });
}

#9

@DamnedScholar Yeah, ok that’s the approach I decided to try this morning. The problem I’m running into now is knowing when the view gets updated. I can’t rely on editor.onDidUpdateDecorations because the highlights may or may not have rendered by that point. I guess I’m going to have to rely on mutation observers or something to detect when elements are appended to the <div class="highlight"> elements. I wish there was an easier way because that feels like a real hack.


#10

I like to remind myself that working with DOM elements started as an inherently hacky system, and the more elegant ways we do it now are just whatever the designer of that particular framework or API thought was relevant to cover. For the most part, I like this better than what I see as the omnibus gospel of JQuery, which was so universal, elegant, and tight that it was practically its own language and had opinions about the way everything else should run. With manipulation governed by focused, limited tools, it feels like the tasks central to the stated purposes of those tools are so much easier, but the cost is having to revert to the bad old ways when you step outside the intended scope. Highlights were meant to sit behind text and notify you of errors or search results, so what you want might require a little stretching.

Good luck. Post here if you come up with something that works.