<reponame>sdpython/jyquickhelper<gh_stars>1-10
# -*- coding: utf-8 -*-
"""
@file
@brief Functions to call from the notebook
"""
from IPython.display import Javascript, HTML
from IPython.core.display import display as jdisp


def set_notebook_name_theNotebook(name="theNotebook", display=True):
    """
    This function must be called from the notebook
    you want to know the name. It relies on
    a javascript piece of code. It populates
    the variable ``theNotebook`` with the notebook name.

    @param      name        name of the variable to create
    @param      display     calls `display <http://ipython.readthedocs.io/en/stable/api/generated/
                            IPython.display.html#IPython.display.display>`_
                            or returns a javascript object
    @return                 None or `Javascript <http://ipython.readthedocs.io/en/stable/api/generated/
                            IPython.display.html#IPython.display.Javascript>`_

    This solution was found at
    `How to I get the current IPython Notebook name
    <http://stackoverflow.com/questions/12544056/how-to-i-get-the-current-ipython-notebook-name>`_.

    The function can be called in a cell.
    The variable ``theNotebook`` will be available in the next cells.

    Try function @see fn store_notebook_path if this one does not work.
    """
    code = """var kernel = IPython.notebook.kernel;
              var body = document.body, attribs = body.attributes;
              var command = "__NAME__ = " + "'"+attribs['data-notebook-name'].value+"'";
              kernel.execute(command);""".replace("              ", "").replace("__NAME__", name)

    def get_name():
        "return name"
        j = Javascript(code)
        if display:
            jdisp(j)
        return j
    return get_name()


def _add_notebook_menu_js():
    return """
                function repeat_indent_string(n){
                    var a = "" ;
                    for ( ; n > 0 ; --n)
                        a += "    ";
                    return a;
                }
                // look up into all sections and builds an automated menu //
                var update_menu_string = function(begin, lfirst, llast, sformat, send, keep_item, begin_format, end_format) {
                    var anchors = document.getElementsByClassName("section");
                    if (anchors.length == 0) {
                        anchors = document.getElementsByClassName("text_cell_render rendered_html");
                    }
                    var i,t;
                    var text_menu = begin;
                    var text_memo = "<pre>\\nlength:" + anchors.length + "\\n";
                    var ind = "";
                    var memo_level = 1;
                    var href;
                    var tags = [];
                    var main_item = 0;
                    var format_open = 0;
                    for (i = 0; i <= llast; i++)
                        tags.push("h" + i);

                    for (i = 0; i < anchors.length; i++) {
                        text_memo += "**" + anchors[i].id + "--\\n";

                        var child = null;
                        for(t = 0; t < tags.length; t++) {
                            var r = anchors[i].getElementsByTagName(tags[t]);
                            if (r.length > 0) {
                                child = r[0];
                                break;
                            }
                        }
                        if (child == null) {
                            text_memo += "null\\n";
                            continue;
                        }
                        if (anchors[i].hasAttribute("id")) {
                            // when converted in RST
                            href = anchors[i].id;
                            text_memo += "#1-" + href;
                            // passer à child suivant (le chercher)
                        }
                        else if (child.hasAttribute("id")) {
                            // in a notebook
                            href = child.id;
                            text_memo += "#2-" + href;
                        }
                        else {
                            text_memo += "#3-" + "*" + "\\n";
                            continue;
                        }
                        var title = child.textContent;
                        var level = parseInt(child.tagName.substring(1,2));

                        text_memo += "--" + level + "?" + lfirst + "--" + title + "\\n";

                        if ((level < lfirst) || (level > llast)) {
                            continue ;
                        }
                        if (title.endsWith('¶')) {
                            title = title.substring(0,title.length-1).replace("<", "&lt;")
                                         .replace(">", "&gt;").replace("&", "&amp;");
                        }
                        if (title.length == 0) {
                            continue;
                        }

                        while (level < memo_level) {
                            text_menu += end_format + "</ul>\\n";
                            format_open -= 1;
                            memo_level -= 1;
                        }
                        if (level == lfirst) {
                            main_item += 1;
                        }
                        if (keep_item != -1 && main_item != keep_item + 1) {
                            // alert(main_item + " - " + level + " - " + keep_item);
                            continue;
                        }
                        while (level > memo_level) {
                            text_menu += "<ul>\\n";
                            memo_level += 1;
                        }
                        text_menu += repeat_indent_string(level-2);
                        text_menu += begin_format + sformat.replace("__HREF__", href).replace("__TITLE__", title);
                        format_open += 1;
                    }
                    while (1 < memo_level) {
                        text_menu += end_format + "</ul>\\n";
                        memo_level -= 1;
                        format_open -= 1;
                    }
                    text_menu += send;
                    //text_menu += "\\n" + text_memo;

                    while (format_open > 0) {
                        text_menu += end_format;
                        format_open -= 1;
                    }
                    return text_menu;
                };
                var update_menu = function() {
                    var sbegin = "__BEGIN__";
                    var sformat = __FORMAT__;
                    var send = "__END__";
                    var begin_format = __BEGIN_FORMAT__;
                    var end_format = __END_FORMAT__;
                    var keep_item = __KEEP_ITEM__;
                    var text_menu = update_menu_string(sbegin, __FIRST__, __LAST__, sformat, send, keep_item,
                                                       begin_format, end_format);
                    var menu = document.getElementById("__MENUID__");
                    menu.innerHTML=text_menu;
                };
                window.setTimeout(update_menu,2000);
            """


