##// END OF EJS Templates
Merge pull request #6866 from takluyver/nb-texteditor...
Min RK -
r19078:231dfe88 merge
parent child Browse files
Show More
1 NO CONTENT: new file 100644
@@ -0,0 +1,29 b''
1 #encoding: utf-8
2 """Tornado handlers for the terminal emulator."""
3
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
6
7 from tornado import web
8 from ..base.handlers import IPythonHandler, path_regex
9 from ..utils import url_escape
10
11 class EditorHandler(IPythonHandler):
12 """Render the text editor interface."""
13 @web.authenticated
14 def get(self, path):
15 path = path.strip('/')
16 if not self.contents_manager.file_exists(path):
17 raise web.HTTPError(404, u'File does not exist: %s' % path)
18
19 basename = path.rsplit('/', 1)[-1]
20 self.write(self.render_template('edit.html',
21 file_path=url_escape(path),
22 basename=basename,
23 page_title=basename + " (editing)",
24 )
25 )
26
27 default_handlers = [
28 (r"/edit%s" % path_regex, EditorHandler),
29 ] No newline at end of file
@@ -0,0 +1,83 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 define([
5 'jquery',
6 'base/js/notificationwidget',
7 ], function($, notificationwidget) {
8 "use strict";
9
10 // store reference to the NotificationWidget class
11 var NotificationWidget = notificationwidget.NotificationWidget;
12
13 /**
14 * Construct the NotificationArea object. Options are:
15 * events: $(Events) instance
16 * save_widget: SaveWidget instance
17 * notebook: Notebook instance
18 * keyboard_manager: KeyboardManager instance
19 *
20 * @constructor
21 * @param {string} selector - a jQuery selector string for the
22 * notification area element
23 * @param {Object} [options] - a dictionary of keyword arguments.
24 */
25 var NotificationArea = function (selector, options) {
26 this.selector = selector;
27 this.events = options.events;
28 if (this.selector !== undefined) {
29 this.element = $(selector);
30 }
31 this.widget_dict = {};
32 };
33
34 /**
35 * Get a widget by name, creating it if it doesn't exist.
36 *
37 * @method widget
38 * @param {string} name - the widget name
39 */
40 NotificationArea.prototype.widget = function (name) {
41 if (this.widget_dict[name] === undefined) {
42 return this.new_notification_widget(name);
43 }
44 return this.get_widget(name);
45 };
46
47 /**
48 * Get a widget by name, throwing an error if it doesn't exist.
49 *
50 * @method get_widget
51 * @param {string} name - the widget name
52 */
53 NotificationArea.prototype.get_widget = function (name) {
54 if(this.widget_dict[name] === undefined) {
55 throw('no widgets with this name');
56 }
57 return this.widget_dict[name];
58 };
59
60 /**
61 * Create a new notification widget with the given name. The
62 * widget must not already exist.
63 *
64 * @method new_notification_widget
65 * @param {string} name - the widget name
66 */
67 NotificationArea.prototype.new_notification_widget = function (name) {
68 if (this.widget_dict[name] !== undefined) {
69 throw('widget with that name already exists!');
70 }
71
72 // create the element for the notification widget and add it
73 // to the notification aread element
74 var div = $('<div/>').attr('id', 'notification_' + name);
75 $(this.selector).append(div);
76
77 // create the widget object and return it
78 this.widget_dict[name] = new NotificationWidget('#notification_' + name);
79 return this.widget_dict[name];
80 };
81
82 return {'NotificationArea': NotificationArea};
83 });
@@ -0,0 +1,74 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 define([
5 'jquery',
6 'base/js/utils',
7 'codemirror/lib/codemirror',
8 'codemirror/mode/meta',
9 'codemirror/addon/search/search'
10 ],
11 function($,
12 utils,
13 CodeMirror
14 ) {
15 var Editor = function(selector, options) {
16 this.selector = selector;
17 this.contents = options.contents;
18 this.events = options.events;
19 this.base_url = options.base_url;
20 this.file_path = options.file_path;
21
22 this.codemirror = CodeMirror($(this.selector)[0]);
23
24 // It appears we have to set commands on the CodeMirror class, not the
25 // instance. I'd like to be wrong, but since there should only be one CM
26 // instance on the page, this is good enough for now.
27 CodeMirror.commands.save = $.proxy(this.save, this);
28
29 this.save_enabled = false;
30 };
31
32 Editor.prototype.load = function() {
33 var that = this;
34 var cm = this.codemirror;
35 this.contents.get(this.file_path, {type: 'file', format: 'text'})
36 .then(function(model) {
37 cm.setValue(model.content);
38
39 // Find and load the highlighting mode
40 var modeinfo = CodeMirror.findModeByMIME(model.mimetype);
41 if (modeinfo) {
42 utils.requireCodeMirrorMode(modeinfo.mode, function() {
43 cm.setOption('mode', modeinfo.mode);
44 });
45 }
46 that.save_enabled = true;
47 },
48 function(error) {
49 cm.setValue("Error! " + error.message +
50 "\nSaving disabled.");
51 that.save_enabled = false;
52 }
53 );
54 };
55
56 Editor.prototype.save = function() {
57 if (!this.save_enabled) {
58 console.log("Not saving, save disabled");
59 return;
60 }
61 var model = {
62 path: this.file_path,
63 type: 'file',
64 format: 'text',
65 content: this.codemirror.getValue(),
66 };
67 var that = this;
68 this.contents.save(this.file_path, model).then(function() {
69 that.events.trigger("save_succeeded.TextEditor");
70 });
71 };
72
73 return {Editor: Editor};
74 });
@@ -0,0 +1,53 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 require([
5 'base/js/namespace',
6 'base/js/utils',
7 'base/js/page',
8 'base/js/events',
9 'contents',
10 'edit/js/editor',
11 'edit/js/menubar',
12 'edit/js/notificationarea',
13 'custom/custom',
14 ], function(
15 IPython,
16 utils,
17 page,
18 events,
19 contents,
20 editor,
21 menubar,
22 notificationarea
23 ){
24 page = new page.Page();
25
26 var base_url = utils.get_body_data('baseUrl');
27 var file_path = utils.get_body_data('filePath');
28 contents = new contents.Contents({base_url: base_url});
29
30 var editor = new editor.Editor('#texteditor-container', {
31 base_url: base_url,
32 events: events,
33 contents: contents,
34 file_path: file_path,
35 });
36
37 // Make it available for debugging
38 IPython.editor = editor;
39
40 var menus = new menubar.MenuBar('#menubar', {
41 base_url: base_url,
42 editor: editor,
43 });
44
45 var notification_area = new notificationarea.EditorNotificationArea(
46 '#notification_area', {
47 events: events,
48 });
49 notification_area.init_notification_widgets();
50
51 editor.load();
52 page.show();
53 });
@@ -0,0 +1,46 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 define([
5 'base/js/namespace',
6 'jquery',
7 'base/js/utils',
8 'bootstrap',
9 ], function(IPython, $, utils, bootstrap) {
10 "use strict";
11
12 var MenuBar = function (selector, options) {
13 // Constructor
14 //
15 // A MenuBar Class to generate the menubar of IPython notebook
16 //
17 // Parameters:
18 // selector: string
19 // options: dictionary
20 // Dictionary of keyword arguments.
21 // codemirror: CodeMirror instance
22 // contents: ContentManager instance
23 // events: $(Events) instance
24 // base_url : string
25 // file_path : string
26 options = options || {};
27 this.base_url = options.base_url || utils.get_body_data("baseUrl");
28 this.selector = selector;
29 this.editor = options.editor;
30
31 if (this.selector !== undefined) {
32 this.element = $(selector);
33 this.bind_events();
34 }
35 };
36
37 MenuBar.prototype.bind_events = function () {
38 // File
39 var that = this;
40 this.element.find('#save_file').click(function () {
41 that.editor.save();
42 });
43 };
44
45 return {'MenuBar': MenuBar};
46 });
@@ -0,0 +1,29 b''
1 define([
2 'base/js/notificationarea'
3 ], function(notificationarea) {
4 "use strict";
5 var NotificationArea = notificationarea.NotificationArea;
6
7 var EditorNotificationArea = function(selector, options) {
8 NotificationArea.apply(this, [selector, options]);
9 }
10
11 EditorNotificationArea.prototype = Object.create(NotificationArea.prototype);
12
13 /**
14 * Initialize the default set of notification widgets.
15 *
16 * @method init_notification_widgets
17 */
18 EditorNotificationArea.prototype.init_notification_widgets = function () {
19 var that = this;
20 var enw = this.new_notification_widget('editor');
21
22 this.events.on("save_succeeded.TextEditor", function() {
23 enw.set_message("File saved", 2000);
24 });
25 };
26
27
28 return {EditorNotificationArea: EditorNotificationArea};
29 });
@@ -0,0 +1,72 b''
1 {% extends "page.html" %}
2
3 {% block title %}{{page_title}}{% endblock %}
4
5 {% block stylesheet %}
6 <link rel="stylesheet" href="{{ static_url('components/codemirror/lib/codemirror.css') }}">
7 <link rel="stylesheet" href="{{ static_url('components/codemirror/addon/dialog/dialog.css') }}">
8 <style>
9 #texteditor-container {
10 border-bottom: 1px solid #ccc;
11 }
12
13 #filename {
14 font-size: 16pt;
15 display: table;
16 padding: 0px 5px;
17 }
18 </style>
19
20 {{super()}}
21 {% endblock %}
22
23 {% block params %}
24
25 data-base-url="{{base_url}}"
26 data-file-path="{{file_path}}"
27
28 {% endblock %}
29
30 {% block header %}
31
32 <span id="filename">{{ basename }}</span>
33
34 {% endblock %}
35
36 {% block site %}
37
38 <div id="menubar-container" class="container">
39 <div id="menubar">
40 <div id="menus" class="navbar navbar-default" role="navigation">
41 <div class="container-fluid">
42 <button type="button" class="btn btn-default navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
43 <i class="fa fa-bars"></i>
44 <span class="navbar-text">Menu</span>
45 </button>
46 <ul class="nav navbar-nav navbar-right">
47 <li id="notification_area"></li>
48 </ul>
49 <div class="navbar-collapse collapse">
50 <ul class="nav navbar-nav">
51 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
52 <ul id="file_menu" class="dropdown-menu">
53 <li id="save_file"><a href="#">Save</a></li>
54 </ul>
55 </li>
56 </ul>
57 </div>
58 </div>
59 </div>
60 </div>
61 </div>
62
63 <div id="texteditor-container" class="container"></div>
64
65 {% endblock %}
66
67 {% block script %}
68
69 {{super()}}
70
71 <script src="{{ static_url("edit/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
72 {% endblock %}
@@ -199,6 +199,7 b' class NotebookWebApplication(web.Application):'
199 199 handlers.extend(load_handlers('notebook.handlers'))
200 200 handlers.extend(load_handlers('nbconvert.handlers'))
201 201 handlers.extend(load_handlers('kernelspecs.handlers'))
202 handlers.extend(load_handlers('edit.handlers'))
202 203 handlers.extend(load_handlers('services.config.handlers'))
203 204 handlers.extend(load_handlers('services.kernels.handlers'))
204 205 handlers.extend(load_handlers('services.contents.handlers'))
@@ -9,6 +9,7 b' import io'
9 9 import os
10 10 import shutil
11 11 from contextlib import contextmanager
12 import mimetypes
12 13
13 14 from tornado import web
14 15
@@ -204,6 +205,7 b' class FileContentsManager(ContentsManager):'
204 205 model['created'] = created
205 206 model['content'] = None
206 207 model['format'] = None
208 model['mimetype'] = None
207 209 try:
208 210 model['writable'] = os.access(os_path, os.W_OK)
209 211 except OSError:
@@ -264,8 +266,11 b' class FileContentsManager(ContentsManager):'
264 266 """
265 267 model = self._base_model(path)
266 268 model['type'] = 'file'
269
270 os_path = self._get_os_path(path)
271 model['mimetype'] = mimetypes.guess_type(os_path)[0] or 'text/plain'
272
267 273 if content:
268 os_path = self._get_os_path(path)
269 274 if not os.path.isfile(os_path):
270 275 # could be FIFO
271 276 raise web.HTTPError(400, "Cannot get content of non-file %s" % os_path)
1 NO CONTENT: file renamed from IPython/html/static/notebook/js/notificationwidget.js to IPython/html/static/base/js/notificationwidget.js
@@ -105,7 +105,7 b' require(['
105 105 save_widget: save_widget,
106 106 quick_help: quick_help},
107 107 common_options));
108 var notification_area = new notificationarea.NotificationArea(
108 var notification_area = new notificationarea.NotebookNotificationArea(
109 109 '#notification_area', {
110 110 events: events,
111 111 save_widget: save_widget,
@@ -1,97 +1,29 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3
4 1 define([
5 2 'base/js/namespace',
6 3 'jquery',
7 4 'base/js/utils',
8 5 'base/js/dialog',
9 'notebook/js/notificationwidget',
6 'base/js/notificationarea',
10 7 'moment'
11 ], function(IPython, $, utils, dialog, notificationwidget, moment) {
8 ], function(IPython, $, utils, dialog, notificationarea, moment) {
12 9 "use strict";
13
14 // store reference to the NotificationWidget class
15 var NotificationWidget = notificationwidget.NotificationWidget;
16
17 /**
18 * Construct the NotificationArea object. Options are:
19 * events: $(Events) instance
20 * save_widget: SaveWidget instance
21 * notebook: Notebook instance
22 * keyboard_manager: KeyboardManager instance
23 *
24 * @constructor
25 * @param {string} selector - a jQuery selector string for the
26 * notification area element
27 * @param {Object} [options] - a dictionary of keyword arguments.
28 */
29 var NotificationArea = function (selector, options) {
30 this.selector = selector;
31 this.events = options.events;
10 var NotificationArea = notificationarea.NotificationArea;
11
12 var NotebookNotificationArea = function(selector, options) {
13 NotificationArea.apply(this, [selector, options]);
32 14 this.save_widget = options.save_widget;
33 15 this.notebook = options.notebook;
34 16 this.keyboard_manager = options.keyboard_manager;
35 if (this.selector !== undefined) {
36 this.element = $(selector);
37 }
38 this.widget_dict = {};
39 };
40
41 /**
42 * Get a widget by name, creating it if it doesn't exist.
43 *
44 * @method widget
45 * @param {string} name - the widget name
46 */
47 NotificationArea.prototype.widget = function (name) {
48 if (this.widget_dict[name] === undefined) {
49 return this.new_notification_widget(name);
50 }
51 return this.get_widget(name);
52 };
53
54 /**
55 * Get a widget by name, throwing an error if it doesn't exist.
56 *
57 * @method get_widget
58 * @param {string} name - the widget name
59 */
60 NotificationArea.prototype.get_widget = function (name) {
61 if(this.widget_dict[name] === undefined) {
62 throw('no widgets with this name');
63 }
64 return this.widget_dict[name];
65 };
66
67 /**
68 * Create a new notification widget with the given name. The
69 * widget must not already exist.
70 *
71 * @method new_notification_widget
72 * @param {string} name - the widget name
73 */
74 NotificationArea.prototype.new_notification_widget = function (name) {
75 if (this.widget_dict[name] !== undefined) {
76 throw('widget with that name already exists!');
77 }
78
79 // create the element for the notification widget and add it
80 // to the notification aread element
81 var div = $('<div/>').attr('id', 'notification_' + name);
82 $(this.selector).append(div);
83
84 // create the widget object and return it
85 this.widget_dict[name] = new NotificationWidget('#notification_' + name);
86 return this.widget_dict[name];
87 };
88
17 }
18
19 NotebookNotificationArea.prototype = Object.create(NotificationArea.prototype);
20
89 21 /**
90 22 * Initialize the default set of notification widgets.
91 23 *
92 24 * @method init_notification_widgets
93 25 */
94 NotificationArea.prototype.init_notification_widgets = function () {
26 NotebookNotificationArea.prototype.init_notification_widgets = function () {
95 27 this.init_kernel_notification_widget();
96 28 this.init_notebook_notification_widget();
97 29 };
@@ -101,7 +33,7 b' define(['
101 33 *
102 34 * @method init_kernel_notification_widget
103 35 */
104 NotificationArea.prototype.init_kernel_notification_widget = function () {
36 NotebookNotificationArea.prototype.init_kernel_notification_widget = function () {
105 37 var that = this;
106 38 var knw = this.new_notification_widget('kernel');
107 39 var $kernel_ind_icon = $("#kernel_indicator_icon");
@@ -324,7 +256,7 b' define(['
324 256 *
325 257 * @method init_notebook_notification_widget
326 258 */
327 NotificationArea.prototype.init_notebook_notification_widget = function () {
259 NotebookNotificationArea.prototype.init_notebook_notification_widget = function () {
328 260 var nnw = this.new_notification_widget('notebook');
329 261
330 262 // Notebook events
@@ -381,7 +313,8 b' define(['
381 313 });
382 314 };
383 315
384 IPython.NotificationArea = NotificationArea;
385
386 return {'NotificationArea': NotificationArea};
316 // Backwards compatibility.
317 IPython.NotificationArea = NotebookNotificationArea;
318
319 return {'NotebookNotificationArea': NotebookNotificationArea};
387 320 });
General Comments 0
You need to be logged in to leave comments. Login now