Node: Add setHandler features on signals

This commit is contained in:
Olivier Goffart 2020-10-21 12:20:59 +02:00
parent c50b9d73d3
commit ac6d4007ab
4 changed files with 73 additions and 23 deletions

View file

@ -70,11 +70,12 @@ console.log(component.counter);
### Signals
The signals are also exposed as property that can be called
The signals are also exposed as property that have a setHandler function, and that can can be called.
```js
// connect to a signal
component.clicked = function() { console.log("hello"); }
component.clicked.setHandler(function() { console.log("hello"); })
// emit a signal
component.clicked();
```

View file

@ -49,6 +49,14 @@ class Component {
}
}
/**
* @hidden
*/
interface Signal {
(): any;
setHandler(cb: any): void;
}
require.extensions['.60'] =
function (module, filename) {
var c = native.load(filename);
@ -64,7 +72,11 @@ require.extensions['.60'] =
});
c.signals().forEach((x: string) => {
Object.defineProperty(ret, x, {
get() { return function () { comp.emit_signal(x, [...arguments]); } },
get() {
let signal = function () { comp.emit_signal(x, [...arguments]); } as Signal;
signal.setHandler = function (callback) { comp.connect_signal(x, callback) };
return signal;
},
enumerable: true,
})
});

View file

@ -83,6 +83,28 @@ fn load(mut cx: FunctionContext) -> JsResult<JsValue> {
Ok(obj.as_value(&mut cx))
}
fn make_signal_handler<'cx>(
cx: &mut impl Context<'cx>,
persistent_context: &persistent_context::PersistentContext<'cx>,
fun: Handle<'cx, JsFunction>,
) -> Box<dyn Fn(&[sixtyfps_interpreter::Value])> {
let fun_value = fun.as_value(cx);
let fun_idx = persistent_context.allocate(cx, fun_value);
Box::new(move |args| {
let args = args.iter().cloned().collect::<Vec<_>>();
run_with_global_contect(&move |cx, persistent_context| {
let args = args.iter().map(|a| to_js_value(a.clone(), cx).unwrap()).collect::<Vec<_>>();
persistent_context
.get(cx, fun_idx)
.unwrap()
.downcast::<JsFunction>()
.unwrap()
.call::<_, _, JsValue, _>(cx, JsUndefined::new(), args)
.unwrap();
})
})
}
fn create<'cx>(
cx: &mut CallContext<'cx, impl neon::object::This>,
component_type: Rc<sixtyfps_interpreter::ComponentDescription>,
@ -103,28 +125,12 @@ fn create<'cx>(
})?
.clone();
if let Type::Signal { .. } = ty {
let _fun = value.downcast_or_throw::<JsFunction, _>(cx)?;
let fun_idx = persistent_context.allocate(cx, value);
let fun = value.downcast_or_throw::<JsFunction, _>(cx)?;
component_type
.set_signal_handler(
component.borrow(),
prop_name.as_str(),
Box::new(move |args| {
let args = args.iter().cloned().collect::<Vec<_>>();
run_with_global_contect(&move |cx, persistent_context| {
let args = args
.iter()
.map(|a| to_js_value(a.clone(), cx).unwrap())
.collect::<Vec<_>>();
persistent_context
.get(cx, fun_idx)
.unwrap()
.downcast::<JsFunction>()
.unwrap()
.call::<_, _, JsValue, _>(cx, JsUndefined::new(), args)
.unwrap();
})
}),
make_signal_handler(cx, &persistent_context, fun),
)
.or_else(|_| cx.throw_error(format!("Cannot set signal")))?;
} else {
@ -412,6 +418,23 @@ declare_types! {
Ok(JsUndefined::new().as_value(&mut cx))
}
method connect_signal(mut cx) {
let signal_name = cx.argument::<JsString>(0)?.value();
let handler = cx.argument::<JsFunction>(1)?;
let this = cx.this();
let persistent_context =
persistent_context::PersistentContext::from_object(&mut cx, this.downcast().unwrap())?;
let lock = cx.lock();
let x = this.borrow(&lock).0.clone();
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
component.description().set_signal_handler(
component.borrow(),
signal_name.as_str(),
make_signal_handler(&mut cx, &persistent_context, handler)
).or_else(|_| cx.throw_error(format!("Cannot set signal")))?;
Ok(JsUndefined::new().as_value(&mut cx))
}
method send_mouse_click(mut cx) {
let x = cx.argument::<JsNumber>(0)?.value() as f32;
let y = cx.argument::<JsNumber>(1)?.value() as f32;

View file

@ -88,7 +88,21 @@ try {
assert.equal(e.toString(), "Error: test_signal expect 1 arguments, but 0 where provided");
}
assert.equal(instance.signal_emission_count, 0);
/// also test setHandler
instance.test_signal2.setHandler(function(a) {
signal_3_emited += 100;
signal_3_string_value = a;
});
instance.test_signal2("salùt")
assert.equal(signal_3_emited, 101);
assert.equal(signal_3_string_value, "salùt");
assert.equal(signal_3_int_value, 55); // same as before
```
*/