Coverage for pyquickhelper/sphinxext/sphinx_collapse_extension.py: 96%

75 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-03 02:21 +0200

1# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief Defines a sphinx extension to hide / unhide 

5section of the page. 

6""" 

7import logging 

8from docutils import nodes 

9from docutils.parsers.rst import directives 

10import sphinx 

11from docutils.parsers.rst import Directive 

12from sphinx.util.nodes import nested_parse_with_titles 

13from .sphinx_ext_helper import sphinx_lang 

14from ..texthelper.texts_language import TITLES 

15 

16 

17class collapse_node(nodes.admonition): 

18 """ 

19 defines ``collapse`` node. 

20 """ 

21 pass 

22 

23 

24class CollapseDirective(Directive): 

25 """ 

26 A ``collapse`` adds hide/unhide button 

27 for a part of HTML page. It has no effect 

28 in other formats. 

29 

30 * *legend*: legend for the button, if not precise, 

31 it will be hide / unhide. Example: ``:legend: hide/unhide``. 

32 * *hide*: the text is shown by default unless this option is set up. 

33 

34 Example:: 

35 

36 .. collapse:: 

37 :legend: hide/unhide 

38 

39 some text to hide or unhide 

40 

41 Which gives: 

42 

43 .. collapse:: 

44 

45 some text to hide or unhide 

46 """ 

47 node_class = collapse_node 

48 has_content = True 

49 required_arguments = 0 

50 optional_arguments = 0 

51 final_argument_whitespace = False 

52 option_spec = { 

53 'class': directives.class_option, 

54 'legend': directives.unchanged, 

55 'hide': directives.unchanged, 

56 } 

57 

58 def run(self): 

59 """ 

60 Builds the collapse text. 

61 """ 

62 env = getattr(self.state.document.settings, "env", None) 

63 lang = sphinx_lang(env) 

64 titles = TITLES.get(lang, TITLES['en']) 

65 

66 if 'legend' in self.options: 

67 legend = self.options['legend'] 

68 if '/' not in legend: 

69 logger = logging.getLogger("sphinx") 

70 logger.warning( 

71 "[CollapseDirective] unable to interpret parameter legend %r.", legend) 

72 legend = None 

73 spl = legend.split('/') 

74 hide = spl[0].strip() 

75 unhide = spl[1].strip() 

76 else: 

77 legend = None 

78 

79 if legend is None: 

80 hide = titles['hide'] 

81 unhide = titles['unhide'] 

82 

83 if 'hide' in self.options and self.options['hide'] not in (False, 'False', 'false', 0, '0'): 

84 show = False 

85 else: 

86 show = True 

87 node = collapse_node(hide=hide, unhide=unhide, show=show) 

88 nested_parse_with_titles(self.state, self.content, node) 

89 return [node] 

90 

91 

92def visit_collapse_node(self, node): 

93 """ 

94 visit collapse_node 

95 """ 

96 pass # pragma: no cover 

97 

98 

99def depart_collapse_node(self, node): 

100 """ 

101 depart collapse_node 

102 """ 

103 pass # pragma: no cover 

104 

105 

106def visit_collapse_node_rst(self, node): 

107 """ 

108 visit collapse_node 

109 """ 

110 self.new_state(0) 

111 legend = '/'.join([node['hide'], node['unhide']]) 

112 self.add_text('.. collapse::' + self.nl) 

113 self.add_text(' :legend: ' + legend + self.nl) 

114 if not node['show']: 

115 self.add_text(' :hide:' + self.nl) 

116 self.new_state(self.indent) 

117 

118 

119def depart_collapse_node_rst(self, node): 

120 """ 

121 depart collapse_node 

122 """ 

123 self.end_state() 

124 self.end_state(wrap=False) 

125 

126 

127def visit_collapse_node_html(self, node): 

128 """ 

129 visit collapse_node 

130 """ 

131 nid = str(id(node)) 

132 hide, unhide = node['hide'], node['unhide'] 

133 

134 script = """function myFunction__ID__() { 

135 var x = document.getElementById("collapse__ID__"); 

136 var b = document.getElementById("colidb__ID__"); 

137 if (x.style.display === "none") { x.style.display = "block"; b.innerText = '__HIDE__'; } 

138 else { x.style.display = "none"; b.innerText = '__UNHIDE__'; } 

139 }""".replace(" ", "") 

140 script = script.replace('__ID__', nid) 

141 script = script.replace('__HIDE__', hide) 

142 script = script.replace('__UNHIDE__', unhide) 

143 

144 self.body.append("<script>{0}{1}{0}</script>{0}".format("\n", script)) 

145 if node['show']: 

146 content = f'<div id="collapse{nid}"">' 

147 label = hide 

148 else: 

149 content = f'<div id="collapse{nid}" style="display:none;">' 

150 label = unhide 

151 self.body.append( 

152 '<p style="margin-bottom:10px;"><button id="colidb{0}" onclick="myFunction{0}()">{1}</button></p>{2}'.format(nid, label, "\n")) 

153 self.body.append(content) 

154 

155 

156def depart_collapse_node_html(self, node): 

157 """ 

158 depart collapse_node 

159 """ 

160 self.body.append("</div>") 

161 

162 

163def setup(app): 

164 """ 

165 setup for ``collapse`` (sphinx) 

166 """ 

167 app.add_node(collapse_node, 

168 html=(visit_collapse_node_html, depart_collapse_node_html), 

169 epub=(visit_collapse_node_html, depart_collapse_node_html), 

170 elatex=(visit_collapse_node, depart_collapse_node), 

171 latex=(visit_collapse_node, depart_collapse_node), 

172 text=(visit_collapse_node, depart_collapse_node), 

173 md=(visit_collapse_node, depart_collapse_node), 

174 rst=(visit_collapse_node_rst, depart_collapse_node_rst)) 

175 

176 app.add_directive('collapse', CollapseDirective) 

177 return {'version': sphinx.__display_version__, 'parallel_read_safe': True}