def add_notebook_menu(menu_id="my_id_menu_nb", raw=False, format="html", header=None,
                      first_level=2, last_level=4, keep_item=None):
    """
    Adds :epkg:`javascript` and :epkg:`HTML` to the notebook
    which gathers all in the notebook and builds a menu.

    @param      menu_id         menu_id
    @param      raw             raw HTML and Javascript
    @param      format          *html* or *rst*
    @param      header          title of the menu (None for None)
    @param      first_level     first level to consider
    @param      last_level      last level to consider
    @param      keep_item       None or integer (starts at 0), reduce the number of displayed items to 1
                                and its descendant
    @return                     HTML object

    In a notebook, it is easier to do by using a magic command
    ``%%html`` for the HTML and another one
    ``%%javascript`` for the Javascript.
    This function returns a full text with :epkg:`HTML` and
    :epkg:`javascript`.

    If the format is :epkg:`RST`, the menu can be copied/pasted in a text cell.

    On the notebook, the instruction would work::

        var anchors = document.getElementsByClassName("anchor-link");

    But it fails during the conversion from a notebook to format RST.
    """
    if keep_item is not None:
        menu_id += str(keep_item)
    html = '<div id="{0}">run previous cell, wait for 2 seconds</div>'.format(
        menu_id)

    add_notebook_menu_js = _add_notebook_menu_js()
    js = add_notebook_menu_js.replace("                ", "") \
                             .replace("__MENUID__", menu_id) \
                             .replace("__FIRST__", str(first_level)) \
                             .replace("__LAST__", str(last_level))

    full = "{0}\n<script>{1}</script>".format(html, js)
    if keep_item is None:
        keep_item = -1

    if format == "html":
        if header is not None and len(header) > 0:
            header = "<b>{0}</b>\n".format(header)
        else:
            header = ""
        full = header + \
            full.replace("__FORMAT__", """'<a href="#__HREF__">__TITLE__</a>'""") \
            .replace("__BEGIN__", "") \
            .replace("__END__", "") \
            .replace("__KEEP_ITEM__", str(keep_item)) \
            .replace("__BEGIN_FORMAT__", "'<li>'") \
            .replace("__END_FORMAT__", "'</li>'")
    elif format == "rst":
        if header is not None and len(header) > 0:
            header = "{0}\n\n".format(header)
        else:
            header = ""
        full = header + \
            full.replace("__FORMAT__", """'* [' + title + '](#' + href + ')\\n'""") \
                .replace("<ul>", "") \
                .replace("</ul>", "") \
                .replace("__BEGIN__", "<pre>\\n") \
                .replace("__END__", "</pre>\\n") \
                .replace("__KEEP_ITEM__", str(keep_item)) \
                .replace("__BEGIN_FORMAT__", "") \
                .replace("__END_FORMAT__", "")
    else:
        raise ValueError("format must be html or rst")

    if raw:
        return full
    else:
        return HTML(full)


def load_extension(name):
    """
    install an extension, checks first it exists,
    if not displays an exception with the list of them

    @param      name        extension name
    """
    return Javascript("IPython.utils.load_extensions('%s')" % name)

# -*- coding: utf-8 -*-
"""
@file
@brief Functions to call from the notebook
"""
from IPython.display import Javascript, HTML
from IPython.core.display import display as jdisp


