Skip to content

Commit

Permalink
add termina::view_ready() #987
Browse files Browse the repository at this point in the history
  • Loading branch information
jcubic committed Dec 9, 2024
1 parent 8a179e7 commit 9f29f95
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* experimental `--cols` CSS variable [#956](https://github.com/jcubic/jquery.terminal/issues/956)
* add `terminal::lines()` [#966](https://github.com/jcubic/jquery.terminal/issues/966)
* add small ASCII Art to signature [#972](https://github.com/jcubic/jquery.terminal/issues/972)
* add `termina::view_ready()` [#987](https://github.com/jcubic/jquery.terminal/issues/987)
### Bugfix
* fix `terminal::login()` when user already authenticated [#980](https://github.com/jcubic/jquery.terminal/issues/980)
* improve mobile support
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![npm](https://img.shields.io/badge/npm-DEV-blue.svg)](https://www.npmjs.com/package/jquery.terminal)
![bower](https://img.shields.io/badge/bower-DEV-yellow.svg)
[![Build and test](https://github.com/jcubic/jquery.terminal/actions/workflows/build.yaml/badge.svg?branch=devel&event=push)](https://github.com/jcubic/jquery.terminal/actions/workflows/build.yaml)
[![Coverage Status](https://coveralls.io/repos/github/jcubic/jquery.terminal/badge.svg?branch=devel&f6f4cbb4305eab7c6a36637dff2538c9)](https://coveralls.io/github/jcubic/jquery.terminal?branch=devel)
[![Coverage Status](https://coveralls.io/repos/github/jcubic/jquery.terminal/badge.svg?branch=devel&07c28c31dc260cd38636ca8bd296cfc4)](https://coveralls.io/github/jcubic/jquery.terminal?branch=devel)
![NPM Downloads](https://img.shields.io/npm/dm/jquery.terminal.svg?style=flat)
[![jsDelivr Downloads](https://data.jsdelivr.com/v1/package/npm/jquery.terminal/badge?style=rounded&n=1)](https://www.jsdelivr.com/package/npm/jquery.terminal)
[![Paid Support](https://img.shields.io/badge/paid-support-354465.svg)](https://support.jcubic.pl/)
Expand Down
77 changes: 77 additions & 0 deletions __tests__/terminal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1617,6 +1617,63 @@ describe('Terminal utils', function() {
expect(output).toMatchSnapshot();
});
});
describe('EventEmitter', function() {
var emitter;
beforeEach(() => {
emitter = new $.terminal.EventEmitter();
});
it('should fire events', () => {
var handler = jest.fn();
emitter.on('test', handler);
emitter.emit('test');
emitter.emit('test');
expect(handler.mock.calls.length).toEqual(2);
});
it('should call different handlers', () => {
var foo = jest.fn();
var bar = jest.fn();
emitter.on('foo', foo);
emitter.on('bar', bar);
emitter.emit('foo', 10);
emitter.emit('bar', 20);
expect(foo).toHaveBeenCalledWith(10);
expect(bar).toHaveBeenCalledWith(20);
});
it('should fire event once', () => {
var handler = jest.fn();
emitter.once('test', handler);
emitter.emit('test');
emitter.emit('test');
expect(handler.mock.calls.length).toEqual(1);
});
it('should remove event handler', () => {
var handler = jest.fn();
emitter.on('test', handler);
emitter.off('test', handler);
emitter.emit('test');
emitter.emit('test');
expect(handler.mock.calls.length).toEqual(0);
});
it('should add mutiple event handlers', () => {
var foo = jest.fn();
var bar = jest.fn();
emitter.on('foo', foo);
emitter.on('foo', bar);
emitter.emit('foo');
expect(foo).toHaveBeenCalledWith();
expect(bar).toHaveBeenCalledWith();
});
it('should remove all event handlers', () => {
var foo = jest.fn();
var bar = jest.fn();
emitter.on('foo', foo);
emitter.on('foo', foo);
emitter.off('foo');
emitter.emit('foo');
expect(foo).not.toHaveBeenCalled();
expect(bar).not.toHaveBeenCalled();
});
});
describe('Cycle', function() {
describe('create', function() {
it('should create Cycle from init values', function() {
Expand Down Expand Up @@ -5184,6 +5241,26 @@ describe('Terminal plugin', function() {
expect(top.greetings).toEqual(greetings);
expect(top.completion).toEqual('settings');
});
it('it should export/import async echo', function(done) {
term.clear();
term.echo(async () => {
await term.delay(100);
return 'helo';
});
term.echo(async () => {
await term.delay(50);
return 'world';
});
term.view_ready().then(() => {
const view = term.export_view();
term.clear();
term.import_view(view);
setTimeout(() => {
expect(term.get_output()).toEqual('world\nhelo');
done();
}, 200);
});
});
it('should import view', function() {
term.clear().push($.noop).set_prompt('# ')
.set_mask(false)
Expand Down
91 changes: 84 additions & 7 deletions js/jquery.terminal-src.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,59 @@
};
}
// -----------------------------------------------------------------------
// :: EventEmitter class
// -----------------------------------------------------------------------
function EventEmitter() {
this._events = {};
}
// -----------------------------------------------------------------------
EventEmitter.prototype.on = function(event, listener) {
if (!this._events[event]) {
this._events[event] = [];
}
this._events[event].push(listener);
};
// -----------------------------------------------------------------------
EventEmitter.prototype.emit = function(event) {
if (this._events[event]) {
const args = Array.prototype.slice.call(arguments, 1);
this._events[event].forEach(function(listener) {
listener.apply(null, args);
});
}
};
// -----------------------------------------------------------------------
EventEmitter.prototype.off = function(event, listener) {
if (!listener) {
delete this._events[event];
} else if (this._events[event]) {
this._events[event] = this._events[event].filter(function(l) {
return l !== listener;
});
}
};
// -----------------------------------------------------------------------
EventEmitter.prototype.once = function(event, listener) {
const self = this;

function wrapper() {
self.off(event, wrapper);
listener.apply(null, arguments);
}

this.on(event, wrapper);
};
// -----------------------------------------------------------------------
EventEmitter.prototype.wait_for = function(event) {
const deferred = new $.Deferred();

this.once(event, function() {
deferred.resolve();
});

return deferred.promise();
};
// -----------------------------------------------------------------------
// :: map object to object
// -----------------------------------------------------------------------
$.omap = function(o, fn) {
Expand Down Expand Up @@ -5385,6 +5438,7 @@
Cycle: Cycle,
History: History,
Stack: Stack,
EventEmitter: EventEmitter,
// ---------------------------------------------------------------------
// :: Validate html color (it can be name or hex)
// ---------------------------------------------------------------------
Expand Down Expand Up @@ -8999,6 +9053,7 @@
}
}
}
// ---------------------------------------------------------------------
var scroll_to_view = (function() {
function scroll_to_view(visible) {
if (!visible) {
Expand Down Expand Up @@ -9762,6 +9817,14 @@
return self;
},
// -------------------------------------------------------------
// :: Return a promise that is resolved when it's safe to
// :: call export_view, it wait for all async function echo
// :: to finish
// -------------------------------------------------------------
view_ready: function() {
return event_hub.wait_for('async_echo_ready');
},
// -------------------------------------------------------------
// :: Return an object that can be used with import_view to
// :: restore the state
// -------------------------------------------------------------
Expand Down Expand Up @@ -9796,7 +9859,8 @@
if (view.focus) {
self.focus();
}
lines.import(clone(view.lines).filter(function(line) {
var cloned_lines = clone(view.lines);
lines.import(cloned_lines.filter(function(line) {
return line[0];
}));
if (view.interpreters instanceof Stack) {
Expand Down Expand Up @@ -11027,16 +11091,24 @@
echo: function(arg, options, deferred) {
var arg_defined = arguments.length > 0;
var d = deferred || new $.Deferred();
function cont() {
function cont(value) {
echo_promise = false;
var original = echo_delay;
echo_delay = [];
for (var i = 0; i < original.length; ++i) {
self.echo.apply(self, original[i]);
}
if (value) {
async_echo = async_echo.filter(function(promise) {
return promise !== value;
});
if (!async_echo.length) {
event_hub.emit('async_echo_ready');
}
}
}
function error(e) {
cont();
function error(e, value) {
cont(value);
display_exception(e, 'ECHO', true);
}
function echo(arg) {
Expand Down Expand Up @@ -11170,6 +11242,7 @@
// queue async functions in echo
if (is_promise(next)) {
echo_promise = true;
async_echo.push(next);
}
lines.push([value, locals]);
unpromise(next, function() {
Expand All @@ -11191,15 +11264,17 @@
if (line) {
self.update(-1, line[0], line[1]);
}
cont();
cont(next);
});
}
fire_event('onAfterEcho', [arg]);
}
if (!contination_run) {
cont();
cont(next);
}
}, error);
}, function(e) {
error(e, next);
});
}, error);
} catch (e) {
// if echo throw exception we can't use error to
Expand Down Expand Up @@ -11997,6 +12072,8 @@
var init_queue = new DelayQueue();
var when_ready = ready(init_queue);
var cmd_ready = ready(command_queue);
var async_echo = [];
var event_hub = new EventEmitter();
var is_bottom_detected;
var is_bottom_observer;
var in_login = false;// some Methods should not be called when login
Expand Down
Loading

0 comments on commit 9f29f95

Please sign in to comment.