import BookmarkTreeNode = chrome . bookmarks . BookmarkTreeNode ; import PersistentSet from "./PersistentSet" ; export class TreeRenderer { private openFolders : PersistentSet < string > ; private readonly hideEmptyFolders : boolean ; private readonly startWithAllFoldersClosed : boolean ; constructor ( openFolders , hideEmptyFolders , startWithAllFoldersClosed ) { this . openFolders = openFolders ; this . hideEmptyFolders = hideEmptyFolders ; this . startWithAllFoldersClosed = startWithAllFoldersClosed ; } renderTree ( treeNode , document , topLevel = false , visible = true ) { let wrapper ; if ( topLevel ) { wrapper = document . createDocumentFragment ( ) ; } else { wrapper = document . createElement ( 'ul' ) ; wrapper . className = 'sub' ; if ( visible ) { wrapper . style . height = 'auto' ; } } if ( typeof treeNode . children === 'undefined' ) { return wrapper ; } treeNode . children . forEach ( ( child ) => { if ( typeof child === 'undefined' ) { return ; } if ( child . url ) { wrapper . appendChild ( this . renderBookmark ( child , document ) ) ; return ; } wrapper . appendChild ( this . renderFolder ( ! this . startWithAllFoldersClosed && this . openFolders . contains ( child . id ) , document , child ) ) ; } ) ; return wrapper ; } private renderFolder ( isOpen , document , child ) { const d = document . createElement ( 'li' ) ; if ( typeof child . url !== 'undefined' ) { throw new Error ( 'Element appears to be a bookmark rather than a folder. Unable to render.' ) ; } d . classList . add ( 'folder' ) ; if ( isOpen ) { d . classList . add ( 'open' ) ; } const folder = document . createElement ( 'span' ) ; folder . innerText = child . title ; d . appendChild ( folder ) ; if ( this . hideEmptyFolders && this . isFolderEmpty ( child ) ) { d . classList . add ( 'hidden' ) ; } else { d . dataset . itemId = child . id ; if ( child . children && child . children . length ) { if ( isOpen ) { const children = this . renderTree ( child , document , false , isOpen ) ; d . appendChild ( children ) ; } d . dataset . loaded = isOpen ? '1' : '0' ; } } return d ; } private renderBookmark ( child , document ) { if ( typeof child . url === 'undefined' ) { throw new Error ( 'Element does not appear to be a bookmark. Unable to render.' ) ; } const d = document . createElement ( 'li' ) ; d . dataset . url = child . url ; d . dataset . itemId = child . id ; const bookmark = document . createElement ( 'span' ) ; if ( ! /^\s*$/ . test ( child . title ) ) { bookmark . innerText = child . title ; } else { bookmark . innerHTML = '&nbsp;' ; } bookmark . title = `${ child . title } [${ child . url }]` ; bookmark . style . backgroundImage = `url("chrome://favicon/${ child . url }")` ; bookmark . className = 'bookmark' ; d . appendChild ( bookmark ) ; return d ; } isFolderEmpty ( folder ) { if ( typeof folder . children === 'undefined' ) { return false ; } const children = folder . children ; if ( children . length === 0 ) { return true ; } for ( folder of children ) { if ( ! this . isFolderEmpty ( folder ) ) { return false ; } } return true ; } }