coffeescript-ui
Version:
Coffeescript User Interface System
272 lines (216 loc) • 6.35 kB
text/coffeescript
###
* coffeescript-ui - Coffeescript User Interface System (CUI)
* Copyright (c) 2013 - 2016 Programmfabrik GmbH
* MIT Licence
* https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org
###
marked = require('marked')
class CUI.DocumentBrowser extends CUI.Element
initOpts: ->
super()
gotoLocation:
check: Function
default: (nodePath, search, nodeIdx) =>
(nodePath, search, nodeIdx)
marked_opts:
default: {}
mandatory: true
check: (v) ->
if not CUI.util.isPlainObject(v)
return false
for _k, _v of v
if _k in ["image", "link"]
return false
true
getMarkdown:
default: (v) -> v
check: Function
renderHref:
check: Function
default: (href, nodePath) =>
href
url:
check: (v) ->
!!CUI.parseLocation(v)
readOpts: ->
super()
= CUI.util.copyObject()
if not .renderer
.renderer = new marked.Renderer()
renderer = .renderer
renderer.image = (href, title, text) =>
.rendererImage(href, title, text)
renderer.link = (href, title, text) =>
.rendererLink(href, title, text)
= {}
renderHref: (href, nodePath) ->
(href, nodePath)
marked: (, markdown) ->
dfr = new CUI.Deferred()
mark = (markdown) =>
dfr.resolve(marked(markdown, ))
ret = (markdown)
if CUI.util.isPromise(ret)
ret
.done (markdown) =>
mark(markdown)
.fail(dfr.reject)
else
mark(ret)
dfr.promise()
loadLocation: (nodePath, search, _nodeIdx) ->
# console.error "loading:", _nodePath
if not nodePath
if not .root.children.length
return
return (.root.children[0].getNodePath())
.root.selectLocation(nodePath)
.done (node) =>
nodeIdx = parseInt(_nodeIdx)
if not node.isSelected()
node.select(search: search, nodeIdx: nodeIdx)
(node, search, nodeIdx)
.fail =>
()
loadEmpty: ->
.replace(new CUI.EmptyLabel(text: "No article available."), "center")
loadContent: (node, search, nodeIdx) ->
node.loadContent()
.done (content, htmlNodes, texts) =>
if not search
.replace(htmlNodes, "center")
return
scroll_node = null
searchQuery = new CUI.DocumentBrowser.SearchQuery(search: search)
nodes = CUI.dom.htmlToNodes((node, content))
text_matches = []
text_node_idx = 0
CUI.dom.findTextInNodes(nodes, (node, textContent) =>
text_node_idx = text_node_idx + 1
text_match = searchQuery.match(textContent)
if not text_match
return
console.debug "matches", searchQuery, textContent
text_match.__mark_all = (nodeIdx == text_node_idx - 1)
text_match.__node = node
text_matches.push(text_match)
)
console.debug "text matches", text_matches
for tm in text_matches
html = tm.getHighlighted()
if tm.__mark_all
html = "<span class='cui-document-browser-marked-node'>" + html + "</span>"
_node = CUI.dom.replaceWith(tm.__node, CUI.dom.htmlToNodes(html))
if tm.__mark_all
scroll_node = _node
# console.debug(child, child.textContent, child.textContent.length)
.replace(nodes, "center")
.prepend(node.getMainArticleUrl(), "center")
if scroll_node
CUI.dom.scrollIntoView(scroll_node)
else
.center().scrollTop = 0
.fail =>
()
getRootNode: ->
.root
__doSearch: (search) ->
.empty("center")
if search.trim().length > 2
matches = .root.findContent(new CUI.DocumentBrowser.SearchQuery(search: search))
# console.debug "found:", matches
for match in matches
.append(match.render(), "center")
if matches.length == 0
.append(
new CUI.Label(markdown: true, text: "Nothing found for **"+search+"**.", multiline: true),
"center")
(true)
else
matches = []
(false)
addWords: (texts) ->
return
for text in texts
for _word in text.split(/(\s+)/)
word = _word.replace(/[\^\$\"\.,\-\(\)\s\t]/g,"")
if word.length == 0
continue
if not .hasOwnProperty(word)
[word] = 1
else
[word] += 1
@
showSearch: (on_off) ->
# console.debug "showSearch", on_off
if on_off
.show()
.hide()
CUI.dom.remove(.DOM)
.replace(, "content")
else
.hide()
.show()
CUI.dom.remove(.DOM)
.replace(.DOM, "content")
render: ->
data = search: ""
do_search = =>
(data.search)
search_input = new CUI.Input
data: data
name: "search"
onDataChanged: =>
CUI.scheduleCallback(ms: 200, call: do_search)
= new CUI.VerticalList()
= new CUI.ListViewTree
cols: ["maximize"]
selectable: true
onSelect: (ev, info) =>
if ev?.search
(info.node.getNodePath(), ev.search, ev.nodeIdx)
else
(info.node.getNodePath())
onDeselect: (ev, info) =>
# console.error "deselect me!", info
root: new CUI.DocumentBrowser.RootNode(browser: @, url: )
= new CUI.SimplePane
header_center: search_input.start()
header_right: [
= new CUI.Button
icon: "search"
onClick: =>
(true)
,
= new CUI.Button
icon: "remove"
hidden: true
onClick: =>
(false)
]
content: .render()
= new CUI.HorizontalLayout
class: "cui-document-browser"
maximize: true
left:
class: "cui-document-browser-list"
content:
flexHandle:
hidden: false
center:
class: "cui-document-browser-center"
content: CUI.dom.text()
load: ->
.root.open()
.done =>
= []
for word, count of
.push
word: word
count: count
sorted: word.toLocaleLowerCase().split("").sort((a,b) -> CUI.util.compareIndex(a, b)).join("")
.sort (a, b) =>
b.count - a.count
console.debug "words", ,