PageRenderTime 1782ms CodeModel.GetById 27ms RepoModel.GetById 7ms app.codeStats 1ms

/background_scripts/completion_engines.coffee

http://github.com/philc/vimium
CoffeeScript | 178 lines | 123 code | 23 blank | 32 comment | 7 complexity | bb60208aee6f8ca5e99214458bac0402 MD5 | raw file
  1. # A completion engine provides search suggestions for a custom search engine. A custom search engine is
  2. # identified by a "searchUrl". An "engineUrl" is used for fetching suggestions, whereas a "searchUrl" is used
  3. # for the actual search itself.
  4. #
  5. # Each completion engine defines:
  6. #
  7. # 1. An "engineUrl". This is the URL to use for search completions and is passed as the option "engineUrl"
  8. # to the "BaseEngine" constructor.
  9. #
  10. # 2. One or more regular expressions which define the custom search engine URLs for which the completion
  11. # engine will be used. This is passed as the "regexps" option to the "BaseEngine" constructor.
  12. #
  13. # 3. A "parse" function. This takes a successful XMLHttpRequest object (the request has completed
  14. # successfully), and returns a list of suggestions (a list of strings). This method is always executed
  15. # within the context of a try/catch block, so errors do not propagate.
  16. #
  17. # 4. Each completion engine *must* include an example custom search engine. The example must include an
  18. # example "keyword" and an example "searchUrl", and may include an example "description" and an
  19. # "explanation".
  20. #
  21. # Each new completion engine must be added to the list "CompletionEngines" at the bottom of this file.
  22. #
  23. # The lookup logic which uses these completion engines is in "./completion_search.coffee".
  24. #
  25. # A base class for common regexp-based matching engines. "options" must define:
  26. # options.engineUrl: the URL to use for the completion engine. This must be a string.
  27. # options.regexps: one or regular expressions. This may either a single string or a list of strings.
  28. # options.example: an example object containing at least "keyword" and "searchUrl", and optional "description".
  29. class BaseEngine
  30. constructor: (options) ->
  31. extend this, options
  32. @regexps = [ @regexps ] if "string" == typeof @regexps
  33. @regexps = @regexps.map (regexp) -> new RegExp regexp
  34. match: (searchUrl) -> Utils.matchesAnyRegexp @regexps, searchUrl
  35. getUrl: (queryTerms) -> Utils.createSearchUrl queryTerms, @engineUrl
  36. # Several Google completion engines package responses as XML. This parses such XML.
  37. class GoogleXMLBaseEngine extends BaseEngine
  38. parse: (xhr) ->
  39. for suggestion in xhr.responseXML.getElementsByTagName "suggestion"
  40. continue unless suggestion = suggestion.getAttribute "data"
  41. suggestion
  42. class Google extends GoogleXMLBaseEngine
  43. constructor: () ->
  44. super
  45. engineUrl: "http://suggestqueries.google.com/complete/search?ss_protocol=legace&client=toolbar&q=%s"
  46. regexps: "^https?://[a-z]+\\.google\\.(com|ie|co\\.uk|ca|com\\.au)/"
  47. example:
  48. searchUrl: "http://www.google.com/search?q=%s"
  49. keyword: "g"
  50. class GoogleMaps extends GoogleXMLBaseEngine
  51. prefix: "map of "
  52. constructor: () ->
  53. super
  54. engineUrl: "http://suggestqueries.google.com/complete/search?ss_protocol=legace&client=toolbar&q=#{@prefix.split(' ').join '+'}%s"
  55. regexps: "^https?://[a-z]+\\.google\\.(com|ie|co\\.uk|ca|com\\.au)/maps"
  56. example:
  57. searchUrl: "https://www.google.com/maps?q=%s"
  58. keyword: "m"
  59. explanation:
  60. """
  61. This uses regular Google completion, but prepends the text "<tt>map of</tt>" to the query. It works
  62. well for places, countries, states, geographical regions and the like, but will not perform address
  63. search.
  64. """
  65. parse: (xhr) ->
  66. for suggestion in super xhr
  67. continue unless suggestion.startsWith @prefix
  68. suggestion[@prefix.length..]
  69. class Youtube extends GoogleXMLBaseEngine
  70. constructor: ->
  71. super
  72. engineUrl: "http://suggestqueries.google.com/complete/search?client=youtube&ds=yt&xml=t&q=%s"
  73. regexps: "^https?://[a-z]+\\.youtube\\.com/results"
  74. example:
  75. searchUrl: "http://www.youtube.com/results?search_query=%s"
  76. keyword: "y"
  77. class Wikipedia extends BaseEngine
  78. constructor: ->
  79. super
  80. engineUrl: "https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=%s"
  81. regexps: "^https?://[a-z]+\\.wikipedia\\.org/"
  82. example:
  83. searchUrl: "http://www.wikipedia.org/w/index.php?title=Special:Search&search=%s"
  84. keyword: "w"
  85. parse: (xhr) -> JSON.parse(xhr.responseText)[1]
  86. class Bing extends BaseEngine
  87. constructor: ->
  88. super
  89. engineUrl: "http://api.bing.com/osjson.aspx?query=%s"
  90. regexps: "^https?://www\\.bing\\.com/search"
  91. example:
  92. searchUrl: "https://www.bing.com/search?q=%s"
  93. keyword: "b"
  94. parse: (xhr) -> JSON.parse(xhr.responseText)[1]
  95. class Amazon extends BaseEngine
  96. constructor: ->
  97. super
  98. engineUrl: "https://completion.amazon.com/search/complete?method=completion&search-alias=aps&client=amazon-search-ui&mkt=1&q=%s"
  99. regexps: "^https?://www\\.amazon\\.(com|co\\.uk|ca|de|com\\.au)/s/"
  100. example:
  101. searchUrl: "http://www.amazon.com/s/?field-keywords=%s"
  102. keyword: "a"
  103. parse: (xhr) -> JSON.parse(xhr.responseText)[1]
  104. class DuckDuckGo extends BaseEngine
  105. constructor: ->
  106. super
  107. engineUrl: "https://duckduckgo.com/ac/?q=%s"
  108. regexps: "^https?://([a-z]+\\.)?duckduckgo\\.com/"
  109. example:
  110. searchUrl: "https://duckduckgo.com/?q=%s"
  111. keyword: "d"
  112. parse: (xhr) ->
  113. suggestion.phrase for suggestion in JSON.parse xhr.responseText
  114. class Webster extends BaseEngine
  115. constructor: ->
  116. super
  117. engineUrl: "http://www.merriam-webster.com/autocomplete?query=%s"
  118. regexps: "^https?://www.merriam-webster.com/dictionary/"
  119. example:
  120. searchUrl: "http://www.merriam-webster.com/dictionary/%s"
  121. keyword: "dw"
  122. description: "Dictionary"
  123. parse: (xhr) -> JSON.parse(xhr.responseText).suggestions
  124. class Qwant extends BaseEngine
  125. constructor: ->
  126. super
  127. engineUrl: "https://api.qwant.com/api/suggest?q=%s"
  128. regexps: "^https?://www\\.qwant\\.com/"
  129. example:
  130. searchUrl: "https://www.qwant.com/?q=%s"
  131. keyword: "qw"
  132. parse: (xhr) ->
  133. suggestion.value for suggestion in JSON.parse(xhr.responseText).data.items
  134. # A dummy search engine which is guaranteed to match any search URL, but never produces completions. This
  135. # allows the rest of the logic to be written knowing that there will always be a completion engine match.
  136. class DummyCompletionEngine extends BaseEngine
  137. constructor: ->
  138. super
  139. regexps: "."
  140. dummy: true
  141. # Note: Order matters here.
  142. CompletionEngines = [
  143. Youtube
  144. GoogleMaps
  145. Google
  146. DuckDuckGo
  147. Wikipedia
  148. Bing
  149. Amazon
  150. Webster
  151. Qwant
  152. DummyCompletionEngine
  153. ]
  154. root = exports ? window
  155. root.CompletionEngines = CompletionEngines