260
260
};
261
261
}
262
262
// -----------------------------------------------------------------------
263
+ // :: EventEmitter class
264
+ // -----------------------------------------------------------------------
265
+ function EventEmitter() {
266
+ this._events = {};
267
+ }
268
+ // -----------------------------------------------------------------------
269
+ EventEmitter.prototype.on = function(event, listener) {
270
+ if (!this._events[event]) {
271
+ this._events[event] = [];
272
+ }
273
+ this._events[event].push(listener);
274
+ };
275
+ // -----------------------------------------------------------------------
276
+ EventEmitter.prototype.emit = function(event) {
277
+ if (this._events[event]) {
278
+ const args = Array.prototype.slice.call(arguments, 1);
279
+ this._events[event].forEach(function(listener) {
280
+ listener.apply(null, args);
281
+ });
282
+ }
283
+ };
284
+ // -----------------------------------------------------------------------
285
+ EventEmitter.prototype.off = function(event, listener) {
286
+ if (!listener) {
287
+ delete this._events[event];
288
+ } else if (this._events[event]) {
289
+ this._events[event] = this._events[event].filter(function(l) {
290
+ return l !== listener;
291
+ });
292
+ }
293
+ };
294
+ // -----------------------------------------------------------------------
295
+ EventEmitter.prototype.once = function(event, listener) {
296
+ const self = this;
297
+
298
+ function wrapper() {
299
+ self.off(event, wrapper);
300
+ listener.apply(null, arguments);
301
+ }
302
+
303
+ this.on(event, wrapper);
304
+ };
305
+ // -----------------------------------------------------------------------
306
+ EventEmitter.prototype.wait_for = function(event) {
307
+ const deferred = new $.Deferred();
308
+
309
+ this.once(event, function() {
310
+ deferred.resolve();
311
+ });
312
+
313
+ return deferred.promise();
314
+ };
315
+ // -----------------------------------------------------------------------
263
316
// :: map object to object
264
317
// -----------------------------------------------------------------------
265
318
$.omap = function(o, fn) {
5385
5438
Cycle: Cycle,
5386
5439
History: History,
5387
5440
Stack: Stack,
5441
+ EventEmitter: EventEmitter,
5388
5442
// ---------------------------------------------------------------------
5389
5443
// :: Validate html color (it can be name or hex)
5390
5444
// ---------------------------------------------------------------------
8999
9053
}
9000
9054
}
9001
9055
}
9056
+ // ---------------------------------------------------------------------
9002
9057
var scroll_to_view = (function() {
9003
9058
function scroll_to_view(visible) {
9004
9059
if (!visible) {
9762
9817
return self;
9763
9818
},
9764
9819
// -------------------------------------------------------------
9820
+ // :: Return a promise that is resolved when it's safe to
9821
+ // :: call export_view, it wait for all async function echo
9822
+ // :: to finish
9823
+ // -------------------------------------------------------------
9824
+ view_ready: function() {
9825
+ return event_hub.wait_for('async_echo_ready');
9826
+ },
9827
+ // -------------------------------------------------------------
9765
9828
// :: Return an object that can be used with import_view to
9766
9829
// :: restore the state
9767
9830
// -------------------------------------------------------------
9796
9859
if (view.focus) {
9797
9860
self.focus();
9798
9861
}
9799
- lines.import(clone(view.lines).filter(function(line) {
9862
+ var cloned_lines = clone(view.lines);
9863
+ lines.import(cloned_lines.filter(function(line) {
9800
9864
return line[0];
9801
9865
}));
9802
9866
if (view.interpreters instanceof Stack) {
@@ -11027,16 +11091,24 @@
11027
11091
echo: function(arg, options, deferred) {
11028
11092
var arg_defined = arguments.length > 0;
11029
11093
var d = deferred || new $.Deferred();
11030
- function cont() {
11094
+ function cont(value ) {
11031
11095
echo_promise = false;
11032
11096
var original = echo_delay;
11033
11097
echo_delay = [];
11034
11098
for (var i = 0; i < original.length; ++i) {
11035
11099
self.echo.apply(self, original[i]);
11036
11100
}
11101
+ if (value) {
11102
+ async_echo = async_echo.filter(function(promise) {
11103
+ return promise !== value;
11104
+ });
11105
+ if (!async_echo.length) {
11106
+ event_hub.emit('async_echo_ready');
11107
+ }
11108
+ }
11037
11109
}
11038
- function error(e) {
11039
- cont();
11110
+ function error(e, value ) {
11111
+ cont(value );
11040
11112
display_exception(e, 'ECHO', true);
11041
11113
}
11042
11114
function echo(arg) {
11170
11242
// queue async functions in echo
11171
11243
if (is_promise(next)) {
11172
11244
echo_promise = true;
11245
+ async_echo.push(next);
11173
11246
}
11174
11247
lines.push([value, locals]);
11175
11248
unpromise(next, function() {
@@ -11191,15 +11264,17 @@
11191
11264
if (line) {
11192
11265
self.update(-1, line[0], line[1]);
11193
11266
}
11194
- cont();
11267
+ cont(next );
11195
11268
});
11196
11269
}
11197
11270
fire_event('onAfterEcho', [arg]);
11198
11271
}
11199
11272
if (!contination_run) {
11200
- cont();
11273
+ cont(next );
11201
11274
}
11202
- }, error);
11275
+ }, function(e) {
11276
+ error(e, next);
11277
+ });
11203
11278
}, error);
11204
11279
} catch (e) {
11205
11280
// if echo throw exception we can't use error to
11997
12072
var init_queue = new DelayQueue();
11998
12073
var when_ready = ready(init_queue);
11999
12074
var cmd_ready = ready(command_queue);
12075
+ var async_echo = [];
12076
+ var event_hub = new EventEmitter();
12000
12077
var is_bottom_detected;
12001
12078
var is_bottom_observer;
12002
12079
var in_login = false;// some Methods should not be called when login
0 commit comments