##// END OF EJS Templates
track dirty state in editor for onbeforeunload
Min RK -
Show More
@@ -1,130 +1,134 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'jquery',
6 6 'base/js/utils',
7 7 'codemirror/lib/codemirror',
8 8 'codemirror/mode/meta',
9 9 'codemirror/addon/comment/comment',
10 10 'codemirror/addon/dialog/dialog',
11 11 'codemirror/addon/edit/closebrackets',
12 12 'codemirror/addon/edit/matchbrackets',
13 13 'codemirror/addon/search/searchcursor',
14 14 'codemirror/addon/search/search',
15 15 'codemirror/keymap/emacs',
16 16 'codemirror/keymap/sublime',
17 17 'codemirror/keymap/vim',
18 18 ],
19 19 function($,
20 20 utils,
21 21 CodeMirror
22 22 ) {
23 23 "use strict";
24 24
25 25 var Editor = function(selector, options) {
26 26 var that = this;
27 27 this.selector = selector;
28 28 this.contents = options.contents;
29 29 this.events = options.events;
30 30 this.base_url = options.base_url;
31 31 this.file_path = options.file_path;
32 32 this.config = options.config;
33 33 this.codemirror = new CodeMirror($(this.selector)[0]);
34 this.generation = -1;
34 35
35 36 // It appears we have to set commands on the CodeMirror class, not the
36 37 // instance. I'd like to be wrong, but since there should only be one CM
37 38 // instance on the page, this is good enough for now.
38 39 CodeMirror.commands.save = $.proxy(this.save, this);
39 40
40 41 this.save_enabled = false;
41 42
42 43 this.config.loaded.then(function () {
43 44 // load codemirror config
44 45 var cfg = that.config.data.Editor || {};
45 46 var cmopts = $.extend(true, {}, // true = recursive copy
46 47 Editor.default_codemirror_options,
47 48 cfg.codemirror_options || {}
48 49 );
49 50 that.set_codemirror_options(cmopts, false);
50 51 that.events.trigger('config_changed.Editor', {config: that.config});
51 52 });
52 53 };
53 54
54 55 // default CodeMirror options
55 56 Editor.default_codemirror_options = {
56 57 extraKeys: {
57 58 "Tab" : "indentMore",
58 59 },
59 60 indentUnit: 4,
60 61 theme: "ipython",
61 62 lineNumbers: true,
62 63 };
63 64
64 65 Editor.prototype.load = function() {
65 66 /** load the file */
66 67 var that = this;
67 68 var cm = this.codemirror;
68 69 return this.contents.get(this.file_path, {type: 'file', format: 'text'})
69 70 .then(function(model) {
70 71 cm.setValue(model.content);
71 72
72 73 // Setting the file's initial value creates a history entry,
73 74 // which we don't want.
74 75 cm.clearHistory();
75 76
76 77 // Find and load the highlighting mode
77 78 utils.requireCodeMirrorMode(model.mimetype, function(spec) {
78 79 var mode = CodeMirror.getMode({}, spec);
79 80 cm.setOption('mode', mode);
80 81 });
81 82 that.save_enabled = true;
83 that.generation = cm.changeGeneration();
82 84 },
83 85 function(error) {
84 86 cm.setValue("Error! " + error.message +
85 87 "\nSaving disabled.");
86 88 that.save_enabled = false;
87 89 }
88 90 );
89 91 };
90 92
91 93 Editor.prototype.save = function() {
92 94 /** save the file */
93 95 if (!this.save_enabled) {
94 96 console.log("Not saving, save disabled");
95 97 return;
96 98 }
97 99 var model = {
98 100 path: this.file_path,
99 101 type: 'file',
100 102 format: 'text',
101 103 content: this.codemirror.getValue(),
102 104 };
103 105 var that = this;
106 // record change generation for isClean
107 this.generation = this.codemirror.changeGeneration();
104 108 return this.contents.save(this.file_path, model).then(function() {
105 109 that.events.trigger("save_succeeded.TextEditor");
106 110 });
107 111 };
108 112
109 113 Editor.prototype._set_codemirror_options = function (options) {
110 114 // update codemirror options from a dict
111 115 for (var opt in options) {
112 116 this.codemirror.setOption(opt, options[opt]);
113 117 }
114 118 };
115 119
116 120 Editor.prototype.update_codemirror_options = function (options) {
117 121 /** update codemirror options locally and save changes in config */
118 122 var that = this;
119 123 this._set_codemirror_options(options);
120 124 return this.config.update({
121 125 Editor: {
122 126 codemirror_options: options
123 127 }
124 128 }).then(
125 129 that.events.trigger('config_changed.Editor', {config: that.config})
126 130 );
127 131 };
128 132
129 133 return {Editor: Editor};
130 134 });
@@ -1,66 +1,73 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 require([
5 5 'base/js/namespace',
6 6 'base/js/utils',
7 7 'base/js/page',
8 8 'base/js/events',
9 9 'contents',
10 10 'services/config',
11 11 'edit/js/editor',
12 12 'edit/js/menubar',
13 13 'edit/js/notificationarea',
14 14 'custom/custom',
15 15 ], function(
16 16 IPython,
17 17 utils,
18 18 page,
19 19 events,
20 20 contents,
21 21 configmod,
22 editor,
22 editmod,
23 23 menubar,
24 24 notificationarea
25 25 ){
26 26 page = new page.Page();
27 27
28 28 var base_url = utils.get_body_data('baseUrl');
29 29 var file_path = utils.get_body_data('filePath');
30 30 contents = new contents.Contents({base_url: base_url});
31 var config = new configmod.ConfigSection('edit', {base_url: base_url})
31 var config = new configmod.ConfigSection('edit', {base_url: base_url});
32 32 config.load();
33 33
34 var editor = new editor.Editor('#texteditor-container', {
34 var editor = new editmod.Editor('#texteditor-container', {
35 35 base_url: base_url,
36 36 events: events,
37 37 contents: contents,
38 38 file_path: file_path,
39 39 config: config,
40 40 });
41 41
42 42 // Make it available for debugging
43 43 IPython.editor = editor;
44 44
45 45 var menus = new menubar.MenuBar('#menubar', {
46 46 base_url: base_url,
47 47 editor: editor,
48 48 events: events,
49 49 });
50 50
51 51 var notification_area = new notificationarea.EditorNotificationArea(
52 52 '#notification_area', {
53 53 events: events,
54 54 });
55 55 notification_area.init_notification_widgets();
56 56
57 57 config.loaded.then(function() {
58 58 if (config.data.load_extensions) {
59 59 var nbextension_paths = Object.getOwnPropertyNames(
60 60 config.data.load_extensions);
61 61 IPython.load_extensions.apply(this, nbextension_paths);
62 62 }
63 63 });
64 64 editor.load();
65 65 page.show();
66
67 window.onbeforeunload = function () {
68 if (!editor.codemirror.isClean(editor.generation)) {
69 return "Unsaved changes will be lost. Close anyway?";
70 }
71 };
72
66 73 });
General Comments 0
You need to be logged in to leave comments. Login now