dialog.js
212 lines
| 7.2 KiB
| application/javascript
|
JavascriptLexer
Jonathan Frederic
|
r17189 | // Copyright (c) IPython Development Team. | ||
// Distributed under the terms of the Modified BSD License. | ||||
MinRK
|
r10903 | |||
Matthias Bussonnier
|
r19982 | define(function(require) { | ||
Matthias BUSSONNIER
|
r12103 | "use strict"; | ||
Matthias Bussonnier
|
r19982 | |||
var CodeMirror = require('codemirror/lib/codemirror'); | ||||
var IPython = require('base/js/namespace'); | ||||
var $ = require('jquery'); | ||||
MinRK
|
r10903 | |||
Bussonnier Matthias
|
r20031 | /** | ||
* A wrapper around bootstrap modal for easier use | ||||
* Pass it an option dictionary with the following properties: | ||||
* | ||||
* - body : <string> or <DOM node>, main content of the dialog | ||||
* if pass a <string> it will be wrapped in a p tag and | ||||
* html element escaped, unless you specify sanitize=false | ||||
* option. | ||||
* - title : Dialog title, default to empty string. | ||||
* - buttons : dict of btn_options who keys are button label. | ||||
* see btn_options below for description | ||||
* - open : callback to trigger on dialog open. | ||||
* - destroy: | ||||
* - notebook : notebook instance | ||||
* - keyboard_manager: keyboard manager instance. | ||||
* | ||||
* Unlike bootstrap modals, the backdrop options is set by default | ||||
* to 'static'. | ||||
* | ||||
* The rest of the options are passed as is to bootstrap modals. | ||||
* | ||||
* btn_options: dict with the following property: | ||||
* | ||||
* - click : callback to trigger on click | ||||
* - class : css classes to add to button. | ||||
* | ||||
* | ||||
* | ||||
**/ | ||||
Jonathan Frederic
|
r17212 | var modal = function (options) { | ||
jon
|
r16933 | var modal = $("<div/>") | ||
.addClass("modal") | ||||
.addClass("fade") | ||||
.attr("role", "dialog"); | ||||
var dialog = $("<div/>") | ||||
.addClass("modal-dialog") | ||||
.appendTo(modal); | ||||
var dialog_content = $("<div/>") | ||||
.addClass("modal-content") | ||||
.appendTo(dialog); | ||||
Bussonnier Matthias
|
r20031 | if(typeof(options.body) === 'string' && options.sanitize !== false){ | ||
Matthias Bussonnier
|
r19982 | options.body = $("<p/>").text(options.body) | ||
} | ||||
jon
|
r16933 | dialog_content.append( | ||
MinRK
|
r10903 | $("<div/>") | ||
.addClass("modal-header") | ||||
.append($("<button>") | ||||
jon
|
r16933 | .attr("type", "button") | ||
MinRK
|
r10903 | .addClass("close") | ||
.attr("data-dismiss", "modal") | ||||
jon
|
r16933 | .attr("aria-hidden", "true") | ||
MinRK
|
r10903 | .html("×") | ||
).append( | ||||
jon
|
r16933 | $("<h4/>") | ||
.addClass('modal-title') | ||||
Bussonnier Matthias
|
r20031 | .text(options.title || "") | ||
MinRK
|
r10903 | ) | ||
).append( | ||||
$("<div/>").addClass("modal-body").append( | ||||
options.body || $("<p/>") | ||||
) | ||||
); | ||||
var footer = $("<div/>").addClass("modal-footer"); | ||||
for (var label in options.buttons) { | ||||
var btn_opts = options.buttons[label]; | ||||
var button = $("<button/>") | ||||
Jonathan Frederic
|
r16970 | .addClass("btn btn-default btn-sm") | ||
MinRK
|
r10903 | .attr("data-dismiss", "modal") | ||
.text(label); | ||||
if (btn_opts.click) { | ||||
jon
|
r16933 | button.click($.proxy(btn_opts.click, dialog_content)); | ||
MinRK
|
r10903 | } | ||
if (btn_opts.class) { | ||||
button.addClass(btn_opts.class); | ||||
} | ||||
footer.append(button); | ||||
} | ||||
jon
|
r16933 | dialog_content.append(footer); | ||
MinRK
|
r10903 | // hook up on-open event | ||
Jonathan Frederic
|
r16955 | modal.on("shown.bs.modal", function() { | ||
MinRK
|
r10903 | setTimeout(function() { | ||
footer.find("button").last().focus(); | ||||
if (options.open) { | ||||
jon
|
r16933 | $.proxy(options.open, modal)(); | ||
MinRK
|
r10903 | } | ||
}, 0); | ||||
}); | ||||
jon
|
r16933 | // destroy modal on hide, unless explicitly asked not to | ||
MinRK
|
r12872 | if (options.destroy === undefined || options.destroy) { | ||
Jonathan Frederic
|
r16955 | modal.on("hidden.bs.modal", function () { | ||
jon
|
r16933 | modal.remove(); | ||
MinRK
|
r10903 | }); | ||
} | ||||
Jonathan Frederic
|
r16955 | modal.on("hidden.bs.modal", function () { | ||
Jonathan Frederic
|
r17212 | if (options.notebook) { | ||
var cell = options.notebook.get_selected_cell(); | ||||
Brian E. Granger
|
r14020 | if (cell) cell.select(); | ||
Jonathan Frederic
|
r17213 | } | ||
if (options.keyboard_manager) { | ||||
options.keyboard_manager.enable(); | ||||
options.keyboard_manager.command_mode(); | ||||
Brian E. Granger
|
r14020 | } | ||
}); | ||||
Jonathan Frederic
|
r17212 | if (options.keyboard_manager) { | ||
options.keyboard_manager.disable(); | ||||
MinRK
|
r11439 | } | ||
Matthias Bussonnier
|
r19875 | |||
options.backdrop = options.backdrop || 'static'; | ||||
MinRK
|
r10903 | |||
jon
|
r16933 | return modal.modal(options); | ||
MinRK
|
r12872 | }; | ||
Jessica B. Hamrick
|
r18237 | var kernel_modal = function (options) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* only one kernel dialog should be open at a time -- but | ||||
* other modal dialogs can still be open | ||||
*/ | ||||
Jessica B. Hamrick
|
r18237 | $('.kernel-modal').modal('hide'); | ||
var dialog = modal(options); | ||||
dialog.addClass('kernel-modal'); | ||||
return dialog; | ||||
}; | ||||
Jonathan Frederic
|
r17214 | var edit_metadata = function (options) { | ||
options.name = options.name || "Cell"; | ||||
MinRK
|
r12872 | var error_div = $('<div/>').css('color', 'red'); | ||
var message = | ||||
Jonathan Frederic
|
r17214 | "Manually edit the JSON below to manipulate the metadata for this " + options.name + "." + | ||
MinRK
|
r12872 | " We recommend putting custom metadata attributes in an appropriately named sub-structure," + | ||
" so they don't conflict with those of others."; | ||||
var textarea = $('<textarea/>') | ||||
.attr('rows', '13') | ||||
.attr('cols', '80') | ||||
.attr('name', 'metadata') | ||||
Jonathan Frederic
|
r17214 | .text(JSON.stringify(options.md || {}, null, 2)); | ||
MinRK
|
r12872 | |||
var dialogform = $('<div/>').attr('title', 'Edit the metadata') | ||||
.append( | ||||
$('<form/>').append( | ||||
$('<fieldset/>').append( | ||||
$('<label/>') | ||||
.attr('for','metadata') | ||||
.text(message) | ||||
) | ||||
.append(error_div) | ||||
.append($('<br/>')) | ||||
.append(textarea) | ||||
) | ||||
); | ||||
var editor = CodeMirror.fromTextArea(textarea[0], { | ||||
lineNumbers: true, | ||||
matchBrackets: true, | ||||
indentUnit: 2, | ||||
autoIndent: true, | ||||
mode: 'application/json', | ||||
}); | ||||
MinRK
|
r17284 | var modal_obj = modal({ | ||
Jonathan Frederic
|
r17214 | title: "Edit " + options.name + " Metadata", | ||
MinRK
|
r12872 | body: dialogform, | ||
buttons: { | ||||
OK: { class : "btn-primary", | ||||
click: function() { | ||||
Jonathan Frederic
|
r19176 | /** | ||
* validate json and set it | ||||
*/ | ||||
MinRK
|
r12872 | var new_md; | ||
try { | ||||
new_md = JSON.parse(editor.getValue()); | ||||
} catch(e) { | ||||
console.log(e); | ||||
error_div.text('WARNING: Could not save invalid JSON.'); | ||||
return false; | ||||
} | ||||
Jonathan Frederic
|
r17214 | options.callback(new_md); | ||
MinRK
|
r12872 | } | ||
}, | ||||
Cancel: {} | ||||
Jonathan Frederic
|
r17214 | }, | ||
notebook: options.notebook, | ||||
keyboard_manager: options.keyboard_manager, | ||||
}); | ||||
Jonathan Frederic
|
r16957 | |||
MinRK
|
r17284 | modal_obj.on('shown.bs.modal', function(){ editor.refresh(); }); | ||
MinRK
|
r12872 | }; | ||
MinRK
|
r10903 | |||
Jonathan Frederic
|
r17204 | var dialog = { | ||
MinRK
|
r10903 | modal : modal, | ||
Jessica B. Hamrick
|
r18237 | kernel_modal : kernel_modal, | ||
MinRK
|
r12872 | edit_metadata : edit_metadata, | ||
MinRK
|
r10903 | }; | ||
Jonathan Frederic
|
r17189 | // Backwards compatability. | ||
Jonathan Frederic
|
r17214 | IPython.dialog = dialog; | ||
Jonathan Frederic
|
r17189 | |||
Jonathan Frederic
|
r17204 | return dialog; | ||
Jonathan Frederic
|
r17189 | }); | ||