fix(link): auto populate urls. Fix links across nodes

Fixes #1116
Also fixes an issue where links wouldn't create properly across multiple
nodes

This was due to a bug in the `select` method. We use the DOM Range API to
more robustly select a node.
This commit is contained in:
Evan Morikawa 2016-01-22 16:30:28 -08:00
parent d15d39abdf
commit cc0d636381
4 changed files with 27 additions and 16 deletions

View file

@ -39,20 +39,24 @@ class ExtendedSelection
return @
selectAt: (at) ->
nodeAt = @findSelectableNodeAt(at)
@setBaseAndExtent(nodeAt, 0, nodeAt, (nodeAt.length ? 0))
nodeAt = @findNodeAt(at)
range = new Range()
range.selectNode(nodeAt)
@rawSelection.removeAllRanges()
@rawSelection.addRange(range)
return @
selectRange: (range) ->
@setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset)
selectFromTo: (from, to) ->
fromNode = @findSelectableNodeAt(from)
toNode = @findSelectableNodeAt(to)
fromNode = @findNodeAt(from)
toNode = @findNodeAt(to)
@setBaseAndExtent(fromNode, 0, toNode, (toNode.length ? 0))
selectFromToWithIndex: (from, fromIndex, to, toIndex) ->
fromNode = @findSelectableNodeAt(from)
toNode = @findSelectableNodeAt(to)
fromNode = @findNodeAt(from)
toNode = @findNodeAt(to)
if (not _.isNumber(fromIndex)) or (not _.isNumber(toIndex))
throw @_errBadUsage()
@setBaseAndExtent(fromNode, fromIndex, toNode, toIndex)
@ -97,7 +101,7 @@ class ExtendedSelection
newFocusNode,
exportedSelection.focusOffset)
findSelectableNodeAt: (arg) ->
findNodeAt: (arg) ->
node = null
if arg instanceof Node
node = arg
@ -107,12 +111,7 @@ class ExtendedSelection
## TODO
node = DOMUtils.findNodeByRegex(@scopeNode, arg)
# Normally, selections are designed to work on TextNodes, but you
# query by Elements. If an Element has just one textNode, we'll use
# that. If an Element has multiple children, it's ambiguous and we
# won't attempt to find the Text Node for you.
textNode = DOMUtils.findOnlyChildTextNode(node)
if textNode then return textNode else return node
return node
# Finds the start and end text index of the current selection relative
# to a given Node or Range. Returns an object of the form:

View file

@ -1,4 +1,5 @@
React = require 'react/addons'
{RegExpUtils} = require 'nylas-exports'
class LinkEditor extends React.Component
@displayName = "LinkEditor"
@ -95,7 +96,12 @@ class LinkEditor extends React.Component
@props.onDoneWithLink()
_initialUrl: (props=@props) =>
props.linkToModify?.getAttribute('href')
initialUrl = props.linkToModify?.getAttribute('href')
if not initialUrl
if RegExpUtils.urlRegex().test(props.linkToModify?.textContent ? "")
initialUrl = props.linkToModify.textContent
return initialUrl
module.exports = LinkEditor

View file

@ -115,9 +115,8 @@ class LinkManager extends ContenteditableExtension
if linkToModify?
equivalentNode = DOMUtils.findSimilarNodeAtIndex(editor.rootNode, linkToModify, 0)
return unless equivalentNode?
equivalentLinkText = DOMUtils.findFirstTextNode(equivalentNode)
return if linkToModify.getAttribute?('href')?.trim() is url.trim()
toSelect = equivalentLinkText
toSelect = equivalentNode
else
# When atomicEdit gets run, the exportedSelection is already restored to
# the last saved exportedSelection state. Any operation we perform will

View file

@ -16,8 +16,15 @@ RegExpUtils =
# http://stackoverflow.com/a/16463966
# http://www.regexpal.com/?fam=93928
# NOTE: This does not match full urls with `http` protocol components.
domainRegex: -> new RegExp(/^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-zA-Z0-9][a-zA-Z0-9-_]+\.[a-zA-Z]{2,11}?/i)
# Test cases: https://regex101.com/r/pD7iS5/2
# http://daringfireball.net/2010/07/improved_regex_for_matching_urls
# https://mathiasbynens.be/demo/url-regex
# This is the Gruber Regex.
urlRegex: -> new RegExp(/^\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))$/)
# https://regex101.com/r/zG7aW4/3
imageTagRegex: -> /<img\s+[^>]*src="([^"]*)"[^>]*>/g