def set_notebook_name_theNotebook(name="theNotebook", display=True):
    """
    This function must be called from the notebook
    you want to know the name. It relies on
    a javascript piece of code. It populates
    the variable ``theNotebook`` with the notebook name.

    @param      name        name of the variable to create
    @param      display     calls `display <http://ipython.readthedocs.io/en/stable/api/generated/
                            IPython.display.html#IPython.display.display>`_
                            or returns a javascript object
    @return                 None or `Javascript <http://ipython.readthedocs.io/en/stable/api/generated/
                            IPython.display.html#IPython.display.Javascript>`_

    This solution was found at
    `How to I get the current IPython Notebook name
    <http://stackoverflow.com/questions/12544056/how-to-i-get-the-current-ipython-notebook-name>`_.

    The function can be called in a cell.
    The variable ``theNotebook`` will be available in the next cells.

    Try function @see fn store_notebook_path if this one does not work.
    """
    code = """var kernel = IPython.notebook.kernel;
              var body = document.body, attribs = body.attributes;
              var command = "__NAME__ = " + "'"+attribs['data-notebook-name'].value+"'";
              kernel.execute(command);""".replace("              ", "").replace("__NAME__", name)

    def get_name():
        "return name"
        j = Javascript(code)
        if display:
            jdisp(j)
        return j
    return get_name()


def _add_notebook_menu_js():
    return """
                function repeat_indent_string(n){
                    var a = "" ;
                    for ( ; n > 0 ; --n)
                        a += "    ";
                    return a;
                }
                // look up into all sections and builds an automated menu //
                var update_menu_string = function(begin, lfirst, llast, sformat, send, keep_item, begin_format, end_format) {
                    var anchors = document.getElementsByClassName("section");
                    if (anchors.length == 0) {
                        anchors = document.getElementsByClassName("text_cell_render rendered_html");
                    }
                    var i,t;
                    var text_menu = begin;
                    var text_memo = "<pre>\\nlength:" + anchors.length + "\\n";
                    var ind = "";
                    var memo_level = 1;
                    var href;
                    var tags = [];
                    var main_item = 0;
                    var format_open = 0;
                    for (i = 0; i <= llast; i++)
                        tags.push("h" + i);

                    for (i = 0; i < anchors.length; i++) {
                        text_memo += "**" + anchors[i].id + "--\\n";

                        var child = null;
                        for(t = 0; t < tags.length; t++) {
                            var r = anchors[i].getElementsByTagName(tags[t]);
                            if (r.length > 0) {
                                child = r[0];
                                break;
                            }
                        }
                        if (child == null) {
                            text_memo += "null\\n";
                            continue;
                        }
                        if (anchors[i].hasAttribute("id")) {
                            // when converted in RST
                            href = anchors[i].id;
                            text_memo += "#1-" + href;
                            // passer à child suivant (le chercher)
                        }
                        else if (child.hasAttribute("id")) {
                            // in a notebook
                            href = child.id;
                            text_memo += "#2-" + href;
                        }
                        else {
                            text_memo += "#3-" + "*" + "\\n";
                            continue;
                        }
                        var title = child.textContent;
                        var level = parseInt(child.tagName.substring(1,2));

                        text_memo += "--" + level + "?" + lfirst + "--" + title + "\\n";

                        if ((level < lfirst) || (level > llast)) {
                            continue ;
                        }
                        if (title.endsWith('¶')) {
                            title = title.substring(0,title.length-1).replace("<", "&lt;")
                                         .replace(">", "&gt;").replace("&", "&amp;");
                        }
                        if (title.length == 0) {
                            continue;
                        }

                        while (level < memo_level) {
                            text_menu += end_format + "</ul>\\n";
                            format_open -= 1;
                            memo_level -= 1;
                        }
                        if (level == lfirst) {
                            main_item += 1;
                        }
                        if (keep_item != -1 && main_item != keep_item + 1) {
                            // alert(main_item + " - " + level + " - " + keep_item);
                            continue;
                        }
                        while (level > memo_level) {
                            text_menu += "<ul>\\n";
                            memo_level += 1;
                        }
                        text_menu += repeat_indent_string(level-2);
                        text_menu += begin_format + sformat.replace("__HREF__", href).replace("__TITLE__", title);
                        format_open += 1;
                    }
                    while (1 < memo_level) {
                        text_menu += end_format + "</ul>\\n";
                        memo_level -= 1;
                        format_open -= 1;
                    }
                    text_menu += send;
                    //text_menu += "\\n" + text_memo;

                    while (format_open > 0) {
                        text_menu += end_format;
                        format_open -= 1;
                    }
                    return text_menu;
                };
                var update_menu = function() {
                    var sbegin = "__BEGIN__";
                    var sformat = __FORMAT__;
                    var send = "__END__";
                    var begin_format = __BEGIN_FORMAT__;
                    var end_format = __END_FORMAT__;
                    var keep_item = __KEEP_ITEM__;
                    var text_menu = update_menu_string(sbegin, __FIRST__, __LAST__, sformat, send, keep_item,
                                                       begin_format, end_format);
                    var menu = document.getElementById("__MENUID__");
                    menu.innerHTML=text_menu;
                };
                window.setTimeout(update_menu,2000);
            """


