search.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. class app.views.Search extends app.View
  2. SEARCH_PARAM = app.config.search_param
  3. @el: '._search'
  4. @activeClass: '_search-active'
  5. @elements:
  6. input: '._search-input'
  7. resetLink: '._search-clear'
  8. @events:
  9. input: 'onInput'
  10. click: 'onClick'
  11. submit: 'onSubmit'
  12. @shortcuts:
  13. typing: 'focus'
  14. altG: 'google'
  15. altS: 'stackoverflow'
  16. altD: 'duckduckgo'
  17. @routes:
  18. after: 'afterRoute'
  19. init: ->
  20. @addSubview @scope = new app.views.SearchScope @el
  21. @searcher = new app.Searcher
  22. @searcher
  23. .on 'results', @onResults
  24. .on 'end', @onEnd
  25. @scope
  26. .on 'change', @onScopeChange
  27. app.on 'ready', @onReady
  28. $.on window, 'hashchange', @searchUrl
  29. $.on window, 'focus', @onWindowFocus
  30. return
  31. focus: =>
  32. return if document.activeElement is @input
  33. return if app.settings.get('noAutofocus')
  34. @input.focus()
  35. return
  36. autoFocus: =>
  37. return if app.isMobile() or $.isAndroid() or $.isIOS()
  38. return if document.activeElement?.tagName is 'INPUT'
  39. return if app.settings.get('noAutofocus')
  40. @input.focus()
  41. return
  42. onWindowFocus: (event) =>
  43. @autoFocus() if event.target is window
  44. getScopeDoc: ->
  45. @scope.getScope() if @scope.isActive()
  46. reset: (force) ->
  47. @scope.reset() if force or not @input.value
  48. @el.reset()
  49. @onInput()
  50. @autoFocus()
  51. return
  52. onReady: =>
  53. @value = ''
  54. @delay @onInput
  55. return
  56. onInput: =>
  57. return if not @value? or # ignore events pre-"ready"
  58. @value is @input.value
  59. @value = @input.value
  60. if @value.length
  61. @search()
  62. else
  63. @clear()
  64. return
  65. search: (url = false) ->
  66. @addClass @constructor.activeClass
  67. @trigger 'searching'
  68. @hasResults = null
  69. @flags = urlSearch: url, initialResults: true
  70. @searcher.find @scope.getScope().entries.all(), 'text', @value
  71. return
  72. searchUrl: =>
  73. if location.pathname is '/'
  74. @scope.searchUrl()
  75. else if not app.router.isIndex()
  76. return
  77. return unless value = @extractHashValue()
  78. @input.value = @value = value
  79. @input.setSelectionRange(value.length, value.length)
  80. @search true
  81. true
  82. clear: ->
  83. @removeClass @constructor.activeClass
  84. @trigger 'clear'
  85. return
  86. externalSearch: (url) ->
  87. if value = @value
  88. value = "#{@scope.name()} #{value}" if @scope.name()
  89. $.popup "#{url}#{encodeURIComponent value}"
  90. @reset()
  91. return
  92. google: =>
  93. @externalSearch "https://www.google.com/search?q="
  94. return
  95. stackoverflow: =>
  96. @externalSearch "https://stackoverflow.com/search?q="
  97. return
  98. duckduckgo: =>
  99. @externalSearch "https://duckduckgo.com/?t=devdocs&q="
  100. return
  101. onResults: (results) =>
  102. @hasResults = true if results.length
  103. @trigger 'results', results, @flags
  104. @flags.initialResults = false
  105. return
  106. onEnd: =>
  107. @trigger 'noresults' unless @hasResults
  108. return
  109. onClick: (event) =>
  110. if event.target is @resetLink
  111. $.stopEvent(event)
  112. @reset()
  113. return
  114. onSubmit: (event) ->
  115. $.stopEvent(event)
  116. return
  117. onScopeChange: =>
  118. @value = ''
  119. @onInput()
  120. return
  121. afterRoute: (name, context) =>
  122. return if app.shortcuts.eventInProgress?.name is 'escape'
  123. @reset(true) if not context.init and app.router.isIndex()
  124. @delay @searchUrl if context.hash
  125. $.requestAnimationFrame @autoFocus
  126. return
  127. extractHashValue: ->
  128. if (value = @getHashValue())?
  129. app.router.replaceHash()
  130. value
  131. HASH_RGX = new RegExp "^##{SEARCH_PARAM}=(.*)"
  132. getHashValue: ->
  133. try HASH_RGX.exec($.urlDecode location.hash)?[1] catch