UNPKG

coffeescript-ui

Version:
272 lines (216 loc) 6.35 kB
### * 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() @addOpts gotoLocation: check: Function default: (nodePath, search, nodeIdx) => @loadLocation(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() @__marked_opts = CUI.util.copyObject(@_marked_opts) if not @__marked_opts.renderer @__marked_opts.renderer = new marked.Renderer() renderer = @__marked_opts.renderer renderer.image = (href, title, text) => @__node.rendererImage(href, title, text) renderer.link = (href, title, text) => @__node.rendererLink(href, title, text) @__words = {} renderHref: (href, nodePath) -> @_renderHref(href, nodePath) marked: (@__node, markdown) -> dfr = new CUI.Deferred() mark = (markdown) => dfr.resolve(marked(markdown, @__marked_opts)) ret = @_getMarkdown(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 @__tree.root.children.length return return @loadLocation(@__tree.root.children[0].getNodePath()) @__tree.root.selectLocation(nodePath) .done (node) => nodeIdx = parseInt(_nodeIdx) if not node.isSelected() node.select(search: search, nodeIdx: nodeIdx) @loadContent(node, search, nodeIdx) .fail => @loadEmpty() loadEmpty: -> @__layout.replace(new CUI.EmptyLabel(text: "No article available."), "center") loadContent: (node, search, nodeIdx) -> node.loadContent() .done (content, htmlNodes, texts) => if not search @__layout.replace(htmlNodes, "center") return scroll_node = null searchQuery = new CUI.DocumentBrowser.SearchQuery(search: search) nodes = CUI.dom.htmlToNodes(@marked(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) @__layout.replace(nodes, "center") @__layout.prepend(node.getMainArticleUrl(), "center") if scroll_node CUI.dom.scrollIntoView(scroll_node) else @__layout.center().scrollTop = 0 .fail => @loadEmpty() getRootNode: -> @__tree.root __doSearch: (search) -> @__searchResult.empty("center") if search.trim().length > 2 matches = @__tree.root.findContent(new CUI.DocumentBrowser.SearchQuery(search: search)) # console.debug "found:", matches for match in matches @__searchResult.append(match.render(), "center") if matches.length == 0 @__searchResult.append( new CUI.Label(markdown: true, text: "Nothing found for **"+search+"**.", multiline: true), "center") @showSearch(true) else matches = [] @showSearch(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 @__words.hasOwnProperty(word) @__words[word] = 1 else @__words[word] += 1 @ showSearch: (on_off) -> # console.debug "showSearch", on_off if on_off @__resetBtn.show() @__searchBtn.hide() CUI.dom.remove(@__tree.DOM) @__leftLayout.replace(@__searchResult, "content") else @__resetBtn.hide() @__searchBtn.show() CUI.dom.remove(@__searchResult.DOM) @__leftLayout.replace(@__tree.DOM, "content") render: -> data = search: "" do_search = => @__doSearch(data.search) search_input = new CUI.Input data: data name: "search" onDataChanged: => CUI.scheduleCallback(ms: 200, call: do_search) @__searchResult = new CUI.VerticalList() @__tree = new CUI.ListViewTree cols: ["maximize"] selectable: true onSelect: (ev, info) => if ev?.search @_gotoLocation(info.node.getNodePath(), ev.search, ev.nodeIdx) else @_gotoLocation(info.node.getNodePath()) onDeselect: (ev, info) => # console.error "deselect me!", info root: new CUI.DocumentBrowser.RootNode(browser: @, url: @_url) @__leftLayout = new CUI.SimplePane header_center: search_input.start() header_right: [ @__searchBtn = new CUI.Button icon: "search" onClick: => @showSearch(true) , @__resetBtn = new CUI.Button icon: "remove" hidden: true onClick: => @showSearch(false) ] content: @__tree.render() @__layout = new CUI.HorizontalLayout class: "cui-document-browser" maximize: true left: class: "cui-document-browser-list" content: @__leftLayout flexHandle: hidden: false center: class: "cui-document-browser-center" content: CUI.dom.text(@_url) @__layout load: -> @__tree.root.open() .done => @__all_words = [] for word, count of @__words @__all_words.push word: word count: count sorted: word.toLocaleLowerCase().split("").sort((a,b) -> CUI.util.compareIndex(a, b)).join("") @__all_words.sort (a, b) => b.count - a.count console.debug "words", @__words, @__all_words