diff --git a/src/range.coffee b/src/range.coffee
index c0d44b379..07ee64de2 100644
--- a/src/range.coffee
+++ b/src/range.coffee
@@ -133,42 +133,53 @@ class Range.BrowserRange
       @tainted = true
 
     r = {}
-    nr = {}
-
-    for p in ['start', 'end']
-      node = this[p + 'Container']
-      offset = this[p + 'Offset']
-
-      if node.nodeType is Node.ELEMENT_NODE
-        # Get specified node.
-        it = node.childNodes[offset]
-        # If it doesn't exist, that means we need the end of the
-        # previous one.
-        node = it or node.childNodes[offset - 1]
-
-        # if node doesn't have any children, it's a <br> or <hr> or
-        # other self-closing tag, and we actually want the textNode
-        # that ends just before it
-        if node.nodeType is Node.ELEMENT_NODE and not node.firstChild
-          it = null # null out ref to node so offset is correctly calculated below.
-          node = node.previousSibling
-
-        while node.nodeType isnt Node.TEXT_NODE
-          node = node.firstChild
-
-        offset = if it then 0 else node.nodeValue.length
-
-      r[p] = node
-      r[p + 'Offset'] = offset
 
+    # Look at the start
+    if @startContainer.nodeType is Node.ELEMENT_NODE
+      # We are dealing with element nodes  
+      r.start = Util.getFirstTextNodeNotBefore @startContainer.childNodes[@startOffset]
+      r.startOffset = 0
+    else
+      # We are dealing with simple text nodes
+      r.start = @startContainer
+      r.startOffset = @startOffset
+
+    # Look at the end
+    if @endContainer.nodeType is Node.ELEMENT_NODE
+      # Get specified node.
+      node = @endContainer.childNodes[@endOffset]
+
+      if node? # Does that node exist?
+        # Look for a text node either at the immediate beginning of node
+        n = node
+        while n? and (n.nodeType isnt Node.TEXT_NODE)
+          n = n.firstChild
+        if n? # Did we find a text node at the start of this element?
+          r.end = n
+          r.endOffset = 0
+
+      unless r.end?  
+        # We need to find a text node in the previous node.
+        node = @endContainer.childNodes[@endOffset - 1]
+        r.end = Util.getLastTextNodeUpTo node
+        r.endOffset = r.end.nodeValue.length
+
+    else # We are dealing with simple text nodes
+      r.end = @endContainer
+      r.endOffset = @endOffset
+
+    # We have collected the initial data.
+
+    # Now let's start to slice & dice the text elements!
+    nr = {}
     nr.start = if r.startOffset > 0 then r.start.splitText(r.startOffset) else r.start
 
-    if r.start is r.end
-      if (r.endOffset - r.startOffset) < nr.start.nodeValue.length
+    if r.start is r.end # is the whole selection inside one text element ?
+      if nr.start.nodeValue.length > (r.endOffset - r.startOffset)
         nr.start.splitText(r.endOffset - r.startOffset)
       nr.end = nr.start
-    else
-      if r.endOffset < r.end.nodeValue.length
+    else # no, the end of the selection is in a separate text element
+      if r.end.nodeValue.length > r.endOffset# does the end need to be cut?
         r.end.splitText(r.endOffset)
       nr.end = r.end
 
diff --git a/src/util.coffee b/src/util.coffee
index 6b4f35804..8b6f42434 100644
--- a/src/util.coffee
+++ b/src/util.coffee
@@ -33,6 +33,18 @@ Util.flatten = (array) ->
 
   flatten(array)
 
+# Public: decides whether node A is an ancestor of node B.
+#
+# This function purposefully ignores the native browser function for this,
+# because it acts weird in PhantomJS.
+# Issue: https://github.com/ariya/phantomjs/issues/11479
+Util.contains = (parent, child) ->
+  node = child
+  while node?
+    if node is parent then return true
+    node = node.parentNode
+  return false
+
 # Public: Finds all text nodes within the elements in the current collection.
 #
 # Returns a new jQuery collection of text nodes.
@@ -59,6 +71,44 @@ Util.getTextNodes = (jq) ->
 
   jq.map -> Util.flatten(getTextNodes(this))
 
+# Public: determine the last text node inside or before the given node
+Util.getLastTextNodeUpTo = (n) ->
+  switch n.nodeType
+    when Node.TEXT_NODE
+      return n # We have found our text node.
+    when Node.ELEMENT_NODE
+      # This is an element, we need to dig in
+      if n.lastChild? # Does it have children at all?
+        result = Util.getLastTextNodeUpTo n.lastChild
+        if result? then return result        
+    else
+      # Not a text node, and not an element node.
+  # Could not find a text node in current node, go backwards
+  n = n.previousSibling
+  if n?
+    Util.getLastTextNodeUpTo n
+  else
+    null
+
+# Public: determine the first text node in or after the given jQuery node.
+Util.getFirstTextNodeNotBefore = (n) ->
+  switch n.nodeType
+    when Node.TEXT_NODE
+      return n # We have found our text node.
+    when Node.ELEMENT_NODE
+      # This is an element, we need to dig in
+      if n.firstChild? # Does it have children at all?
+        result = Util.getFirstTextNodeNotBefore n.firstChild
+        if result? then return result
+    else
+      # Not a text or an element node.
+  # Could not find a text node in current node, go forward
+  n = n.nextSibling
+  if n?
+    Util.getFirstTextNodeNotBefore n
+  else
+    null
+
 Util.xpathFromNode = (el, relativeRoot) ->
   try
     result = simpleXPathJQuery.call el, relativeRoot
diff --git a/test/helpers/spec_helper.coffee b/test/helpers/spec_helper.coffee
index 1f878a58d..2ddf66993 100644
--- a/test/helpers/spec_helper.coffee
+++ b/test/helpers/spec_helper.coffee
@@ -15,7 +15,7 @@ class this.MockSelection
     @description    = data[5]
 
     @commonAncestor = @startContainer
-    while not @commonAncestor.contains @endContainer
+    while not Util.contains(@commonAncestor, @endContainer)
       @commonAncestor = @commonAncestor.parentNode
     @commonAncestorXPath = Util.xpathFromNode($(@commonAncestor))[0]
 
