{"id":154,"date":"2010-09-21T10:50:48","date_gmt":"2010-09-21T17:50:48","guid":{"rendered":"http:\/\/adam.yanalunas.com\/blog\/?p=154"},"modified":"2010-10-20T11:55:26","modified_gmt":"2010-10-20T18:55:26","slug":"the-subtle-art-of-ranges-intro","status":"publish","type":"post","link":"http:\/\/adam.yanalunas.com\/blog\/archives\/154","title":{"rendered":"The subtle art of ranges &#8211; Intro"},"content":{"rendered":"<p>You&#8217;re starting to see it more and more. You select some text on a website and &#8212; <em>woosh<\/em> &#8212; something happens. Sometimes you expect the action. Oftentimes you don&#8217;t. Regardless, these things are possible due to DOM ranges. <\/p>\n<p>And DOM ranges are terrible.<\/p>\n<p>I don&#8217;t mean they are a terrible idea. I mean they&#8217;re terrible to work with. Of course there is no single, standard API to work with. Of course Internet Explorer adds another level of challenge. And of course you&#8217;re going to at some point have to know how these things work if you expect to be a JavaScript ninja.<\/p>\n<p>There are many reasons to deal with ranges. Some lame services will hijack your selection and inject in their own tags. If you&#8217;ve ever needed to hack around a WYSWYG editor then ranges will be on the docket. Or say you&#8217;re leading a team that allows users to select text on a page and do things like highlight it, make a note attached to it or even place a bookmark at that point in the page. That&#8217;d be <a href=\"https:\/\/content.ashford.edu\/\">my job<\/a>.<\/p>\n<p>The default <a href=\"https:\/\/developer.mozilla.org\/en\/DOM\/range\">range object<\/a> seems good enough for a lot of tasks. Where it starts to show its weakness is interacting with the DOM outside of just the range. <\/p>\n<p>You want to take what a user has selected and wrap it in a decorative <code>&lt;span&gt;<\/code>? That should be easy, right? What happens if that selection starts in the middle of an <code>&lt;li&gt;<\/code>, moves down a few paragraphs, enters a <code>&lt;div&gt;<\/code> and ends a few levels deeper in the node tree? Well, you can&#8217;t just wrap that in a single element. <\/p>\n<p>The browsers all try to be helpful. Really, they do. If your range starts in the middle of an <code>&lt;em&gt;<\/code> tag but ends outside of it the range you get back from the browser will automatically split the tag properly if you wrap it. That&#8217;s nice. But if you remove that wrapper now you have a split tag that equates to more child nodes in memory than in code. That makes for bad assumptions later.<\/p>\n<p>During my research into and development of this project I&#8217;ve found a stunning lack of comprehensive information (much less example code) for DOM ranges. Obviously <a href=\"http:\/\/www.quirksmode.org\/dom\/range_intro.html\">PPK is the place to start<\/a> but his level of detail is light and &#8212; at best &#8212; beginner. I&#8217;ve worked with some guys at Google who are on the Closure Library team and are ridiculously smart. Even they didn&#8217;t plan for the basic needs I have. Or it could be I&#8217;m doing it wrong.<\/p>\n<p>In any case, I&#8217;ll be working on a series of entries to this blog that will go through what I&#8217;ve learned, show some code, talk about common pitfalls, propose some best practices and hopefully shine some light on the dark corner that is DOM ranges.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;re starting to see it more and more. You select some text on a website and &#8212; woosh &#8212; something happens. Sometimes you expect the action. Oftentimes you don&#8217;t. Regardless, these things are possible due to DOM ranges. <\/p>\n<p>And DOM ranges are terrible.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6],"tags":[30,40,35],"_links":{"self":[{"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/posts\/154"}],"collection":[{"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/comments?post=154"}],"version-history":[{"count":4,"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/posts\/154\/revisions"}],"predecessor-version":[{"id":158,"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/posts\/154\/revisions\/158"}],"wp:attachment":[{"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/media?parent=154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/categories?post=154"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/adam.yanalunas.com\/blog\/wp-json\/wp\/v2\/tags?post=154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}