define([ "require", "jquery", "base/js/namespace", "./snippets_submenu_python", "./snippets_submenu_markdown", ], function (requirejs, $, Jupyter, python, markdown) { "use strict"; var mod_name = 'snippets_menu'; var mod_log_prefix = mod_name + '[' + mod_name + ']'; var python_menus = [ python.numpy, python.scipy, python.matplotlib, python.sympy, python.pandas, python.astropy, python.h5py, python.numba, python.python, ]; var default_menus = [ { 'name' : 'Snippets', 'sub-menu-direction' : 'left', 'sub-menu' : python_menus.concat([markdown]), }, ]; var options = { sibling: undefined, // if undefined, set by cfg.sibling_selector menus : [], hooks: { pre_config: undefined, post_config: undefined, } }; var includable_submenu_keys = [ "numpy", "scipy", "matplotlib", "sympy", "pandas", "astropy", "h5py", "numba", "python", "markdown", ]; // default parameters var cfg = { insert_as_new_cell: false, insert_before_sibling: false, include_custom_menu: false, include_submenu: {}, // default set after this definition sibling_selector: '#help_menu', top_level_submenu_goes_left: true, // The default has to be included here as well as config.yaml // because the configurator will not store the default given // in config.yaml unless it is changed. That means that this // should be kept up-to-date with whatever goes in // config.yaml. custom_menu_content: JSON.stringify({ "name" : "My favorites", "sub-menu" : [{ "name" : "Menu item text", "snippet" : [ "import something", "", "new_command(3.14)", "other_new_code_on_new_line('with a string!')", "stringy(\"if you need them, escape double quotes with a single backslash\")", "backslashy('This \\ appears as just one backslash in the output')", "backslashy2('Here \\\\ are two backslashes')" ]}, { "name" : "TeX can be written in menu labels $\\alpha_W e\\int_0 \\mu \\epsilon$", "snippet" : [ "another_new_command(2.78)" ] } ] }) }; for (var ii=0; ii< includable_submenu_keys.length; ii++) { cfg.include_submenu[includable_submenu_keys[ii]] = true; } function config_loaded_callback () { if (options['pre_config_hook'] !== undefined) { options['pre_config_hook'](); } // true => deep cfg = $.extend(true, cfg, Jupyter.notebook.config.data.snippets); if (cfg.insert_as_new_cell) { console.log(mod_log_prefix, "Insertions will insert new cell"); } // If `options.menus` had elements added in custom.js, skip all of this and ignore all remaining options if (options.menus.length > 0) { console.log(mod_log_prefix, '`options.menus` was created in custom.js; skipping all other configuration.'); } else { options.menus = [ { 'name' : 'Snippets', 'sub-menu-direction' : cfg.top_level_submenu_goes_left ? 'left' : 'right', 'sub-menu' : [], }, ]; if (cfg.include_custom_menu) { var custom_menu_content = JSON.parse(cfg.custom_menu_content); console.log(mod_log_prefix, "Inserting custom", custom_menu_content.name, "sub-menu"); options.menus[0]['sub-menu'].push(custom_menu_content); } for (var ii=0; ii < includable_submenu_keys.length; ii++) { var key = includable_submenu_keys[ii]; if (cfg.include_submenu[key]) { console.log(mod_log_prefix, "Inserting default", key, "sub-menu"); options.menus[0]['sub-menu'].push(key === "markdown" ? markdown : python[key]); } } } if (options.hooks.post_config !== undefined) { options.hooks.post_config(); } // select correct sibling if (options.sibling === undefined) { options.sibling = $(cfg.sibling_selector).parent(); if (options.sibling.length < 1) { options.sibling = $("#help_menu").parent(); } } } function insert_snippet_code (snippet_code) { if (cfg.insert_as_new_cell) { var new_cell = Jupyter.notebook.insert_cell_above('code'); new_cell.set_text(snippet_code); new_cell.focus_cell(); } else { var selected_cell = Jupyter.notebook.get_selected_cell(); Jupyter.notebook.edit_mode(); selected_cell.code_mirror.replaceSelection(snippet_code, 'around'); } } function callback_insert_snippet (evt) { // this (or event.currentTarget, see below) always refers to the DOM // element the listener was attached to - see // http://stackoverflow.com/questions/12077859 insert_snippet_code($(evt.currentTarget).data('snippet-code')); } function build_menu_element (menu_item_spec, direction) { // Create the menu item html element var element = $('
'); if (typeof menu_item_spec == 'string') { if (menu_item_spec != '---') { console.log(mod_log_prefix, 'Don\'t understand sub-menu string "' + menu_item_spec + '"'); return null; } return element.addClass('divider'); } var a = $('') .attr('href', '#') .html(menu_item_spec.name) .appendTo(element); if (menu_item_spec.hasOwnProperty('snippet')) { var snippet = menu_item_spec.snippet; if (typeof snippet == 'string' || snippet instanceof String) { snippet = [snippet]; } a.attr({ 'title' : "", // Do not remove this, even though it's empty! 'data-snippet-code' : snippet.join('\n'), }) .on('click', callback_insert_snippet) .addClass('snippet'); } else if (menu_item_spec.hasOwnProperty('internal-link')) { a.attr('href', menu_item_spec['internal-link']); } else if (menu_item_spec.hasOwnProperty('external-link')) { a.empty(); a.attr({ 'target' : '_blank', 'title' : 'Opens in a new window', 'href' : menu_item_spec['external-link'], }); $('').appendTo(a); $('').html(menu_item_spec.name).appendTo(a); } if (menu_item_spec.hasOwnProperty('sub-menu')) { element .addClass('dropdown-submenu') .toggleClass('dropdown-submenu-left', direction === 'left'); var sub_element = $(' ') .toggleClass('dropdown-menu-compact', menu_item_spec.overlay === true) // For space-saving menus .appendTo(element); var new_direction = (menu_item_spec['sub-menu-direction'] === 'left') ? 'left' : 'right'; for (var j=0; j