ringa-js / ringa Goto Github PK
View Code? Open in Web Editor NEWRinga is a highly extensible ES6 MVC-inspired library designed to help you build scalable and highly debuggable applications.
License: MIT License
Ringa is a highly extensible ES6 MVC-inspired library designed to help you build scalable and highly debuggable applications.
License: MIT License
Follow web standards to make Ring events work like promises.
Ring.Event(...).then(...);
Ring.Event(...).catch(...);
Target Code:
import {eachIn, dispatch} from 'ringa';
controller.addListener('test', [
Executor1,
eachIn('items', 'item', Executor2),
Executor3
]);
item
in items
run Executor2 (one at a time) and waitNote: this requires that the CommandThread executors are dynamically computed while the thread is running!
Alternate Syntax:
import {eachParallel, dispatch} from 'ringa';
controller.addListener('test', [
Executor1,
eachIn(items => items.map(items => Executor2)),
Executor3
]);
Should outline:
event ->
dom (bubble / capture) ->
controller ->
thread ->
command
Target Code:
import {eachParallel, dispatch} from 'ringa';
controller.addListener('test', [
Executor1,
eachInParallel('items', 'item', Executor2),
Executor3
]);
item
in items
run Executor2 (all in parallel) and pass 'item' as an injector to each and waitAlternate Syntax:
import {eachParallel, dispatch} from 'ringa';
controller.addListener('test', [
Executor1,
eachInParallel(items => items.map(items => Executor2)),
Executor3
]);
Code right now:
export default class MyModel extends Model {
constructor(id) {
super(id);
this.show = false;
this.overlay = false;
}
set show(value) {
if (this._show === value) {
return;
}
this._show = value;
this.notify('show');
}
get show() {
return this._show;
}
set overlay(value) {
if (this._overlay === value) {
return;
}
this._overlay = value;
this.notify('overlay');
}
get overlay() {
return this._overlay;
}
}
To simplify, target code should be:
export default class MyModel extends Model {
constructor(id) {
super(id);
@property
this.show = false;
@property
this.overlay = false;
}
}
PASS tests/Command.test.js
โ Console
console.error src/util/executors.js:82
Ringa Injection Error!:
Executor: Controller1_CommandComplexArgs1
Missing: c
Required: $ringaEvent, $target, $controller, $thread, testObject, a, b, c
Available: $controller, $customEvent, $detail, $lastEvent, $lastPromiseError, $lastPromiseResult, $ringaEvent, $target, $thread, done, fail
If you are minifying JS, make sure you add the original, unmangled property name to the UglifyJSPlugin mangle exceptions.
Dispatched from: unknown stack.
console.error src/util/executors.js:82
Ringa Injection Error!:
Executor: Controller1_CommandComplexArgs1
Missing: testObject
Required: $ringaEvent, $target, $controller, $thread, testObject, a, b, c
Available: $controller, $customEvent, $detail, $lastEvent, $lastPromiseError, $lastPromiseResult, $ringaEvent, $target, $thread, done, fail
If you are minifying JS, make sure you add the original, unmangled property name to the UglifyJSPlugin mangle exceptions.
Dispatched from: unknown stack.
PASS tests/FunctionExecutor.test.js
โ Console
console.error node_modules/core-js/modules/es6.promise.js:117
Unhandled promise rejection someError
Get project integrated into Yarn.
Ringa events right now have:
event.done()
event.fail()
They should also have event.cancel()
. All AbstractCommands should have a _cancel()
method as well so that commands can roll back their most recent operation if someone calls _cancel()
on the event.
We need a unit test that tests the code from the README example so that as the framework updates, the README is not out of date.
Note there are (3) locations this code will exist:
The goal will be to build the unit test.
As an aside: for our entire platform I would like every piece of documented code to have a unit test in the core Ringa code.
RingaEvent line 200
then(resolve, reject) {
if (resolve) {
if (!reject) {
this.addFailListener(resolve.bind(undefined, undefined));
}
this.addDoneListener(resolve);
}
if (reject) this.addFailListener(reject);
}
Write a shell script that does the following:
ringa
react-ringa
ringa-example-server
ringa-example-react
mongodb
is installedFor each, it should run npm install
. Then it should pretty-print nice little options on how to start everything up and get the example running on your machine.
Target code:
controller.addListener('someEvent', [
new Promise((resolve, reject) => {
resolve({result: []});
})
]);
CommandFactory should automatically determine that a promise has been added (using the .then check recommended by most frameworks), and wrap it in a CommandPromiseWrapper. When CommandPromiseWrapper::_execute is called it should wait for the promise to be resolved before continuing to the next command in the CommandThread (e.g. by calling CommandAbstract::done()).
Target Code (UP FOR DISCUSSION):
function preLogger(/* injections */, done /* optional */) {
console.log('Starting event: ', ringaEvent.type);
done();
}
function postLogger(/* injections */, done /* optional */) {
console.log('Finished event: ', ringaEvent.type);
done();
}
controller.addPreMiddleware(preLogger);
controller.addPostMiddleware(postLogger);
We need to add support for the capture phase of events and of course unit tests to verify it works as expected.
Target code:
controller.addListener([...], true); // true for capture phase
Target Code:
import {dynamic, dispatch} from 'ringa';
function buildCommands(items) {
return items.map(item => Executor2);
}
controller.addListener('test', [
Executor1,
dynamic(buildCommands),
Executor3
]);
dispatch('test', {
items: ['item1', 'item2', 'item3']
});
Need to implement stopPropagation
and stopImmediatePropagation
on RingaEvent
that works with the Bus
.
Right now a Controller requires that events are dispatched on a DOM node. We need to add support for any generic bus type.
Get the project into NPM.
Right now, the Controller constructor requires that a DOM node be passed when it is created.
We need to change that so that the DOM node can be set later and when it is set, initialize
is called.
Controllers need to internally cache all their events and when you switch to a new event bus (or DOM node) they need to detach all the original listeners and reattach them to the new bus.
Target Code:
controller.addListener([
...
Executor1,
[[Executor2]],
Executor3,
...
]);
Executor1 should run, Executor2 should be started, but then Executor3 should be run immediately without waiting for Executor2 to finish.
buildArgumentsFromRingaEvent will console.error() and throw Error when it encounters an issue with injections. We need a way to silence these errors if they are expected, similar to contoller.options.consoleLogFails = false;
We need code coverage testing built into our testing process.
There are a lot of files that need to follow the standardized format for commenting. Controller.js is a good example of where I want to go, especially with section headings, but a ton of files are missing detailed comments.
Example code:
export default class FormBaseController extends Controller {
constructor() {
super();
this.injections.formModel = () => {
this.modelWatcher.find(FormBaseModel);
};
}
}
Note that in this case every single time an injection runs, the injector will recompute (find) the FormBaseModel - which might be costly. In some cases this might be required, but I think that we should have a rule that if the injection callback returns a value, then that value that is returned is memoized (cached) for next time the injection is evaluated rather than calling the callback all over again.
Target Code:
export default class FormBaseController extends Controller {
constructor() {
super();
// Our callback will only be called once, and then after that it will reuse the returned value.
this.injections.formModel = () => this.modelWatcher.find(FormBaseModel);
}
}
However, if the injection property (formModel
in this case) is ever overwritten with a new function or a new value, then the memoized value needs to be discarded so we will have to watch for changes to the injection value (in this case formModel
)
Target code:
controller.addListener('testEvent', [
iif(someValue => someValue === true, TruthyCommand, FalsyCommand)
]);
Ring.dispatch('testEvent', {someValue: true});
For information on what an 'iif' is, take a look here: https://en.wikipedia.org/wiki/IIf
Target Code:
controller.addListener('type', [
Executor1,
[Executor2, Executor3],
Executor4
]);
Combined with no wait operator ([[]]):
controller.addListener('type', [
Executor1,
[[Executor2, Executor3]],
Executor4
]);
We should have a caching mechanism for a Controller to keep track of all its event to thread factories so that it can be attached, detached, or switch between event buses without ruining flow and without having to call initialize
again.
Target Code:
import {inject} from 'ringa';
controller.addListener('test', [
Executor1,
inject(Executor2, {
property1: 'some value'
}),
Executor2
]);
When Executor2's is executed the following occurs:
CommandAbstract
and CommandFunctionWrapper
: the injection Object is merged into the standard injections for the execute() method.
CommandEventWrapper
: the injection Object becomes the details for the event.
Note: we may want to consider allowing Executor2 to be its own chain, but I think that will make complexity go through the roof right now.
Target code:
import {dispatch} from 'ring';
controller.addListener('someEvent', [
dispatch(SOME_EVENT_TYPE, {
details: 'this is a details object that gets added to the event'} /*optional*/,
someDomNode /*optional*/)
]);
...
controller.addListener(SOME_EVENT_TYPE, [...]);
Target code:
controller.addListener('myEvent', [
interval(conditionCallback, executor, milliseconds)
]);
This will check conditionCallback
and as long as it returns true, it would run executor
every milliseconds
. Once conditionCallback
returns false, then it continues to the next executor
.
This should allow for the ability to create primitive animations!
Pain Code:
import {Model} from 'ringa';
export default class PopupLoadingModel extends Model {
constructor() {
super();
this.addProperty('loading', false);
}
}
Target Code:
import {model, property} from 'ringa';
export default model('PopupLoadingModel', [
property('loading', false)
]);
OR
import {model, property} from 'ringa';
model('PopupLoadingModel', property('loading', false));
Target Code:
controller.addListener(type, [
Executor1,
Executor2,
50,
Executor3
]);
Executor1 should run, then Executor2, then it should wait 50 milliseconds, then Executor3 should run.
Controller: add support for a single event type to trigger multiple threads (ordered by priority) within the same Controller.
Note that this is primarily useful when one controller extends another or when you want two threads to run in parallel in response to a single event.
We should probably consider doing a clone of the event between the two threads - but this is going to get super complicated.
Rules:
id
: must be unique applicationwide. By default, will be the class name combined with a count for the number of instances of that class.
name
: does not have to be unique, but must be unique for all models attached to a controller for injection.
Once comments are all in the system, we should hook up a JS API generator process to publish a complete web-browser friendly documentation during npm run build
to the docs
folder.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.