|
// leave at least 2 line with only a star on it below, or doc generation fails |
|
/** |
|
* |
|
* |
|
* Placeholder for custom user javascript |
|
* mainly to be overridden in profile/static/custom/custom.js |
|
* This will always be an empty file in IPython |
|
* |
|
* User could add any javascript in the `profile/static/custom/custom.js` file |
|
* (and should create it if it does not exist). |
|
* It will be executed by the ipython notebook at load time. |
|
* |
|
* Same thing with `profile/static/custom/custom.css` to inject custom css into the notebook. |
|
* |
|
* Classes and functions are available at load time and may be accessed plainly: |
|
* |
|
* IPython.Cell.options_default.cm_config.extraKeys['Home'] = 'goLineLeft'; |
|
* IPython.Cell.options_default.cm_config.extraKeys['End'] = 'goLineRight'; |
|
* |
|
* Instances are created later however and must be accessed using events: |
|
* require([ |
|
* 'base/js/namespace', |
|
* 'base/js/events' |
|
* ], function(IPython, events) { |
|
* events.on("app_initialized.NotebookApp", function () { |
|
* IPython.keyboard_manager.... |
|
* }); |
|
* }); |
|
* |
|
* __Example 1:__ |
|
* |
|
* Create a custom button in toolbar that execute `%qtconsole` in kernel |
|
* and hence open a qtconsole attached to the same kernel as the current notebook |
|
* |
|
* require([ |
|
* 'base/js/namespace', |
|
* 'base/js/events' |
|
* ], function(IPython, events) { |
|
* events.on('app_initialized.NotebookApp', function(){ |
|
* IPython.toolbar.add_buttons_group([ |
|
* { |
|
* 'label' : 'run qtconsole', |
|
* 'icon' : 'icon-terminal', // select your icon from http://fortawesome.github.io/Font-Awesome/icons |
|
* 'callback': function () { |
|
* IPython.notebook.kernel.execute('%qtconsole') |
|
* } |
|
* } |
|
* // add more button here if needed. |
|
* ]); |
|
* }); |
|
* }); |
|
* |
|
* __Example 2:__ |
|
* |
|
* At the completion of the dashboard loading, load an unofficial javascript extension |
|
* that is installed in profile/static/custom/ |
|
* |
|
* require([ |
|
* 'base/js/events' |
|
* ], function(events) { |
|
* events.on('app_initialized.DashboardApp', function(){ |
|
* require(['custom/unofficial_extension.js']) |
|
* }); |
|
* }); |
|
* |
|
* __Example 3:__ |
|
* |
|
* Use `jQuery.getScript(url [, success(script, textStatus, jqXHR)] );` |
|
* to load custom script into the notebook. |
|
* |
|
* // to load the metadata ui extension example. |
|
* $.getScript('/static/notebook/js/celltoolbarpresets/example.js'); |
|
* // or |
|
* // to load the metadata ui extension to control slideshow mode / reveal js for nbconvert |
|
* $.getScript('/static/notebook/js/celltoolbarpresets/slideshow.js'); |
|
* |
|
* |
|
* @module IPython |
|
* @namespace IPython |
|
* @class customjs |
|
* @static |
|
*/ |
|
|
|
|
|
// events: grep -ohrE "events.trigger\('[^']+" | grep -Eo "[^']+$" | sort -u |
|
|
|
require([ |
|
'custom/he', |
|
'base/js/namespace', |
|
'base/js/events', |
|
'jquery' |
|
], function(he,IPython,events,$){ |
|
|
|
events.on("notebook_loaded.Notebook", function () { |
|
|
|
$('body').on('keydown.wysiwyg', function(e){ |
|
if ($(this).find('.selected.rendered').length && wysiwyg_enabled && e.keyCode === 13) { |
|
|
|
if ($(this).find('.selected.rendered .text_cell_render.rendered_html[contenteditable!=true]').length) { |
|
console.log('blocking Ctrl+Entr'); |
|
$(this) |
|
.find('.selected .text_cell_render.rendered_html') |
|
.attr('contenteditable', 'true') |
|
.focus(); |
|
$(this) |
|
.find('.MathJax,.MathJax_Preview,.MathJax_Display,.anchor-link') |
|
.attr('contenteditable', 'false'); |
|
$(this) |
|
.find('div.cell.selected') |
|
.addClass('wysiwyg_edit_mode'); |
|
IPython.keyboard_manager.enabled = false; |
|
return false; |
|
} |
|
return true; |
|
} else { |
|
return true; |
|
} |
|
}); |
|
|
|
$('body').on('click.wysiwyg', '.text_cell_render.rendered_html', function(e){ |
|
if (wysiwyg_enabled) { |
|
$(this) |
|
.attr('contenteditable', 'true'); |
|
$(this) |
|
.find('.MathJax,.MathJax_Preview,.MathJax_Display,.anchor-link') |
|
.attr('contenteditable', 'false'); |
|
$(this) |
|
.closest('div.cell.selected') |
|
.addClass('wysiwyg_edit_mode'); |
|
} else { |
|
return true; |
|
} |
|
}); |
|
|
|
$('body').on('blur.wysiwyg', '.text_cell_render.rendered_html', function(e){ |
|
if (wysiwyg_enabled) { |
|
$(this) |
|
.attr('contenteditable', 'false'); |
|
$(this) |
|
.closest('div.cell') |
|
.removeClass('wysiwyg_edit_mode'); |
|
return false; |
|
} else { |
|
return true; |
|
} |
|
}); |
|
|
|
var onKeys = function(e){ |
|
$edit = $(e.target); |
|
if ($edit.attr('contenteditable') == 'true' && wysiwyg_enabled) { |
|
|
|
IPython.keyboard_manager.enabled = false; |
|
// helpfully this is restored to true immediately after editing... |
|
|
|
//~ // re-evaluate the raw markdown in this cell |
|
//~ if (e.type === 'keydown' && e.ctrlKey && e.keyCode === 13) { |
|
//~ reformat.apply(this); |
|
//~ IPython.notebook.execute_cell(); |
|
//~ } |
|
// edit raw markdown |
|
if (e.type === 'keydown' && e.ctrlKey && e.keyCode === 13) { |
|
console.log('edit mode?'); |
|
reformat.apply(this); |
|
$(this) |
|
.attr('contenteditable','false'); |
|
$(this) |
|
.closest('div.cell.selected') |
|
.removeClass('wysiwyg_edit_mode'); |
|
IPython.notebook.edit_mode(); |
|
return false; |
|
} |
|
// evaluate cell and insert new below |
|
else if (e.type === 'keydown' && e.altKey && e.keyCode === 13) { |
|
reformat.apply(this); |
|
IPython.notebook.execute_cell_and_insert_below(); |
|
IPython.notebook.to_markdown(); |
|
IPython.notebook.execute_cell(); |
|
return false; |
|
} |
|
// save notebook |
|
else if (e.type === 'keydown' && e.ctrlKey && e.keyCode === 83) { |
|
IPython.notebook.save_notebook(); |
|
return false; |
|
} |
|
// leave edit mode |
|
else if (e.keyCode === 27) { |
|
console.log('leave edit'); |
|
$(this) |
|
.attr('contenteditable','false'); |
|
$(this) |
|
.closest('div.cell.selected') |
|
.removeClass('wysiwyg_edit_mode'); |
|
return false; |
|
} |
|
} else { |
|
IPython.keyboard_manager.enabled = true; |
|
console.log('skip'); |
|
return true; |
|
} |
|
}; |
|
|
|
var wysiwyg_enabled = false; |
|
var distraction_enabled = false; |
|
|
|
// add menu items option |
|
$('#view_menu').append('<li id="toggle_distraction" title="Enable/disable distraction-free notebook style"><a href="#">Toggle Distraction-Free</a></li>'); |
|
$('#edit_menu').append('<li class="divider"></li>').append('<li id="toggle_wysiwyg" title="Enable/disable WYSIWYG markdown mode"><a href="#">Enable WYSIWYG editing</a></li>'); |
|
|
|
// bind wysiwyg action |
|
$('#toggle_wysiwyg').click(function(){ |
|
if (wysiwyg_enabled) { |
|
wysiwyg_enabled = false; |
|
$(this).find('a').text('Enable WYSIWYG editing'); |
|
$('body') |
|
.off('keydown.wysiwyg', '.text_cell_render.rendered_html'); |
|
} else { |
|
/** Are you sure? **/ |
|
IPython.dialog.modal({ |
|
title: "Enable WYSIWYG markdown editing?", |
|
body: $("<p><strong>Warning:</strong> WYWSIWYG markdown editing is unstable and will destroy many advanced elements including <em>MathJax</em>, <em>headings</em>, <em>everything else</em></p><p>Do you wish to continue?</p>"), |
|
buttons: { |
|
'No': { |
|
class: 'btn-primary' |
|
}, |
|
'Yes': { |
|
class: 'btn-warning', |
|
click: function(){ |
|
wysiwyg_enabled = true; |
|
$(this).find('a').text('Disable WYSIWYG editing'); |
|
// make editable, attach keyboard shortcuts |
|
$('body') |
|
.on('keydown.wysiwyg', '.text_cell_render.rendered_html', onKeys); |
|
} |
|
} |
|
}, |
|
notebook: IPython.ntoebook, |
|
keyboard_manager: IPython.keyboard_manager |
|
}); |
|
} |
|
}); |
|
|
|
// bind distraction action |
|
$('#toggle_distraction').click(function(){ |
|
if (distraction_enabled) { |
|
distraction_enabled = false; |
|
$('#header-container').show(); |
|
$('.header-bar').show(); |
|
$('div#maintoolbar').show(); |
|
IPython.menubar._size_header(); |
|
} else { |
|
distraction_enabled = true; |
|
$('#header-container').hide(); |
|
$('.header-bar').hide(); |
|
$('div#maintoolbar').hide(); |
|
IPython.menubar._size_header(); |
|
} |
|
}); |
|
|
|
|
|
function getDisplayType (element) { |
|
var cStyle = element.currentStyle || window.getComputedStyle(element, ""); |
|
return cStyle.display; |
|
} |
|
var reformat = function(e){ |
|
|
|
//console.log($(this).parent().find('.CodeMirror')[0].CodeMirror.getDoc()); |
|
|
|
var CM = $(this).parent().find('.CodeMirror')[0].CodeMirror; |
|
|
|
//console.log(e); |
|
//console.log(this); |
|
// replace b,i |
|
$(this).find('b').replaceWith(function(){ |
|
return $("<strong />").append($(this).contents()); |
|
}); |
|
$(this).find('i').replaceWith(function(){ |
|
return $("<em />").append($(this).contents()); |
|
}); |
|
|
|
// replace divs |
|
$(this).find('div').replaceWith(function(){ |
|
return $('<p>'+$(this).html()+'</p>'); |
|
}); |
|
|
|
// wrap contiguous inline regions |
|
var to_wrap = []; |
|
$(this).contents().each(function(){ |
|
if (this.nodeType === 3) { |
|
to_wrap.push(this); |
|
} else if (getDisplayType(this) === 'inline') { |
|
to_wrap.push(this); |
|
} else { |
|
if (to_wrap.length > 0) |
|
$(to_wrap).wrapAll('<p>'); |
|
to_wrap = []; |
|
} |
|
}); |
|
if (to_wrap.length > 0) |
|
$(to_wrap).wrapAll('<p>'); |
|
|
|
// delete empty |
|
$(this).contents() |
|
.filter(function(){return $.trim(this.innerHTML) === ""}) |
|
.remove(); |
|
|
|
// delete unstyled |
|
$(this).find('span, div').not('[class]').replaceWith(function(){ |
|
return $(this).contents(); |
|
}); |
|
|
|
// update source-views |
|
//$('.source').text($('.document').html()); |
|
//$('.markdown').text(toMarkdown($('.document').html())); |
|
//console.log(toMarkdown($(this).html())); |
|
|
|
/** IPython notebook fixes **/ |
|
// remove heading ids |
|
$(this).find('h1,h2,h3,h4,h5,h6') |
|
.removeAttr('id'); |
|
// remove heading anchors |
|
$(this).find('h1,h2,h3,h4,h5,h6').find('.anchor-link') |
|
.remove(); |
|
// remove mathjax |
|
$(this).find('.MathJax,.MathJax_Preview,.MathJax_Display') |
|
.remove(); |
|
// restore inline maths |
|
$(this).find('script[type="math/tex"]') |
|
.replaceWith(function(){return '$'+$(this).text()+'$';}); |
|
// restore display maths |
|
$(this).find('script[type="math/tex; mode=display"]') |
|
.replaceWith(function(){return '$$'+$(this).text()+'$$';}); |
|
|
|
CM.getDoc().setValue(toMarkdown($(this).html())); |
|
|
|
}; |
|
|
|
|
|
$.getScript('/static/custom/to-markdown.js').done(function(d){ |
|
|
|
$('body').on('input','[contenteditable]',reformat); |
|
|
|
events.on("command_mode.Cell", function (e) { |
|
//console.log(e); |
|
}); |
|
|
|
}).fail(function(a,b,c){ |
|
console.log('Failed to load SJIM.'); |
|
}); |
|
|
|
$('head').append('<style>div.cell.selected.wysiwyg_edit_mode{border-color:green;}</style>'); |
|
|
|
$('#toggle_wysiwyg,#toggle_distraction').click(); |
|
|
|
// catch all new cells and make markdown as default? |
|
events.on("create.Cell", function (e) { |
|
if (distraction_enabled) { |
|
// problem: create happens before selection moves |
|
// and 'event' doesn't point to the created :-( |
|
// solution: wait until re-selection has happened? |
|
// -- not elegant |
|
setTimeout(function(){ |
|
//console.log($('.selected')); |
|
if ($('.selected .rendered_html').length == 0) { |
|
//console.log('to_markdown'); |
|
IPython.notebook.to_markdown(); |
|
IPython.notebook.execute_cell(); |
|
} |
|
if ($('.selected.unrendered').length) { |
|
//console.log('execute_cell'); |
|
} |
|
//IPython.notebook.to_markdown(); |
|
//IPython.notebook.execute_cell(); |
|
},200); |
|
} |
|
}); |
|
|
|
}); |
|
}); |