def add_notebook_menu(menu_id="my_id_menu_nb", raw=False, format="html", header=None,
                      first_level=2, last_level=4, keep_item=None):
    """
    Adds :epkg:`javascript` and :epkg:`HTML` to the notebook
    which gathers all in the notebook and builds a menu.

    @param      menu_id         menu_id
    @param      raw             raw HTML and Javascript
    @param      format          *html* or *rst*
    @param      header          title of the menu (None for None)
    @param      first_level     first level to consider
    @param      last_level      last level to consider
    @param      keep_item       None or integer (starts at 0), reduce the number of displayed items to 1
                                and its descendant
    @return                     HTML object

    In a notebook, it is easier to do by using a magic command
    ``%%html`` for the HTML and another one
    ``%%javascript`` for the Javascript.
    This function returns a full text with :epkg:`HTML` and
    :epkg:`javascript`.

    If the format is :epkg:`RST`, the menu can be copied/pasted in a text cell.

    On the notebook, the instruction would work::

        var anchors = document.getElementsByClassName("anchor-link");

    But it fails during the conversion from a notebook to format RST.
    """
    if keep_item is not None:
        menu_id += str(keep_item)
    html = '<div id="{0}">run previous cell, wait for 2 seconds</div>'.format(
        menu_id)

    add_notebook_menu_js = _add_notebook_menu_js()
    js = add_notebook_menu_js.replace("                ", "") \
                             .replace("__MENUID__", menu_id) \
                             .replace("__FIRST__", str(first_level)) \
                             .replace("__LAST__", str(last_level))

    full = "{0}\n<script>{1}</script>".format(html, js)
    if keep_item is None:
        keep_item = -1

    if format == "html":
        if header is not None and len(header) > 0:
            header = "<b>{0}</b>\n".format(header)
        else:
            header = ""
        full = header + \
            full.replace("__FORMAT__", """'<a href="#__HREF__">__TITLE__</a>'""") \
            .replace("__BEGIN__", "") \
            .replace("__END__", "") \
            .replace("__KEEP_ITEM__", str(keep_item)) \
            .replace("__BEGIN_FORMAT__", "'<li>'") \
            .replace("__END_FORMAT__", "'</li>'")
    elif format == "rst":
        if header is not None and len(header) > 0:
            header = "{0}\n\n".format(header)
        else:
            header = ""
        full = header + \
            full.replace("__FORMAT__", """'* [' + title + '](#' + href + ')\\n'""") \
                .replace("<ul>", "") \
                .replace("</ul>", "") \
                .replace("__BEGIN__", "<pre>\\n") \
                .replace("__END__", "</pre>\\n") \
                .replace("__KEEP_ITEM__", str(keep_item)) \
                .replace("__BEGIN_FORMAT__", "") \
                .replace("__END_FORMAT__", "")
    else:
        raise ValueError("format must be html or rst")

    if raw:
        return full
    else:
        return HTML(full)


def load_extension(name):
    """
    install an extension, checks first it exists,
    if not displays an exception with the list of them

    @param      name        extension name
    """
    return Javascript("IPython.utils.load_extensions('%s')" % name)
