# LeftNav.ts

`

1<comment>/**</comment>

2<comment> * LeftNav: Responsible for constructing the left-hand navigation pane. </comment>

3<comment> */</comment>

4

5<comment>/** */</comment>

6import { m, Vnode} from <quote>'hslayout'</quote>;

7import { Layout } from <quote>'hslayout'</quote>;

8import { Collapsible } from <quote>'hswidget'</quote>;

9import { libLinkByPath }from <quote>'../NodesDisplay'</quote>;

10import { DocSets } from <quote>'../DocSets'</quote>;

11

12

13<comment>/**</comment>

14<comment> * Constructs the left-hand navigation pane</comment>

15<comment> */</comment>

16export class LeftNav extends Layout {

17 getComponents(node: Vnode): Vnode {

18 let lib = m.route.param(<quote>'lib'</quote>);

19 let field = m.route.param(<quote>'field'</quote>);

20 const docSet = DocSets.getNode(0, lib) || {name:<quote>'unknown'</quote>, id:0};

21 return m(<quote>'.hs-left'</quote>, [m(<quote>'.hs-left-nav'</quote>, navList(docSet, field))]);

22 }

23}

24

25<comment>/** creates the list if modules (`*.ts` files) */</comment>

26function navList(docSet:any, field:string):Vnode[] {

27 <comment>/** */</comment>

28 function collectModules(docSet:any) {

29 const modulesByName = {};

30 docSet.modules = [];

31 if (docSet.children) {

32 docSet.children.forEach((c:any) => {

33 <comment>// don<quote>'t show modules from other projects (isExternal flag) or modules on the ignore list</comment>

34<comment></comment> if (!(c.flags && c.flags.isExternal) && !ignoreModules[c.name]) {

35 const name = c.innerModule? c.innerModule : c.name;

36 let module = modulesByName[name];

37 if (!module) { <comment>// new module</comment>

38<comment></comment> docSet.modules.push(module = modulesByName[name] = {

39 name: name,

40 lib: docSet.lib,

41 fullPath: docSet.fullPath + '</quote>.<quote>'+ name,

42 groups:[]

43 });

44 }

45 <comment>// get existing module groups</comment>

46<comment></comment> const groups = {};

47 module.groups.forEach((g:any) => groups[g.title] = g);

48 <comment>// for each group in child:</comment>

49<comment></comment> if (c.groups) { c.groups.forEach((g:any) => {

50 let group = groups[g.title]; <comment>// get existing </comment>

51<comment></comment> if (!group) { <comment>// else create new</comment>

52<comment></comment> group = groups[g.title] = {

53 children:[],

54 kind: g.kind,

55 title: g.title

56 };

57 module.groups.push(group);

58 }

59 group.children = group.children.concat(g.children);

60 });}

61 }

62 });

63 }

64 }

65 <comment>/** </comment>

66<comment> * processes a module, i.e. a `.ts` file.</comment>

67<comment> */</comment>

68 function externalModule(mdl:any) {

69 let selected = false;

70 if (field==='</quote><quote>'+mdl.id || field.indexOf(mdl.fullPath) === 0) { selected=true; }

71

72 return m(Collapsible, {css:`.hs-left-nav-module`, preArrow: true, isExpanded:selected, components:[

73 m(`${selected?'</quote>.hs-left-nav-selected<quote>':'</quote><quote>'}`, libLinkByPath(mdl.lib, mdl.fullPath, mdl.name, `.hs-left-nav-module-name`)),

74 !mdl.groups? undefined : mdl.groups.map((g:any) => entries(g, mdl, field))

75 ]});

76 }

77

78 if (docSet.kind === 0) { <comment>// External DocSets</comment>

79<comment></comment> collectModules(docSet);

80<comment>// const modules = docSet.children? docSet.children.map(externalModule) : ['</quote>no children<quote>'];</comment>

81<comment></comment> const modules = docSet.modules.map(externalModule);

82 modules.unshift(m('</quote>.hs-left-nav-header<quote>', '</quote>Modules<quote>'));

83 return [m('</quote>.hs-left-nav-content<quote>', modules)];

84 }

85}

86

87<comment>/**</comment>

88<comment> * modules to ignore in the list</comment>

89<comment> */</comment>

90const ignoreModules = {

91 overview: true, <comment>// the project overview.ts file</comment>

92<comment></comment> index: true <comment>// the index.ts file</comment>

93<comment></comment>};

94

95<comment>//const expanded: {string?:boolean} = {};</comment>

96<comment></comment>

97<comment>/**</comment>

98<comment> * processes a group of entries, e.g. Variables, Functions, or Classes.</comment>

99<comment> * @param group the group structure within the docset</comment>

100<comment> * @param mdl the entire module docset</comment>

101<comment> * @param field the field ID to be displayed on the main panel</comment>

102<comment> */</comment>

103function entries(group:any, mdl:any, field:string) {

104 function moduleGet(c:any) {

105 return DocSets.getNode(c, mdl.lib);

106 }

107 <comment>/**</comment>

108<comment> * processes one entry within a group, e.g. one variable, function, or class.</comment>

109<comment> */</comment>

110 function entry(mod:any) {

111 const selected = (field==='</quote><quote>'+mod.id || field===mod.fullPath)? '</quote>.hs-left-nav-selected<quote>' : '</quote><quote>';

112 const exported = (mod.flags && mod.flags.isExported);

113 const isStatic = (mod.flags && mod.flags.isStatic);

114 const css = `.hs-left-nav-entry ${selected} ${exported?'</quote>.hs-left-nav-exported<quote>' : '</quote><quote>'}`;

115 return (!exported && group.title==='</quote>Variables<quote>')? '</quote><quote>' : <comment>// ignore local module variables</comment>

116<comment></comment> m('</quote><quote>', [

117 isStatic? '</quote>static<quote>': '</quote><quote>',

118 libLinkByPath(mod.lib, mod.fullPath, mod.name, css)

119 ]);

120 }

121

122 function empty(mod:any) { return mod !== '</quote><quote>'; }

123

124 let grp = [];

125 if (group && group.children) {

126 grp = group.children

127 .map(moduleGet) <comment>// replace id reference by module</comment>

128<comment></comment> .sort(exportAscending) <comment>// sort: exported first, then alphabetically</comment>

129<comment></comment> .map(entry) <comment>// replace module by vnode structure</comment>

130<comment></comment> .filter(empty); <comment>// filter empty elements</comment>

131<comment></comment> if (grp.length > 0) { <comment>// add an entries header if there are elements</comment>

132<comment></comment> grp.unshift(m('</quote>.hs-left-nav-header<quote>', group.title));

133 }

134 }

135 return (grp.length > 1)? m(`.hs-left-nav-entries`, grp) : '</quote>';

136}

137

138<comment>/**</comment>

139<comment> * sorting function: sort first by exported status, then alphabetically.</comment>

140<comment> */</comment>

141function exportAscending(a:any, b:any):boolean|number {

142 if (a.flags && b.flags) {

143 if (a.flags.isExported && b.flags.isExported) { return a.name > b.name; }

144 else if (a.flags.isExported) { return -1; }

145 else if (b.flags.isExported) { return 1; }

146 else { return a.name > b.name; }

147 } else { return a.name > b.name; }

148}

149

150

`