Coverage for src/jyquickhelper/helper_in_notebook.py: 87%
38 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-02 00:05 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-02 00:05 +0200
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Functions to call from the notebook
5"""
6from IPython.display import Javascript, HTML
9def set_notebook_name_theNotebook(name="theNotebook", display=True):
10 """
11 This function must be called from the notebook
12 you want to know the name. It relies on
13 a javascript piece of code. It populates
14 the variable ``theNotebook`` with the notebook name.
16 @param name name of the variable to create
17 @param display calls `display <http://ipython.readthedocs.io/en/stable/api/generated/
18 IPython.display.html#IPython.display.display>`_
19 or returns a javascript object
20 @return None or `Javascript <http://ipython.readthedocs.io/en/stable/api/generated/
21 IPython.display.html#IPython.display.Javascript>`_
23 This solution was found at
24 `How to I get the current IPython Notebook name
25 <http://stackoverflow.com/questions/12544056/how-to-i-get-the-current-ipython-notebook-name>`_.
27 The function can be called in a cell.
28 The variable ``theNotebook`` will be available in the next cells.
30 Try function @see fn store_notebook_path if this one does not work.
31 """
32 from IPython.core.display import display as jdisp # pylint: disable=E0611
34 code = """var kernel = IPython.notebook.kernel;
35 var body = document.body, attribs = body.attributes;
36 var command = "__NAME__ = " + "'"+attribs['data-notebook-name'].value+"'";
37 kernel.execute(command);""".replace(" ", "").replace("__NAME__", name)
39 def get_name():
40 "return name"
41 j = Javascript(code)
42 if display:
43 jdisp(j)
44 return j
45 return get_name()
48def _add_notebook_menu_js():
49 return """
50 function repeat_indent_string(n){
51 var a = "" ;
52 for ( ; n > 0 ; --n)
53 a += " ";
54 return a;
55 }
56 // look up into all sections and builds an automated menu //
57 var update_menu_string = function(begin, lfirst, llast, sformat, send, keep_item, begin_format, end_format) {
58 var anchors = document.getElementsByClassName("section");
59 if (anchors.length == 0) {
60 anchors = document.getElementsByClassName("text_cell_render rendered_html");
61 }
62 var i,t;
63 var text_menu = begin;
64 var text_memo = "<pre>\\nlength:" + anchors.length + "\\n";
65 var ind = "";
66 var memo_level = 1;
67 var href;
68 var tags = [];
69 var main_item = 0;
70 var format_open = 0;
71 for (i = 0; i <= llast; i++)
72 tags.push("h" + i);
74 for (i = 0; i < anchors.length; i++) {
75 text_memo += "**" + anchors[i].id + "--\\n";
77 var child = null;
78 for(t = 0; t < tags.length; t++) {
79 var r = anchors[i].getElementsByTagName(tags[t]);
80 if (r.length > 0) {
81 child = r[0];
82 break;
83 }
84 }
85 if (child == null) {
86 text_memo += "null\\n";
87 continue;
88 }
89 if (anchors[i].hasAttribute("id")) {
90 // when converted in RST
91 href = anchors[i].id;
92 text_memo += "#1-" + href;
93 // passer à child suivant (le chercher)
94 }
95 else if (child.hasAttribute("id")) {
96 // in a notebook
97 href = child.id;
98 text_memo += "#2-" + href;
99 }
100 else {
101 text_memo += "#3-" + "*" + "\\n";
102 continue;
103 }
104 var title = child.textContent;
105 var level = parseInt(child.tagName.substring(1,2));
107 text_memo += "--" + level + "?" + lfirst + "--" + title + "\\n";
109 if ((level < lfirst) || (level > llast)) {
110 continue ;
111 }
112 if (title.endsWith('¶')) {
113 title = title.substring(0,title.length-1).replace("<", "<")
114 .replace(">", ">").replace("&", "&");
115 }
116 if (title.length == 0) {
117 continue;
118 }
120 while (level < memo_level) {
121 text_menu += end_format + "</ul>\\n";
122 format_open -= 1;
123 memo_level -= 1;
124 }
125 if (level == lfirst) {
126 main_item += 1;
127 }
128 if (keep_item != -1 && main_item != keep_item + 1) {
129 // alert(main_item + " - " + level + " - " + keep_item);
130 continue;
131 }
132 while (level > memo_level) {
133 text_menu += "<ul>\\n";
134 memo_level += 1;
135 }
136 text_menu += repeat_indent_string(level-2);
137 text_menu += begin_format + sformat.replace("__HREF__", href).replace("__TITLE__", title);
138 format_open += 1;
139 }
140 while (1 < memo_level) {
141 text_menu += end_format + "</ul>\\n";
142 memo_level -= 1;
143 format_open -= 1;
144 }
145 text_menu += send;
146 //text_menu += "\\n" + text_memo;
148 while (format_open > 0) {
149 text_menu += end_format;
150 format_open -= 1;
151 }
152 return text_menu;
153 };
154 var update_menu = function() {
155 var sbegin = "__BEGIN__";
156 var sformat = __FORMAT__;
157 var send = "__END__";
158 var begin_format = __BEGIN_FORMAT__;
159 var end_format = __END_FORMAT__;
160 var keep_item = __KEEP_ITEM__;
161 var text_menu = update_menu_string(sbegin, __FIRST__, __LAST__, sformat, send, keep_item,
162 begin_format, end_format);
163 var menu = document.getElementById("__MENUID__");
164 menu.innerHTML=text_menu;
165 };
166 window.setTimeout(update_menu,2000);
167 """
170def add_notebook_menu(menu_id="my_id_menu_nb", raw=False, format="html", header=None,
171 first_level=2, last_level=4, keep_item=None):
172 """
173 Adds :epkg:`javascript` and :epkg:`HTML` to the notebook
174 which gathers all in the notebook and builds a menu.
176 @param menu_id menu_id
177 @param raw raw HTML and Javascript
178 @param format *html* or *rst*
179 @param header title of the menu (None for None)
180 @param first_level first level to consider
181 @param last_level last level to consider
182 @param keep_item None or integer (starts at 0), reduce the number of displayed items to 1
183 and its descendant
184 @return HTML object
186 In a notebook, it is easier to do by using a magic command
187 ``%%html`` for the HTML and another one
188 ``%%javascript`` for the Javascript.
189 This function returns a full text with :epkg:`HTML` and
190 :epkg:`javascript`.
192 If the format is :epkg:`RST`, the menu can be copied/pasted in a text cell.
194 On the notebook, the instruction would work::
196 var anchors = document.getElementsByClassName("anchor-link");
198 But it fails during the conversion from a notebook to format RST.
199 """
200 if keep_item is not None:
201 menu_id += str(keep_item)
202 html = f'<div id="{menu_id}">run previous cell, wait for 2 seconds</div>'
204 add_notebook_menu_js = _add_notebook_menu_js()
205 js = add_notebook_menu_js.replace(" ", "") \
206 .replace("__MENUID__", menu_id) \
207 .replace("__FIRST__", str(first_level)) \
208 .replace("__LAST__", str(last_level))
210 full = f"{html}\n<script>{js}</script>"
211 if keep_item is None:
212 keep_item = -1
214 if format == "html":
215 if header is not None and len(header) > 0:
216 header = f"<b>{header}</b>\n"
217 else:
218 header = ""
219 full = header + \
220 full.replace("__FORMAT__", """'<a href="#__HREF__">__TITLE__</a>'""") \
221 .replace("__BEGIN__", "") \
222 .replace("__END__", "") \
223 .replace("__KEEP_ITEM__", str(keep_item)) \
224 .replace("__BEGIN_FORMAT__", "'<li>'") \
225 .replace("__END_FORMAT__", "'</li>'")
226 elif format == "rst":
227 if header is not None and len(header) > 0:
228 header = f"{header}\n\n"
229 else:
230 header = ""
231 full = header + \
232 full.replace("__FORMAT__", """'* [' + title + '](#' + href + ')\\n'""") \
233 .replace("<ul>", "") \
234 .replace("</ul>", "") \
235 .replace("__BEGIN__", "<pre>\\n") \
236 .replace("__END__", "</pre>\\n") \
237 .replace("__KEEP_ITEM__", str(keep_item)) \
238 .replace("__BEGIN_FORMAT__", "") \
239 .replace("__END_FORMAT__", "")
240 else:
241 raise ValueError("format must be html or rst")
243 if raw:
244 return full
245 else:
246 return HTML(full)
249def load_extension(name):
250 """
251 install an extension, checks first it exists,
252 if not displays an exception with the list of them
254 @param name extension name
255 """
256 return Javascript(f"IPython.utils.load_extensions('{name}')")