Jean-Yves Didier

added documentation; modified component interface so that slots are unique

This diff is collapsed. Click to expand it.
{
"plugins": ["sigslot.js"],
"plugins": ["./sigslot.js"],
"source" : {
"include" : [ "../src", "Readme.md" ]
"include" : [ "../src", "./Readme.md" ]
},
"opts" : {
"template": "arcs",
"destination": "engine"
"template": "./arcs",
"destination": "./engine"
}
}
......
{
"name": "arcsjs",
"version": "0.9.2",
"version": "0.9.3",
"description": "Augmented Reality Component System in web browser and node environment",
"homepage": "http://arcs.ibisc.fr",
"repository": {
......@@ -9,8 +9,8 @@
},
"main": "build/arcs.js",
"scripts": {
"build": "webpack --config-name core",
"doc": "webpack --config-name doc",
"build": "npx webpack --config-name core",
"doc": "npx webpack --config-name doc",
"test": "npx mocha"
},
"keywords": [
......
......@@ -7,10 +7,10 @@ import Component from './component.js';
/**
* Creates an application runnable by the ARCS engine.
* @class ARCS.Application
* @class Application
* @classdesc The application is the master class of the ARCS engine.
* It is initialized using a structured object (possibly described in JSON,
* see {@link ARCS.Application#import})
* see {@link Application#import})
* to load all external scripts describing components, instanciate
* all components and then start the application
*/
......@@ -26,6 +26,7 @@ let Application = function () {
/**
* Exports an object representing an application
* @function Application#export
*/
this.export = function() {
var i;
......@@ -100,6 +101,7 @@ let Application = function () {
* not inherently an error by itself but it may indicate a problem in your
* application.
* @param sheetName {string} name of the sheet to set as a current sheet.
* @function Application#setSheet
*/
this.setSheet = function (sheetname) {
if (sheets.hasOwnProperty(sheetname)) {
......@@ -115,6 +117,7 @@ let Application = function () {
};
/**
* This is the end my friend. This triggers the end of the application
* @function Application#finish
*/
this.finish = function () {
if (currentSheet) {
......@@ -128,7 +131,7 @@ let Application = function () {
* Imports a structured object describing the application. The structured object
* may be described itself in a JSON format.
* @param object {object} structured object describing an application.
*
* @function Application#import
* @example
* // JSON format of an application description
* {
......@@ -195,6 +198,7 @@ let Application = function () {
* the same key, then it is overridden.
* @param key {string} name of the factory
* @param factory {object} component factory to register.
* @function Application#setFactory
*/
this.setFactory = function (key, factory) {
factories[key] = factory;
......@@ -206,6 +210,7 @@ let Application = function () {
/**
* Starts the application
* @function Application#start
*/
this.start = async function () {
console.log("[ARCS] Instanciating components...");
......@@ -214,6 +219,7 @@ let Application = function () {
};
};
Application.setDependency = function (app, key) {
app.setDependency(key);
};
......
......@@ -6,7 +6,7 @@
/**
* Defines main traits of components in a namespace regrouping important methods
*
* @namespace
* @class Component
*/
var Component = {
/** Error message */
......@@ -40,22 +40,51 @@ var Component = {
name.prototype.slots = [];
name.prototype.signals = {};
/**
* Gives the list of global slot names for a given type of component
* @returns {Array.String} list of global slot names
* @function slotList
* @memberof Component
* @static
*/
name.slotList = function () {
return name.prototype.slots;
};
/**
* Gives the list of local slot names for a given type of component
* @returns {Array.String} list of global slot names
* @function Component#slotList
*/
name.prototype.slotList = function () {
return this.slots;
};
/**
* Gives the list of global slot names for a given type of component
* @returns {Array.String} list of global slot names
* @function slotList
* @memberof Component
* @static
*/
name.prototype.signalList = function () {
var res = [], i;
for (i in this.signals) {
res.push(i);
}
return res;
return Object.keys(this.signals);
};
/**
* Gives the list of local slot names for a given type of component
* @returns {Array.String} list of global slot names
* @function Component#slotList
*/
name.signalList = function () {
return name.prototype.signalList();
};
/**
* Emits a signal
* @param signal {String} name of the signal to emit
* @param {...*} [params] zero or more params to pass to the signal
* @function Component#emit
*/
name.prototype.emit = function (signal) {
var slt, func, obj;
var args = Array.prototype.slice.call(arguments,1);
......@@ -66,14 +95,36 @@ var Component = {
}
};
/**
* Creates a slot that is only owned by this component instance.
* You can see an example of such use in component {@link StateMachine}
* Please notice, that when this method is called, the list of global
* slots will be separated from the local one. Newer global slots will
* then not be added to the component instance.
* In case the slot is already existing, a call to this function will
* replace the slot.
* @param slot {String} name of the slot to create
* @param func {Function} callback function that will be used as a slot
* @function Component#slot
*/
name.prototype.slot = function(slot, func) {
if (!this.hasOwnProperty('slots')) {
this.slots = name.prototype.slots.map(s => s);
}
this.slots.push(slot);
}
if (!this.slots.includes(slot)) {
this.slots.push(slot);
}
this[slot]= func;
};
/**
* Creates a signal that is only owned by this component instance.
* Please notice, that when this method is called, the list of global
* signals will be separated from the local one. Newer global signals will
* then not be added to the component instance.
* @param slot {String} name of the signal to create
* @function Component#signal
*/
name.prototype.signal = function(signal) {
if (!this.hasOwnProperty('signals')) {
this.signals = {};
......@@ -81,20 +132,45 @@ var Component = {
}
this.signals[signal]= [];
};
/**
* Adds one or more global slots. This method has two different
* behaviours. The first one is equivalent to {@link Component#slot}
* except the defined slot is global. The second one tags some methods
* of the components as slots just by giving their names.
*
* @param slot {String|Array.String} name or names of the slots to create
* @param [func] {Function} callback function that will be used as a slot
* @function slot
* @memberof Component
* @static
*/
name.slot = function (slot, func) {
var i;
if (slot instanceof Array) {
for (i = 0; i < slot.length; i++) {
name.prototype.slots.push(slot[i]);
if (!name.prototype.slots.includes(slot[i])) {
name.prototype.slots.push(slot[i]);
}
}
} else {
name.prototype.slots.push(slot);
if (!name.prototype.slots.includes(slot)) {
name.prototype.slots.push(slot);
}
if (func !== undefined) {
name.prototype[slot] = func;
}
}
};
/**
* Adds one or more global signals.
* @param signal {String|Array.String} name or names of the signals to create
* @function signal
* @memberof Component
* @static
*/
name.signal = function (signal) {
var i;
if (signal instanceof Array) {
......@@ -193,8 +269,7 @@ var Component = {
if (destination[slt] === undefined) {
throw Component.UndefinedSlot;
}
var func = destination[slt];
func.apply(destination, value);
},
......
......@@ -29,18 +29,35 @@ let Connection = function (source, signal, destination, slot) {
Component.disconnect(source, signal, destination, slot);
};
/**
* Returns the source of a connection
* @returns {Component} source component of the connection
*/
this.getSource = function() {
return source;
};
/**
* Returns the destination of a connection
* @returns {Component} destination component of the connection
*/
this.getDestination = function () {
return destination;
};
/**
* Returns the slot name of a connection
* @returns {String} slot name
*/
this.getSlot = function () {
return slot;
};
/**
* Returns the signal name of a connection
* @returns {String} signal name
*/
this.getSignal = function () {
return signal;
};
......
......@@ -2,10 +2,10 @@ import StateMachine from './statemachine.js';
import isInNode from './arcs.js';
/**
* @class ARCS.Context
* @classdesc Class representing a context containing libraries and components
* used by different parts of the framework.
* @param ctx {object} an object representing data for the context.
* @class Context
*/
let Context = function( ctx ) {
let components = {};
......@@ -124,6 +124,7 @@ let Context = function( ctx ) {
* when the library is loaded.
* @param libName {string} name of the library to load
* @param cbFunction {function} callback function to call when library is loaded
* @function Context#loadLibrary
*/
this.loadLibrary = function (libName, cbFunction) {
var libUrl = libName, libActualName = libName;
......@@ -155,6 +156,7 @@ let Context = function( ctx ) {
/**
* @return the component list stored inside context
* @function Context#getComponentList
*/
this.getComponentList = function () {
var list = Object.keys(components);
......@@ -168,34 +170,30 @@ let Context = function( ctx ) {
return list;
};
/**
* @return a constant value stored by the engine given its name
* @param cName {String} name of the constant
* @function Context#getConstant
*/
this.getConstant = function(cName) {
/*if (!constants.hasOwnProperty(cName)) {
return undefined;
}*/
return constants[cName];
};
// to determine if really needed
this.getComponentType = function(cName) {
/*if (!components.hasOwnProperty(cName))
return undefined;*/
if (components[cName] === undefined) return undefined;
return components[cName].type;
};
// to determine if really needed
this.getComponentValue = function(cName) {
/*if (!components.hasOwnProperty(cName))
return undefined;*/
if (components[cName] === undefined) return undefined;
return components[cName].value;
};
// to determine if really needed
this.getComponent = function (cName) {
/*if (!components.hasOwnProperty(cName))
return undefined;*/
if (components[cName] === undefined) return undefined;
return components[cName].instance;
};
......
......@@ -8,20 +8,34 @@
* @param value {mixed} value passed to the invoked slot
* @constructor
*/
let Invocation = function (destination, slot, value) {
/**
* Returns the destination component of this invocation
* @returns {object} destination component of this invocation
*/
this.getDestination = function () {
return destination;
};
/**
* Returns the slot name of this invocation
* @returns {String} slot name of this invocation
*/
this.getSlot = function () {
return slot;
};
/**
* Returns the value used for this invocation
* @returns {mixed} value used for this invocation
*/
this.getValue = function () {
return value;
};
/**
* Performs the invocation
*/
this.invoke = function () {
var func = destination[slot];
if (func === undefined) {
......
......@@ -9,9 +9,14 @@ import EventLogicParser from './eventlogicparser.js';
/**
* Describes a statemachine
* @param obj {object} an object describing a state machine. If obj is empty then the statemachine is empty
* @param obj.initial {String} name of the initial state of the statemachine
* @param obj.final {String} name of the final state of the statemachine
* @param obj.transitions {Object} transition object. Each key of the object is named after
* the name of a state and its associated value is an object whose keys are tokens
* and values the name of the state the transition should reach once activated
* by the token
* @class
*/
let StateMachine = Component.create(function (obj) {
// dynamic construction: properties are initial state that have properties
// that are tokens and value that are the final state
......@@ -48,18 +53,6 @@ let StateMachine = Component.create(function (obj) {
for (t in transitions[s]) {
if (transitions[s].hasOwnProperty(t)) {
network[t] = TransitionNetwork.build(astTokens[s][t],tokenEvents);
/*network = TransitionNetwork.build(astTokens[s][t],tokenEvents).promise;
network.then(
function() {
var token;
// clean up remaining promises
for (token in tokenEvents) {
if (tokenEvents.hasOwnProperty(token)) tokenEvents[token].abort();
}
// then activate next sheet
setSheet(transitions[s][t]);
}
);*/
}
}
}
......@@ -151,20 +144,8 @@ let StateMachine = Component.create(function (obj) {
}
}
}
// we will temporay dump properties in order to understand how the statemachine is built
/*
for (p in transitions) {
if (transitions.hasOwnProperty(p)) {
for (t in transitions[p]) {
if (transitions[p].hasOwnProperty(t)) {
console.log("\t" + p + "\t----\t" + t + "\t--->\t" + transitions[p][t]);
}
}
}
}*/
};
/**
* Initialize and starts the statemachine, setting its current state to
* the initial state (by default, it is the departure of the first transition
......