# -*- coding: utf-8 -*- @file @brief Functions to call from the notebook This function must be called from the notebook     you want to know the name. It relies on     a javascript piece of code. It populates     the variable ``theNotebook`` with the notebook name.      @param      name        name of the variable to create     @param      display     calls `display <http://ipython.readthedocs.io/en/stable/api/generated/                             IPython.display.html#IPython.display.display>`_                             or returns a javascript object     @return                 None or `Javascript <http://ipython.readthedocs.io/en/stable/api/generated/                             IPython.display.html#IPython.display.Javascript>`_      This solution was found at     `How to I get the current IPython Notebook name     <http://stackoverflow.com/questions/12544056/how-to-i-get-the-current-ipython-notebook-name>`_.      The function can be called in a cell.     The variable ``theNotebook`` will be available in the next cells.      Try function @see fn store_notebook_path if this one does not work. var kernel = IPython.notebook.kernel;               var body = document.body, attribs = body.attributes;               var command = "__NAME__ = " + "'"+attribs['data-notebook-name'].value+"'";               kernel.execute(command); function repeat_indent_string(n){                     var a = "" ;                     for ( ; n > 0 ; --n)                         a += "    ";                     return a;                 }                 // look up into all sections and builds an automated menu //                 var update_menu_string = function(begin, lfirst, llast, sformat, send, keep_item, begin_format, end_format) {                     var anchors = document.getElementsByClassName("section");                     if (anchors.length == 0) {                         anchors = document.getElementsByClassName("text_cell_render rendered_html");                     }                     var i,t;                     var text_menu = begin;                     var text_memo = "<pre>\\nlength:" + anchors.length + "\\n";                     var ind = "";                     var memo_level = 1;                     var href;                     var tags = [];                     var main_item = 0;                     var format_open = 0;                     for (i = 0; i <= llast; i++)                         tags.push("h" + i);                      for (i = 0; i < anchors.length; i++) {                         text_memo += "**" + anchors[i].id + "--\\n";                          var child = null;                         for(t = 0; t < tags.length; t++) {                             var r = anchors[i].getElementsByTagName(tags[t]);                             if (r.length > 0) {                                 child = r[0];                                 break;                             }                         }                         if (child == null) {                             text_memo += "null\\n";                             continue;                         }                         if (anchors[i].hasAttribute("id")) {                             // when converted in RST                             href = anchors[i].id;                             text_memo += "#1-" + href;                             // passer à child suivant (le chercher)                         }                         else if (child.hasAttribute("id")) {                             // in a notebook                             href = child.id;                             text_memo += "#2-" + href;                         }                         else {                             text_memo += "#3-" + "*" + "\\n";                             continue;                         }                         var title = child.textContent;                         var level = parseInt(child.tagName.substring(1,2));                          text_memo += "--" + level + "?" + lfirst + "--" + title + "\\n";                          if ((level < lfirst) || (level > llast)) {                             continue ;                         }                         if (title.endsWith('¶')) {                             title = title.substring(0,title.length-1).replace("<", "&lt;")                                          .replace(">", "&gt;").replace("&", "&amp;");                         }                         if (title.length == 0) {                             continue;                         }                          while (level < memo_level) {                             text_menu += end_format + "</ul>\\n";                             format_open -= 1;                             memo_level -= 1;                         }                         if (level == lfirst) {                             main_item += 1;                         }                         if (keep_item != -1 && main_item != keep_item + 1) {                             // alert(main_item + " - " + level + " - " + keep_item);                             continue;                         }                         while (level > memo_level) {                             text_menu += "<ul>\\n";                             memo_level += 1;                         }                         text_menu += repeat_indent_string(level-2);                         text_menu += begin_format + sformat.replace("__HREF__", href).replace("__TITLE__", title);                         format_open += 1;                     }                     while (1 < memo_level) {                         text_menu += end_format + "</ul>\\n";                         memo_level -= 1;                         format_open -= 1;                     }                     text_menu += send;                     //text_menu += "\\n" + text_memo;                      while (format_open > 0) {                         text_menu += end_format;                         format_open -= 1;                     }                     return text_menu;                 };                 var update_menu = function() {                     var sbegin = "__BEGIN__";                     var sformat = __FORMAT__;                     var send = "__END__";                     var begin_format = __BEGIN_FORMAT__;                     var end_format = __END_FORMAT__;                     var keep_item = __KEEP_ITEM__;                     var text_menu = update_menu_string(sbegin, __FIRST__, __LAST__, sformat, send, keep_item,                                                        begin_format, end_format);                     var menu = document.getElementById("__MENUID__");                     menu.innerHTML=text_menu;                 };                 window.setTimeout(update_menu,2000); Adds :epkg:`javascript` and :epkg:`HTML` to the notebook     which gathers all in the notebook and builds a menu.      @param      menu_id         menu_id     @param      raw             raw HTML and Javascript     @param      format          *html* or *rst*     @param      header          title of the menu (None for None)     @param      first_level     first level to consider     @param      last_level      last level to consider     @param      keep_item       None or integer (starts at 0), reduce the number of displayed items to 1                                 and its descendant     @return                     HTML object      In a notebook, it is easier to do by using a magic command     ``%%html`` for the HTML and another one     ``%%javascript`` for the Javascript.     This function returns a full text with :epkg:`HTML` and     :epkg:`javascript`.      If the format is :epkg:`RST`, the menu can be copied/pasted in a text cell.      On the notebook, the instruction would work::          var anchors = document.getElementsByClassName("anchor-link");      But it fails during the conversion from a notebook to format RST. '<a href="#__HREF__">__TITLE__</a>' '* [' + title + '](#' + href + ')\\n' install an extension, checks first it exists,     if not displays an exception with the list of them      @param      name        extension name