diff --git a/js/kunai.js b/js/kunai.js index a9d08eb..d6f7bfd 100644 --- a/js/kunai.js +++ b/js/kunai.js @@ -30,6 +30,7 @@ class Kunai { })) ) + try { this.log.disableBacktrace(true) this.log.info(`version ${KUNAI_PACKAGE.version} (https://github.com/cpprefjp/kunai/tree/v${KUNAI_PACKAGE.version})`) @@ -38,16 +39,13 @@ class Kunai { this.log.disableBacktrace(false) } - if (this.opts.compat) { - this.compat = new Compat(this.log) - } - this.ui = { navbar: null, sidebar: null, content: null, } this.initUI() + this.getSidebar = this.initSidebar() this.wand = new Wand(this.log) @@ -56,15 +54,21 @@ class Kunai { async cpprefjp() { this.load_impl(['cpprefjp', 'site']) - this.crs = await this.initCRSearch(true) + this.afterCR = this.initCRSearch(true) + this.crs = await this.afterCR } async boostjp() { this.load_impl(['boostjp', 'site']) - this.crs = await this.initCRSearch(false) + this.afterCR = this.initCRSearch(false) + this.crs = await this.afterCR } - load_impl(config) { + async load_impl(config) { + if (this.opts.compat) { + this.compat = new Compat(this.log, config) + } + const desc = config.join('/') this.log.info(`loading (${desc})`) $('body').addClass('kunai') @@ -114,13 +118,18 @@ class Kunai { this.ui.content = new UI.Content(l) } - async initCRSearch(isEnabled, onDatabase) { + async onDatabase(db) { + await this.ui.sidebar.onDatabase(db) + await this.ui.sidebar.treeview.onPageID(this.meta.page_id) + } + + async initCRSearch(isEnabled) { if (!isEnabled) return null - await this.initSidebar() + await this.getSidebar let crs = new CRSearch({ - onDatabase: ::this.ui.sidebar.onDatabase, + onDatabase: ::this.onDatabase, }) crs.database('https://cpprefjp.github.io/static/crsearch/crsearch.json') diff --git a/js/kunai/compat.js b/js/kunai/compat.js index 1a26fac..2872d99 100644 --- a/js/kunai/compat.js +++ b/js/kunai/compat.js @@ -1,6 +1,7 @@ class Compat { - constructor(log) { + constructor(log, repo) { this.log = log.makeContext('Compat') + this.repo = [].concat(repo) this.log.info('applying...') @@ -27,6 +28,8 @@ class Compat { } } + // $('#navbar-collapse ul.nav > li:nth-child(2) > a').text(repo.join('/')) + this.log.info('applied.') } // constructor diff --git a/js/kunai/meta/meta.js b/js/kunai/meta/meta.js index 8e94380..4d3f0b8 100644 --- a/js/kunai/meta/meta.js +++ b/js/kunai/meta/meta.js @@ -6,6 +6,8 @@ import * as Code from '../code' import {Logger} from 'nagato' +import URL from 'url-parse' + let Marked = require('marked') const MarkedOpts = { @@ -56,6 +58,12 @@ class Meta { this.log.info(`original_url: ${this.original_url}`, this.original_url) this.filename = [...this.original_url.pathname.split('/')].pop() + { + let ids = this.original_url.pathname.split('/').slice(5) + ids[ids.length - 1] = ids[ids.length - 1].replace(/\.md$/, '') + this.page_id = ids + } + this.raw_url = new URL(this.original_url) this.raw_url.host = 'raw.githubusercontent.com' this.raw_url.pathname = this.raw_url.pathname.replace( diff --git a/js/kunai/ui/sidebar.js b/js/kunai/ui/sidebar.js index 68d4b86..af42dcc 100644 --- a/js/kunai/ui/sidebar.js +++ b/js/kunai/ui/sidebar.js @@ -33,38 +33,24 @@ class Sidebar { this.e.addClass('legacy') } - this.initComponents() + this.getTreeview = this.initTreeview() } async onDatabase(db) { try { this.log.info(`onDatabase`, db) - this.tree = db.getTree(this.kc) - - // workaround name - for (let t of this.tree) { - if (t.root) { - const name = t.root.id.join() - const real_name = t.category.name - if (name !== real_name) { - this.log.warn(`got incorrect title '${name}'; expected = '${real_name}'. ignoring...`) - } - } - } + this.db = db - this.treeView.onData(this.tree) + let t = await this.getTreeview + await t.onData(db) } finally { this.e.removeClass('loading') } } - async initComponents() { - await this.initDynamicComponents() - } - - async initDynamicComponents() { + async initTreeview() { let e = null if (this.legacy) { @@ -73,7 +59,7 @@ class Sidebar { e = $('
').addClass('kunai-tree').addClass('v2').appendTo(this.e) } - this.treeView = new Treeview( + this.treeview = new Treeview( this.log, this.kc, this.e, @@ -81,6 +67,7 @@ class Sidebar { legacy: this.legacy } ) + return this.treeview } } diff --git a/js/kunai/ui/treeview.js b/js/kunai/ui/treeview.js index f69dcb0..db9e3fc 100644 --- a/js/kunai/ui/treeview.js +++ b/js/kunai/ui/treeview.js @@ -24,6 +24,8 @@ class DOM { this.lastBranchID = 0 this.branchPrevs = new Map + + this.expandElems = new WeakMap } static scrollEps = 8 @@ -82,22 +84,23 @@ class DOM { } } - async createContent(e, elem, obj) { - // this.log.debug(`createContent '${obj.self.id}'`, e, elem, obj) + async createContent(obj) { + this.log.debug(`createContent '${obj.self.id}'`, obj) switch (obj.self.id.type) { case IType.header: - return await this.createHeaderContent(e, elem, obj) + return await this.createHeaderContent(obj) default: - this.log.error('createContent', e, elem, obj) + this.log.error('createContent', obj) throw new Error(`unhandled index type in createContent`) } } - async createHeaderContent(e, elem, h) { + async createHeaderContent(h) { // this.log.debug(`createHeaderContent (${h.self.id.join()})`, e, elem, h) let empty = true + let elem = this.expandElems.get(h.self.id) if (h.classes && h.classes.length) { empty = false @@ -126,10 +129,23 @@ class DOM { return true // this.lazyLoaders.get(h.self.id) } - async doExpand(id, e) { - // this.log.debug(`doExpand '${id.join()}'`, id, e) - await this.lazyLoaders.get(id)(e) - $(e.target).closest('li').toggleClass('expanded') + async doExpand(id) { + // this.log.debug(`doExpand '${id.join()}'`, id) + await this.lazyLoaders.get(id)() + this.expandElems.get(id).toggleClass('expanded') + } + + async scrollAt(id) { + this.log.debug(`scrollAt '${id.join()}'`, id) + + const e = this.expandElems.get(id) + + let broot = e.closest('.kunai-branch') + // this.log.debug(`branch root`, broot) + + broot.animate({ + scrollTop: e.offset().top + }, 1) } async kunaiBranch(me, branchFor, scrollHandler) { @@ -226,18 +242,18 @@ class DOM { } async makeExpandable(elem, obj) { + // this.log.debug(`makeExpandable '${obj.self.id.join()}'`, elem, obj) + this.expandElems.set(obj.self.id, elem) this.lazyLoaders.set( obj.self.id, - async (e) => { - return await ::this.createContent(e, elem, obj) - } + async () => { await this.createContent(obj) } ) let bar = $('
', {class: 'expandbar'}).appendTo(elem) bar.append( - $('
', {class: 'expander'}).on('click', async (e) => { - await this.doExpand(obj.self.id, e) + $('
', {class: 'expander'}).on('click', async () => { + await this.doExpand(obj.self.id) }) ) @@ -289,37 +305,95 @@ class Treeview { } } - async onData(tree) { - const runID = JSON.stringify({name: 'onData', timestamp: Date.now()}) - console.time(runID) - try { - this.dom = new DOM(this.log, this.kc) - await this.onDataImpl(tree) - } finally { - console.timeEnd(runID) + async onPageID(ids) { + this.page_id = [].concat(ids) + + this.page_idx_id = null + const ns_id = ids.shift() + + for (const type of Object.values(IType)) { + const rvid = IndexID.composeReverseID(type, ids) + if (this.db.reverseID.has(rvid)) { + this.page_idx_id = this.db.reverseID.get(rvid) + } } - } - async onDataImpl(tree) { - this.log.debug('data', tree) - let root = $('
    ', {class: 'root'}).appendTo(this.root) + this.page_idx = null - const cats = this.kc.categories() + try { + if (!this.page_idx_id) { + throw new Error(`IndexID for path '${ids.join('/')}' not present in database`) + } + if (!IndexID.isClassy(this.page_idx_id.type)) { + this.log.info(`current page '${this.page_idx_id.join()}' is not classy. nothing to expand`) + + } else { + this.log.info(`classy page '${this.page_idx_id.join()}'`) - for (const top of tree) { - if (top.category.index === cats.get('index').index) { - continue + for (const ns of this.db.namespaces) { + if (ns.namespace[0] !== 'reference') continue + + this.log.debug(`checking Namespace '${ns.pretty_name()}'`, ns) + if (ns.indexes.has(this.page_idx_id)) { + this.page_idx = ns.indexes.get(this.page_idx_id) + } + } + + if (!this.page_idx) { + throw new Error(`Index for '${this.page_idx_id.join()}' not found in any of the 'reference' namespace`) + } + + const h = this.page_idx.in_header + this.log.info(`expanding current page header '${h.id.join()}'`, h, this.page_idx) + + // await this.dom.doExpand(h.id) + await this.dom.doExpand(h.id) + await this.dom.scrollAt(h.id) } - let e = $('
  • ', {class: 'top', 'data-top-id': top.namespace.namespace[0]}).appendTo(root) - e.append(await this.dom.makeTitle(top)) + } catch (e) { + this.log.error(`Failed to determine current page for id '${ids.join('/')}'. Sidebar will NOT work properly! (${e})`, ids) + } + } - if (top.category.index === cats.get('lang').index) { - this.processLangTop(top, e) - } else { - this.processTop(top, e) + async onData(db) { + this.db = db + this.tree = db.getTree(this.kc) + + // workaround name + for (let t of this.tree) { + if (t.root) { + const name = t.root.id.join() + const real_name = t.category.name + if (name !== real_name) { + this.log.warn(`got incorrect title '${name}'; expected = '${real_name}'. ignoring...`) + } } } + + this.dom = new DOM(this.log, this.kc) + await this.onDataImpl() + } + + async onDataImpl() { + this.log.debug('data', this.tree) + let root = $('
      ', {class: 'root'}).appendTo(this.root) + + const cats = this.kc.categories() + + root.append(await Promise.all( + this.tree.filter((top) => top.category.index !== cats.get('index').index).map(async (top) => { + let e = $('
    • ', {class: 'top', 'data-top-id': top.namespace.namespace[0]}) + e.append(await this.dom.makeTitle(top)) + + if (top.category.index === cats.get('lang').index) { + this.processLangTop(top, e) + } else { + this.processTop(top, e) + } + return e + }) + )) } async processTop(top, e) { diff --git a/js/kunai/wand.js b/js/kunai/wand.js index 8367b8c..60012e2 100644 --- a/js/kunai/wand.js +++ b/js/kunai/wand.js @@ -3,6 +3,8 @@ import {NetworkError} from './error' import {default as Numeral} from 'numeral' import {Logger} from 'nagato' +import URL from 'url-parse' + class APIError extends NetworkError { constructor() { diff --git a/package.json b/package.json index 0b8f9e5..ef68aec 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "anser": "^1.4.4", "babel-runtime": "^6.26.0", "codemirror": "^5.31.0", - "crsearch": "^2.6.2", + "crsearch": "^2.6.4", "font-awesome": "^4.7.0", "jquery": "^3.2.1", "marked": "^0.3.6",