class app.views.SearchScope extends app.View SEARCH_PARAM = app.config.search_param @elements: input: '._search-input' tag: '._search-tag' @events: click: 'onClick' keydown: 'onKeydown' textInput: 'onTextInput' @routes: after: 'afterRoute' constructor: (@el) -> super init: -> @placeholder = @input.getAttribute 'placeholder' @searcher = new app.SynchronousSearcher fuzzy_min_length: 2 max_results: 1 @searcher.on 'results', @onResults return getScope: -> @doc or app isActive: -> !!@doc name: -> @doc?.name search: (value, searchDisabled = false) -> return if @doc @searcher.find app.docs.all(), 'text', value @searcher.find app.disabledDocs.all(), 'text', value if not @doc and searchDisabled return searchUrl: -> if value = @extractHashValue() @search value, true return onResults: (results) => return unless doc = results[0] if app.docs.contains(doc) @selectDoc(doc) else @redirectToDoc(doc) return selectDoc: (doc) -> previousDoc = @doc return if doc is previousDoc @doc = doc @tag.textContent = doc.fullName @tag.style.display = 'block' @input.removeAttribute 'placeholder' @input.value = @input.value[@input.selectionStart..] @input.style.paddingLeft = @tag.offsetWidth + 10 + 'px' $.trigger @input, 'input' @trigger 'change', @doc, previousDoc return redirectToDoc: (doc) -> hash = location.hash app.router.replaceHash('') location.assign doc.fullPath() + hash return reset: => return unless @doc previousDoc = @doc @doc = null @tag.textContent = '' @tag.style.display = 'none' @input.setAttribute 'placeholder', @placeholder @input.style.paddingLeft = '' @trigger 'change', null, previousDoc return doScopeSearch: (event) => @search @input.value[0...@input.selectionStart] $.stopEvent(event) if @doc return onClick: (event) => if event.target is @tag @reset() $.stopEvent(event) return onKeydown: (event) => if event.which is 8 # backspace if @doc and @input.selectionEnd is 0 @reset() $.stopEvent(event) else if not @doc and @input.value and not $.isChromeForAndroid() return if event.ctrlKey or event.metaKey or event.altKey or event.shiftKey if event.which is 9 or # tab (event.which is 32 and app.isMobile()) # space @doScopeSearch(event) return onTextInput: (event) => return unless $.isChromeForAndroid() if not @doc and @input.value and event.data == ' ' @doScopeSearch(event) return extractHashValue: -> if value = @getHashValue() newHash = $.urlDecode(location.hash).replace "##{SEARCH_PARAM}=#{value} ", "##{SEARCH_PARAM}=" app.router.replaceHash(newHash) value HASH_RGX = new RegExp "^##{SEARCH_PARAM}=(.+?) ." getHashValue: -> try HASH_RGX.exec($.urlDecode location.hash)?[1] catch afterRoute: (name, context) => if !app.isSingleDoc() and context.init and context.doc @selectDoc(context.doc) return
class app.views.SearchScope extends app.View
SEARCH_PARAM = app.config.search_param
@elements:
input: '._search-input'
tag: '._search-tag'
@events:
click: 'onClick'
keydown: 'onKeydown'
textInput: 'onTextInput'
@routes:
after: 'afterRoute'
constructor: (@el) -> super
init: ->
@placeholder = @input.getAttribute 'placeholder'
@searcher = new app.SynchronousSearcher
fuzzy_min_length: 2
max_results: 1
@searcher.on 'results', @onResults
return
getScope: ->
@doc or app
isActive: ->
!!@doc
name: ->
@doc?.name
search: (value, searchDisabled = false) ->
return if @doc
@searcher.find app.docs.all(), 'text', value
@searcher.find app.disabledDocs.all(), 'text', value if not @doc and searchDisabled
return
searchUrl: ->
if value = @extractHashValue()
@search value, true
return
onResults: (results) =>
return unless doc = results[0]
if app.docs.contains(doc)
@selectDoc(doc)
else
@redirectToDoc(doc)
return
selectDoc: (doc) ->
previousDoc = @doc
return if doc is previousDoc
@doc = doc
@tag.textContent = doc.fullName
@tag.style.display = 'block'
@input.removeAttribute 'placeholder'
@input.value = @input.value[@input.selectionStart..]
@input.style.paddingLeft = @tag.offsetWidth + 10 + 'px'
$.trigger @input, 'input'
@trigger 'change', @doc, previousDoc
return
redirectToDoc: (doc) ->
hash = location.hash
app.router.replaceHash('')
location.assign doc.fullPath() + hash
return
reset: =>
return unless @doc
previousDoc = @doc
@doc = null
@tag.textContent = ''
@tag.style.display = 'none'
@input.setAttribute 'placeholder', @placeholder
@input.style.paddingLeft = ''
@trigger 'change', null, previousDoc
return
doScopeSearch: (event) =>
@search @input.value[0...@input.selectionStart]
$.stopEvent(event) if @doc
return
onClick: (event) =>
if event.target is @tag
@reset()
$.stopEvent(event)
return
onKeydown: (event) =>
if event.which is 8 # backspace
if @doc and @input.selectionEnd is 0
@reset()
$.stopEvent(event)
else if not @doc and @input.value and not $.isChromeForAndroid()
return if event.ctrlKey or event.metaKey or event.altKey or event.shiftKey
if event.which is 9 or # tab
(event.which is 32 and app.isMobile()) # space
@doScopeSearch(event)
return
onTextInput: (event) =>
return unless $.isChromeForAndroid()
if not @doc and @input.value and event.data == ' '
@doScopeSearch(event)
return
extractHashValue: ->
if value = @getHashValue()
newHash = $.urlDecode(location.hash).replace "##{SEARCH_PARAM}=#{value} ", "##{SEARCH_PARAM}="
app.router.replaceHash(newHash)
value
HASH_RGX = new RegExp "^##{SEARCH_PARAM}=(.+?) ."
getHashValue: ->
try HASH_RGX.exec($.urlDecode location.hash)?[1] catch
afterRoute: (name, context) =>
if !app.isSingleDoc() and context.init and context.doc
@selectDoc(context.doc)
return