aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJez Ng2012-09-06 10:40:30 -0400
committerJez Ng2012-09-06 10:40:30 -0400
commite932e28c6ee3376fc3e2c87f07637f123817e0c9 (patch)
tree2efa30068e871f0b7d4d6b0a8decaef1340d711c
parenteb0955875ba6ba77a90b1e411c42be0df6de950d (diff)
parent95d538d0458ae6206a791edead92cd0e4b1e3990 (diff)
downloadvimium-e932e28c6ee3376fc3e2c87f07637f123817e0c9.tar.bz2
Merge remote-tracking branch 'liesen/idiomatic-coffee-utils' into next-release
-rw-r--r--lib/utils.coffee138
-rw-r--r--tests/utils_test.coffee22
2 files changed, 82 insertions, 78 deletions
diff --git a/lib/utils.coffee b/lib/utils.coffee
index 598b631a..39279760 100644
--- a/lib/utils.coffee
+++ b/lib/utils.coffee
@@ -1,6 +1,7 @@
Utils =
getCurrentVersion: ->
- # Chromium #15242 will make this XHR request to access the manifest unnecessary.
+ # Chromium #15242 will make this XHR request to access the manifest
+ # unnecessary
manifestRequest = new XMLHttpRequest()
manifestRequest.open("GET", chrome.extension.getURL("manifest.json"), false)
manifestRequest.send(null)
@@ -25,10 +26,9 @@ Utils =
escapeHtml: (string) -> string.replace(/</g, "&lt;").replace(/>/g, "&gt;")
# Generates a unique ID
- createUniqueId: (->
+ createUniqueId: do ->
id = 0
- return -> id += 1
- )()
+ -> id += 1
hasChromePrefix: (url) ->
chromePrefixes = [ 'about', 'view-source' ]
@@ -38,84 +38,79 @@ Utils =
# Completes a partial URL (without scheme)
createFullUrl: (partialUrl) ->
- if (!/^[a-z]{3,}:\/\//.test(partialUrl))
+ unless /^[a-z]{3,}:\/\//.test partialUrl
"http://" + partialUrl
else
partialUrl
- # Tries to detect, whether :str is a valid URL.
+ # Tries to detect if :str is a valid URL.
isUrl: (str) ->
- # more or less RFC compliant URL host part parsing. This should be sufficient
- # for our needs
+ # Starts with a scheme: URL
+ return true if /^[a-z]{3,}:\/\//.test str
+
+ # Must not contain spaces
+ return false if ' ' in str
+
+ # More or less RFC compliant URL host part parsing. This should be sufficient for our needs
urlRegex = new RegExp(
- '^(?:([^:]+)(?::([^:]+))?@)?' + # user:password (optional) => \1, \2
- '([^:]+|\\[[^\\]]+\\])' + # host name (IPv6 addresses in square brackets allowed) => \3
- '(?::(\\d+))?$' # port number (optional) => \4
+ '^(?:([^:]+)(?::([^:]+))?@)?' + # user:password (optional) => \1, \2
+ '([^:]+|\\[[^\\]]+\\])' + # host name (IPv6 addresses in square brackets allowed) => \3
+ '(?::(\\d+))?$' # port number (optional) => \4
)
- # these are all official ASCII TLDs that are longer than 3 characters
- # (including the inofficial .onion TLD used by TOR)
- longTlds = [ 'arpa', 'asia', 'coop', 'info', 'jobs', 'local', 'mobi', 'museum', 'name', 'onion' ]
-
- # are there more?
- specialHostNames = [ 'localhost' ]
-
- # it starts with a scheme, so it's definitely an URL
- if (/^[a-z]{3,}:\/\//.test(str))
- return true
-
- # spaces => definitely not a valid URL
- if (str.indexOf(' ') >= 0)
- return false
-
- # assuming that this is an URL, try to parse it into its meaningful parts. If matching fails, we're
- # pretty sure that we don't have some kind of URL here.
- match = urlRegex.exec(str.split('/')[0])
- if (!match)
- return false
- hostname = match[3]
-
- # allow known special host names
- if (specialHostNames.indexOf(hostname) >= 0)
- return true
-
- # allow IPv6 addresses (need to be wrapped in brackets, as required by RFC). It is sufficient to check
- # for a colon here, as the regex wouldn't match colons in the host name unless it's an v6 address
- if (hostname.indexOf(':') >= 0)
- return true
-
- # at this point we have to make a decision. As a heuristic, we check if the input has dots in it. If
- # yes, and if the last part could be a TLD, treat it as an URL.
- dottedParts = hostname.split('.')
- lastPart = dottedParts[dottedParts.length-1]
- if (dottedParts.length > 1 && ((lastPart.length >= 2 && lastPart.length <= 3) ||
- longTlds.indexOf(lastPart) >= 0))
- return true
-
- # also allow IPv4 addresses
- if (/^(\d{1,3}\.){3}\d{1,3}$/.test(hostname))
- return true
-
- # fallback: no URL
+ # Official ASCII TLDs that are longer than 3 characters + inofficial .onion TLD used by TOR
+ longTlds = ['arpa', 'asia', 'coop', 'info', 'jobs', 'local', 'mobi', 'museum', 'name', 'onion']
+
+ specialHostNames = ['localhost']
+
+ # Try to parse the URL into its meaningful parts. If matching fails we're pretty sure that we don't have
+ # some kind of URL here.
+ match = urlRegex.exec (str.split '/')[0]
+ return false unless match
+ hostName = match[3]
+
+ # Allow known special host names
+ return true if hostName in specialHostNames
+
+ # Allow IPv6 addresses (need to be wrapped in brackets as required by RFC). It is sufficient to check for
+ # a colon, as the regex wouldn't match colons in the host name unless it's an v6 address
+ return true if ':' in hostName
+
+ # At this point we have to make a decision. As a heuristic, we check if the input has dots in it. If yes,
+ # and if the last part could be a TLD, treat it as an URL
+ dottedParts = hostName.split '.'
+
+ if dottedParts.length > 1
+ lastPart = dottedParts.pop()
+ return true if 2 <= lastPart.length <= 3 or lastPart in longTlds
+
+ # Allow IPv4 addresses
+ return true if /^(\d{1,3}\.){3}\d{1,3}$/.test hostName
+
+ # Fallback: no URL
return false
# Creates a search URL from the given :query.
createSearchUrl: (query) ->
- # we need to escape explictely to encode characters like "+" correctly
+ # Escape explicitely to encode characters like "+" correctly
"http://www.google.com/search?q=" + encodeURIComponent(query)
- # Converts :string into a google search if it's not already a URL.
- # We don't bother with escaping characters as Chrome will do that for us.
+ # Converts :string into a Google search if it's not already a URL. We don't bother with escaping characters
+ # as Chrome will do that for us.
convertToUrl: (string) ->
string = string.trim()
- # special-case about:[url] and view-source:[url]
- if Utils.hasChromePrefix string then string
+
+ # Special-case about:[url] and view-source:[url]
+ if Utils.hasChromePrefix string
+ string
+ else if Utils.isUrl string
+ Utils.createFullUrl string
else
- if (Utils.isUrl(string)) then Utils.createFullUrl(string) else Utils.createSearchUrl(string)
+ Utils.createSearchUrl string
-# This creates a new function out of an existing function, where the new function takes fewer arguments.
-# This allows us to pass around functions instead of functions + a partial list of arguments.
-Function.prototype.curry = ->
+# This creates a new function out of an existing function, where the new function takes fewer arguments. This
+# allows us to pass around functions instead of functions + a partial list of arguments.
+Function::curry = ->
fixedArguments = Array.copy(arguments)
fn = this
-> fn.apply(this, fixedArguments.concat(Array.copy(arguments)))
@@ -124,19 +119,7 @@ Array.copy = (array) -> Array.prototype.slice.call(array, 0)
String::startsWith = (str) -> @indexOf(str) == 0
-# A very simple method for defining a new class (constructor and methods) using a single hash.
-# No support for inheritance is included because we really shouldn't need it.
-# TODO(philc): remove this.
-Class =
- extend: (properties) ->
- newClass = ->
- this.init.apply(this, arguments) if (this.init)
- null
- newClass.prototype = properties
- newClass.constructor = newClass
- newClass
-
-globalRoot = if window? then window else global
+globalRoot = window ? global
globalRoot.extend = (hash1, hash2) ->
for key of hash2
hash1[key] = hash2[key]
@@ -144,4 +127,3 @@ globalRoot.extend = (hash1, hash2) ->
root = exports ? window
root.Utils = Utils
-root.Class = Class
diff --git a/tests/utils_test.coffee b/tests/utils_test.coffee
index c5e5d002..f3810114 100644
--- a/tests/utils_test.coffee
+++ b/tests/utils_test.coffee
@@ -1,6 +1,28 @@
require "./test_helper.js"
extend(global, require "../lib/utils.js")
+context "isUrl",
+ should "accept valid URLs", ->
+ assert.isTrue Utils.isUrl "www.google.com"
+ assert.isTrue Utils.isUrl "www.bbc.co.uk"
+ assert.isTrue Utils.isUrl "yahoo.com"
+ assert.isTrue Utils.isUrl "nunames.nu"
+ assert.isTrue Utils.isUrl "user:pass@ftp.xyz.com/test"
+
+ assert.isTrue Utils.isUrl "localhost/index.html"
+ assert.isTrue Utils.isUrl "127.0.0.1:8192/test.php"
+
+ # IPv6
+ assert.isTrue Utils.isUrl "[::]:9000"
+
+ # Long TLDs
+ assert.isTrue Utils.isUrl "illinois.state.museum"
+ assert.isTrue Utils.isUrl "eqt5g4fuenphqinx.onion"
+
+ should "reject invalid URLs", ->
+ assert.isFalse Utils.isUrl "a.x"
+ assert.isFalse Utils.isUrl "www-domain-tld"
+
context "convertToUrl",
should "detect and clean up valid URLs", ->
assert.equal "http://www.google.com/", Utils.convertToUrl("http://www.google.com/")