From dc929bfc2a1dffcf4f6bb45df734ad8468c3601a Mon Sep 17 00:00:00 2001 From: "Theunis J. Botha" Date: Sun, 10 Oct 2021 15:31:23 +0200 Subject: [PATCH] cascading works --- .r3_history | 3 + dist/r3.js | 1569 ++++++++++++----- package-lock.json | 442 ++++- package.json | 3 +- r3.php | 2 +- src/r3/index.js | 4 + src/r3/r3-component/r3-component-mesh.js | 216 +++ src/r3/r3-component/r3-component-touch.js | 16 +- src/r3/r3-entity/r3-entity-slider.js | 54 +- src/r3/r3-event.js | 148 +- src/r3/r3-graph.js | 479 +++++ src/r3/r3-node.js | 124 ++ src/r3/r3-object/r3-object.js | 172 +- src/r3/r3-runtime/index.js | 2 + src/r3/r3-runtime/r3-runtime-bullet.js | 6 + src/r3/r3-runtime/r3-runtime-code-mirror.js | 6 + src/r3/r3-runtime/r3-runtime-control-kit.js | 6 + src/r3/r3-runtime/r3-runtime-document.js | 9 +- src/r3/r3-runtime/r3-runtime-js-d-o-m.js | 130 ++ .../r3-runtime/r3-runtime-node-j-s-image.js | 6 + src/r3/r3-runtime/r3-runtime-stats.js | 6 + src/r3/r3-runtime/r3-runtime-three.js | 6 + src/r3/r3-runtime/r3-runtime-web-image.js | 6 + src/r3/r3-runtime/r3-runtime.js | 13 +- src/r3/r3-system/r3-system-d-o-m.js | 4 +- src/r3/r3-system/r3-system-input.js | 4 +- src/r3/r3-system/r3-system-linking.js | 363 ++-- src/r3/r3-system/r3-system-render.js | 16 +- src/r3/r3-system/r3-system-runtime.js | 67 +- src/r3/r3-system/r3-system-socket.js | 4 +- src/r3/r3-system/r3-system-storage.js | 4 +- src/r3/r3.js | 4 +- .../generated_required_components.template | 16 +- src/templates/object_base.template | 2 + src/templates/runtime_extends.template | 6 + src/templates/start.template | 2 +- src/templates/token.db | 39 +- test/R3.test.js | 70 + version | 2 +- 39 files changed, 3314 insertions(+), 717 deletions(-) create mode 100644 src/r3/r3-graph.js create mode 100644 src/r3/r3-node.js create mode 100644 src/r3/r3-runtime/r3-runtime-js-d-o-m.js diff --git a/.r3_history b/.r3_history index 93895dd..d1478e9 100644 --- a/.r3_history +++ b/.r3_history @@ -47,3 +47,6 @@ r3 create ComponentMesh component_extends Component ./r3-component/ r3 create ComponentGeometry component_extends Component ./r3-component/ r3 create ComponentBufferGeometry component_extends ComponentGeometry ./r3-component/ r3 create ComponentPlaneGeometry component_extends ComponentBufferGeometry ./r3-component/ +r3 create Graph base ./ +r3 create Node base ./ +r3 create RuntimeJsDOM runtime_extends RuntimeDOM ./r3-runtime/ diff --git a/dist/r3.js b/dist/r3.js index 9e245ac..c300d89 100644 --- a/dist/r3.js +++ b/dist/r3.js @@ -17,12 +17,12 @@ class R3 { /** * static Version - Current R3 version */ -R3.Version = '3.0.261'; +R3.Version = '3.0.338'; /** * static CompileDate - Current compile date of R3 */ -R3.CompileDate = '2021 Oct 03 - 07:35:08 am'; +R3.CompileDate = '2021 Oct 10 - 15:24:05 pm'; class System { @@ -113,8 +113,8 @@ class SystemDOM extends System { SystemDOM.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemDOM.Subscriptions = {}; @@ -366,8 +366,8 @@ class SystemInput extends System { SystemInput.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemInput.Subscriptions = {}; @@ -427,6 +427,16 @@ class SystemLinking extends System { SystemLinking.OnObjectPropertyUpdated ); + SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'] = Event.Subscribe( + Event.ON_READY_STATE_CHANGE, + SystemLinking.OnOnReadyStateChange + ); + + SystemLinking.Subscriptions['FINAL_INITIALIZE'] = Event.Subscribe( + Event.FINAL_INITIALIZE, + SystemLinking.OnFinalInitialize + ); + SystemLinking.Started = true; console.log('Started system: SystemLinking'); @@ -461,6 +471,12 @@ class SystemLinking extends System { SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED'].remove(); delete SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED']; + SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'].remove(); + delete SystemLinking.Subscriptions['ON_READY_STATE_CHANGE']; + + SystemLinking.Subscriptions['FINAL_INITIALIZE'].remove(); + delete SystemLinking.Subscriptions['FINAL_INITIALIZE']; + SystemLinking.Started = false; console.log('Stopped system: SystemLinking'); @@ -584,7 +600,7 @@ class SystemLinking extends System { /** * SetParentChildRelationships() * - When an object gets some value assigned to a property, and it is a required property, we need to ensure that - * the proper parent / child relationships are maintained + * the proper parent and child relationships are maintained * @param r3Object * @param property * @param value @@ -664,9 +680,9 @@ class SystemLinking extends System { /** * DetermineFutureReadyState() * - When an object is assigned some value to one of its required properties, we should determine the future - * 'readiness' state of this R3 Object. If an object will fall out of readiness, we need to notify all relevant - * systems of the eventual demise of this object, so that they have the opportunity to cleanly stop using running - * instances of this object. + * 'readiness' state of this R3 Object. Only if its ready state becomes false, we need to cascade this + * information to all parents forcing them to emit a Only if its ready state becomes false, we force all parents + * to emit a READY_STATE_PENDING_FALSE event. * @param r3Object * @param property * @param value @@ -683,293 +699,122 @@ class SystemLinking extends System { if (r3Object.ready[r]) { + /** + * This object is currently ready - we need to check if this object will fall out of a ready state. + * We only need to compare the current property. + */ + let ready = true; - /** - * This object is currently ready - we need to check if this object will fall out of a ready state - */ let requirements = r3Object.required[r]; if (requirements.hasOwnProperty(property)) { - - /** - * The property change is one of the required properties of this Object, so it affects the overall - * 'readiness' of this object. - */ - if (requirements[property] instanceof Array) { - - /** - * - */ - if (!(value instanceof Array)) { - ready = false; - } - - if (value.length === 0) { - ready = false; - } - - for (let v = 0; v < value.length; v++) { - if (!(value[v] instanceof requirements[property][0])) { - ready = false; - } - } - - } else { - - if (!(value instanceof requirements[property])) { - - ready = false; - - } - } - + ready = r3Object.requirementValueCheck(requirements[property], value); } if (!ready) { /** * This object will fall out of readiness state - notify all systems */ - Event.Emit( - Event.FUTURE_READY_STATE_FALSE, - { - r3Object, - property, - value, - requiredIndex : r - } - ); - } - - } else { - - let ready = true; - - /** - * This object is current *NOT* ready - we need to check if this object will fall into a ready state. - */ - let requirements = r3Object.required[r]; - - for (let requirementProperty in requirements) { - if (requirements.hasOwnProperty(requirementProperty)) { - - if (requirementProperty === property) { - /** - * Compare against the current value and not the r3Object[requirementProperty] - */ - - if (requirements[requirementProperty] instanceof Array) { - - } - - } - - } - } - - /** - * Now check all the other requirements (since we can only have a true ready state if *ALL* requirements are met) - */ - for (let requirement in requirements) { - - if (requirement === property) { - /** - * Skip the current property - it has already been evaluated - */ - continue; - } - - if (requirements.hasOwnProperty(requirement)) { - - if (requirements[requirement] instanceof Array) { - - if (!(r3Object[requirement] instanceof Array)) { - ready = false; - } - - if (r3Object[requirement].length === 0) { - ready = false; - } - - for (let p = 0; p < r3Object[requirement].length; p++) { - if (!(r3Object[requirement][p] instanceof requirements[requirement][0])) { - ready = false; - } - } - - } else { - if (!(r3Object[requirement] instanceof requirements[requirement])) { - ready = false; - } - } - } - } - - // if (requirements.hasOwnProperty(property)) { - // - // - // - // } else { - // ready = false; - // } - - if (ready) { - - /** - * This object will become ready - notify all systems - but don't modify the ready state yet (until after the update) - */ - Event.Emit( - Event.FUTURE_READY_STATE_TRUE, - { - r3Object, - property, - value, - requiredIndex: r - } - ); - - } - - } // if or not ready - - } // for - - // if (r3Object.required[property] instanceof Array) { - // - // if (value.length === 0) { - // return false; - // } - // - // for (let i = 0; i < value.length; i++) { - // if (value[i].initialized !== true) { - // return false; - // } - // } - // - // return true; - // - // } else { - // - // if (value === null) { - // return false; - // } else { - // - // if (value.initialized !== true) { - // return false; - // } - // - // return true; - // } - // } - - // for (let requiredProperty in this.required) { - // if (this.required.hasOwnProperty(requiredProperty)) { - // if (requiredProperty === property) { - // if (!isReady(property, value)) { - // this.initialized = false; - // return; - // } - // } else { - // if (!isReady(requiredProperty, this[requiredProperty])) { - // this.initialized = false; - // return; - // } - // } - // } - // } - - } - - /** - * DetermineActualReadyState() - * - When an object is assigned some value to one of its required properties, we should determine the current - * 'readiness' state of this R3 Object after its property has assumed the value. If the ready state of an object - * changed - we need to start / stop this Object or Entity, create / delete instances of the Component - * @param r3Object - * @param property - * @param value - */ - static DetermineActualReadyState( - r3Object, - property, - value - ) { - - console.log('Determining actual ready state of ' + r3Object.name); - - for (let r = 0; r < r3Object.required.length; r++) { - - let ready = true; - - /** - * This object is currently ready - we need to check if this object will fall out of a ready state - */ - let requirements = r3Object.required[r]; - - for (let property in requirements) { - if (requirements.hasOwnProperty(property)) { - - if (requirements[property] instanceof Array) { - - if (!(r3Object[property] instanceof Array)) { - ready = false; - } - - if (r3Object[property] .length === 0) { - ready = false; - } - - for (let v = 0; v < r3Object[property].length; v++) { - if (!(r3Object[property][v] instanceof requirements[property][0])) { - ready = false; - } - } - - } else { - if (!(r3Object[property] instanceof requirements[property])) { - ready = false; - } - } + console.log('Future ready state will transition from true to false'); + SystemLinking.CascadeFutureReadyState(r3Object, R3Object.READY_STATE_PENDING_FALSE); } } - - r3Object.ready[r] = ready; } } /** - * RequirementsValueCheck() - * - Does a quick check of the value against the requirement - * @param requirementProperty - * @param value + * CascadeFutureReadyState() + * - We start at the current node - emit READY_STATE_PENDING_FALSE event, afterwards calling asking all parents to + * emit a READY_STATE_PENDING_FALSE event. This allows the SystemLinking to stop Entities before the cleanup + * occurs. + * @param r3Object + * @param readyState */ - static RequirementsValueCheck( - requirementProperty, - value + static CascadeFutureReadyState( + r3Object, + readyState ) { - //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START - //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END + let node = new Node( + { + object : r3Object + } + ); - //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START - //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END + let graph = new Graph( + { + startNode : node, + relevant : ['parents'] + } + ) + + let nodes = graph.closed; + + /** + * nodes contains a list of current node and parent Objects which are affected by the ready state of this object. + */ + for (let n = 0; n < nodes.length; n++) { + + let node = nodes[n]; + + /** + * The parent does not know directly why it falls out of ready state necessarily - because from its perspective + * it may have all its children requirements met - however a child of one of its children is going out of ready + * state. So - without adding too much complexity here, we just notify all parents (including the current node) + * that it's impending ready state will be false. We don't care about the readyStateIndex because of this. (for + * the sake of complexity) + */ + Event.Emit( + Event.ON_READY_STATE_CHANGE, + { + r3Object: node.object, + readyState: readyState + } + ); + } } /** - * ActivateInstances() - * - No comment + * CascadeActualReadyState() + * - We start at the current node, determine its current ready state (it triggers the appropriate events), + * afterwards we work from the first parent upwards, determining it's ready state, taking appropriate action and + * cascading upwards. + * @param r3Object */ - static ActivateInstances() { + static CascadeActualReadyState(r3Object) { - // if (this instanceof Component && this.initialized) { - // this.createInstance(); - // } - // - // if (this instanceof Entity && this.initialized && !this.started) { - // this.start(); - // } + console.log('Cascading actual ready state of ' + r3Object.name); + + let node = new Node( + { + object : r3Object + } + ); + + let graph = new Graph( + { + startNode : node, + relevant : ['parents'] + } + ) + + let nodes = graph.closed; + + /** + * nodes contains the current node as it's first object, followed by its parents + */ + for (let n = 0; n < nodes.length; n++) { + + let node = nodes[n]; + + /** + * A simple node.object.isReady() check will trigger the required READY_STATE_CHANGE events + */ + node.object.isReady(); + } } @@ -1125,12 +970,96 @@ class SystemLinking extends System { */ static OnObjectPropertyUpdated(object) { - let {r3Object, property, value} = object; + let {r3Object} = object; /** * Determine the actual ready state of the r3Object */ - SystemLinking.DetermineActualReadyState(r3Object, property, value); + SystemLinking.CascadeActualReadyState(r3Object); + + } + + /** + * OnOnReadyStateChange() + * - Listens to events of type Event.ON_READY_STATE_CHANGE and executes this function. + * @param object (The event data passed as argument - typically an R3Object) + * @return + */ + static OnOnReadyStateChange(object) { + + let {r3Object, readyState, readyStateIndex} = object; + + if (readyState === R3Object.READY_STATE_TRUE) { + + console.log('Ready state changed to true for ' + r3Object.name + ' by passing requirements set ' + readyStateIndex); + + /** + * If it is a Component and it has no instance, call its createInstance(). + */ + if (r3Object instanceof Component && !r3Object.instance) { + r3Object.createInstance(); + } + + /** + * If it is an Entity and it is stopped, call the start() method. + */ + if (r3Object instanceof Entity && r3Object.started === false) { + r3Object.start(); + } + + } + + if (readyState === R3Object.READY_STATE_FALSE) { + console.log('Ready state false for : ' + r3Object.name); + + /** + * If it is a Component and it has an instance, dispose of it + */ + if (r3Object instanceof Component && r3Object.instance) { + r3Object.disposeInstance(); + } + } + + if (readyState === R3Object.READY_STATE_PENDING_FALSE) { + console.log('Ready state pending false for : ' + r3Object.name); + + /** + * If it is an Entity and is started, stop it. + */ + if (r3Object instanceof Entity && r3Object.started === true) { + r3Object.stop(); + } + } + + if (readyState === R3Object.READY_STATE_PENDING_TRUE) { + + /** + * We don't do anything at the moment - we just log this information. + */ + console.log('Ready state pending true for ' + r3Object.name + ' by passing requirements set ' + readyStateIndex); + } + + } + + /** + * OnFinalInitialize() + * - Listens to events of type Event.FINAL_INITIALIZE and executes this function. + * @param object (The event data passed as argument - typically an R3Object) + * @return + */ + static OnFinalInitialize(object) { + + if (object instanceof Component) { + if (object.required.length === 0) { + object.createInstance(); + } + } + + if (object instanceof Entity) { + if (object.required.length === 0) { + object.start(); + } + } } @@ -1142,13 +1071,14 @@ class SystemLinking extends System { SystemLinking.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemLinking.Subscriptions = {}; /** - * static BlacklistedComponents - A list of component constructors which should not be permitted to create instances immediately + * static BlacklistedComponents - A list of component constructors which should not be permitted to create instances + * immediately */ SystemLinking.BlacklistedComponents = []; @@ -1208,14 +1138,14 @@ class SystemRender extends System { */ static OnInstanceCreated(object) { - if (object instanceof R3.Component.DOM) { - if (object.runtime instanceof R3.Runtime.DOM.Document) { + if (object instanceof ComponentDOM) { + if (object.runtime instanceof RuntimeDocument) { document.body.appendChild(object.instance); } } - if (object instanceof R3.Component.Graphics.Image) { - if (object.runtime instanceof R3.Runtime.Image.WebImage) { + if (object instanceof ComponentImage) { + if (object.runtime instanceof RuntimeWebImage) { document.body.appendChild(object.instance); } } @@ -1231,8 +1161,8 @@ class SystemRender extends System { SystemRender.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemRender.Subscriptions = {}; @@ -1333,23 +1263,41 @@ class SystemRuntime extends System { * the DOM. */ if ( - object instanceof R3.Component.DOM || - object instanceof R3.Component.Input + object instanceof ComponentDOM || + object instanceof ComponentImage || + object instanceof ComponentInput ) { if (SystemRuntime.CurrentProject === null) { - return new R3.Runtime.DOM.Document(); + + if (typeof process === 'undefined') { + + if (!SystemRuntime.RuntimeDocument) { + SystemRuntime.RuntimeDocument = new RuntimeDocument(); + } + + return SystemRuntime.RuntimeDocument; + + } else { + + if (!SystemRuntime.RuntimeJsDOM) { + SystemRuntime.RuntimeJsDOM = new RuntimeJsDOM(); + } + + return SystemRuntime.RuntimeJsDOM; + + } } else { console.log('TODO: implement a project based DOM runtime'); } } - if (object instanceof R3.Component.Graphics.Image) { - if (SystemRuntime.CurrentProject === null) { - return new R3.Runtime.Image.WebImage(); - } else { - console.log('TODO: implement a project based Image runtime'); - } - } + // if (object instanceof ComponentImage) { + // if (SystemRuntime.CurrentProject === null) { + // return new RuntimeWebImage(); + // } else { + // console.log('TODO: implement a project based Image runtime'); + // } + // } } @@ -1401,8 +1349,8 @@ class SystemRuntime extends System { SystemRuntime.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemRuntime.Subscriptions = {}; @@ -1416,6 +1364,11 @@ SystemRuntime.Projects = []; */ SystemRuntime.CurrentProject = null; +/** + * static ServerSide - No comment + */ +SystemRuntime.ServerSide = (typeof process !== 'undefined'); + /** * static RuntimeCoder - No comment */ @@ -1446,6 +1399,16 @@ SystemRuntime.RuntimePhysics = {}; */ SystemRuntime.RuntimeStatistics = {}; +/** + * static RuntimeJsDOM - No comment + */ +SystemRuntime.RuntimeJsDOM = null; + +/** + * static RuntimeDocument - No comment + */ +SystemRuntime.RuntimeDocument = null; + class SystemSocket extends System { constructor(options) { @@ -1494,8 +1457,8 @@ class SystemSocket extends System { SystemSocket.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemSocket.Subscriptions = {}; @@ -1573,8 +1536,8 @@ class SystemStorage extends System { SystemStorage.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemStorage.Subscriptions = {}; @@ -1602,12 +1565,13 @@ Runtime.BASE_SOCKET = 0x6; Runtime.BASE_STATISTICS = 0x7; Runtime.CODE_MIRROR = 0x8; Runtime.DOCUMENT = 0x9; -Runtime.CONTROL_KIT = 0xa; -Runtime.THREE = 0xb; -Runtime.NODE_JS_IMAGE = 0xc; -Runtime.WEB_IMAGE = 0xd; -Runtime.BULLET = 0xe; -Runtime.STATS = 0xf; +Runtime.JS_DOM = 0xa; +Runtime.CONTROL_KIT = 0xb; +Runtime.THREE = 0xc; +Runtime.NODE_JS_IMAGE = 0xd; +Runtime.WEB_IMAGE = 0xe; +Runtime.BULLET = 0xf; +Runtime.STATS = 0x10; class RuntimeCoder extends Runtime { @@ -1703,7 +1667,7 @@ class RuntimeDocument extends RuntimeDOM { */ buildInstance(component) { - if (component instanceof R3.Component.DOM.Canvas) { + if (component instanceof ComponentCanvas) { let canvas = document.createElement('canvas'); canvas.setAttribute('width', component.width); canvas.setAttribute('height', component.height); @@ -1715,6 +1679,46 @@ class RuntimeDocument extends RuntimeDOM { } +class RuntimeJsDOM extends RuntimeDOM { + + constructor(options) { + + if (typeof options === 'undefined') { + options = {}; + } + + super(options); + + /** + * dom - No comment + */ + if (typeof options.dom === 'undefined') { + options.dom = new JSDOM(`

R3 NodeJS DOM

`);; + } + + Object.assign(this, options); + + } + + /** + * buildInstance() + * - Creates a runtime instance object based on the R3.Component representing it. + * @param component + */ + buildInstance(component) { + + if (component instanceof ComponentCanvas) { + let canvas = this.dom.window.document.createElement('canvas'); + canvas.setAttribute('width', component.width); + canvas.setAttribute('height', component.height); + canvas.setAttribute('style', component.style); + return canvas; + } + + } + +} + class RuntimeGUI extends Runtime { constructor(options) { @@ -2261,44 +2265,43 @@ Event.ENTITY_CREATED = 0xa; Event.ENTITY_INITIALIZED = 0xb; Event.ENTITY_STARTED = 0xc; Event.FINAL_INITIALIZE = 0xd; -Event.FUTURE_READY_STATE_FALSE = 0xe; -Event.FUTURE_READY_STATE_TRUE = 0xf; -Event.GET_API_URL = 0x10; -Event.GET_RUNTIME = 0x11; -Event.GET_WINDOW_SIZE = 0x12; -Event.GRAPHICS_COMPONENT_INITIALIZED = 0x13; -Event.IMAGE_COMPONENT_INITIALIZED = 0x14; -Event.IMAGE_INSTANCE_CREATED = 0x15; -Event.INPUT_COMPONENT_INITIALIZED = 0x16; -Event.INSTANCE_CREATED = 0x17; -Event.INSTANCE_DISPOSED = 0x18; -Event.KEYBOARD_DOWN = 0x19; -Event.KEYBOARD_UP = 0x1a; -Event.MOUSE_DOWN = 0x1b; -Event.MOUSE_MOVE = 0x1c; -Event.MOUSE_UP = 0x1d; -Event.MOUSE_WHEEL = 0x1e; -Event.OBJECT_CREATED = 0x1f; -Event.OBJECT_PROPERTY_UPDATE = 0x20; -Event.OBJECT_PROPERTY_UPDATED = 0x21; -Event.PAUSE = 0x22; -Event.PROJECT_INITIALIZED = 0x23; -Event.RESTART = 0x24; -Event.RUNTIME_CREATED = 0x25; -Event.SLIDER_ENTITY_INITIALIZED = 0x26; -Event.START = 0x27; -Event.TOUCH_CANCEL = 0x28; -Event.TOUCH_COMPONENT_INITIALIZED = 0x29; -Event.TOUCH_END = 0x2a; -Event.TOUCH_MOVE = 0x2b; -Event.TOUCH_START = 0x2c; -Event.UPDATE_FROM_INSTANCE_AFTER = 0x2d; -Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2e; -Event.UPDATE_INSTANCE_AFTER = 0x2f; -Event.UPDATE_INSTANCE_BEFORE = 0x30; -Event.UPDATE_INSTANCE_PROPERTY = 0x31; -Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x32; -Event.MAX_EVENTS = 0x33; +Event.GET_API_URL = 0xe; +Event.GET_RUNTIME = 0xf; +Event.GET_WINDOW_SIZE = 0x10; +Event.GRAPHICS_COMPONENT_INITIALIZED = 0x11; +Event.IMAGE_COMPONENT_INITIALIZED = 0x12; +Event.IMAGE_INSTANCE_CREATED = 0x13; +Event.INPUT_COMPONENT_INITIALIZED = 0x14; +Event.INSTANCE_CREATED = 0x15; +Event.INSTANCE_DISPOSED = 0x16; +Event.KEYBOARD_DOWN = 0x17; +Event.KEYBOARD_UP = 0x18; +Event.MOUSE_DOWN = 0x19; +Event.MOUSE_MOVE = 0x1a; +Event.MOUSE_UP = 0x1b; +Event.MOUSE_WHEEL = 0x1c; +Event.OBJECT_CREATED = 0x1d; +Event.OBJECT_PROPERTY_UPDATE = 0x1e; +Event.OBJECT_PROPERTY_UPDATED = 0x1f; +Event.ON_READY_STATE_CHANGE = 0x20; +Event.PAUSE = 0x21; +Event.PROJECT_INITIALIZED = 0x22; +Event.RESTART = 0x23; +Event.RUNTIME_CREATED = 0x24; +Event.SLIDER_ENTITY_INITIALIZED = 0x25; +Event.START = 0x26; +Event.TOUCH_CANCEL = 0x27; +Event.TOUCH_COMPONENT_INITIALIZED = 0x28; +Event.TOUCH_END = 0x29; +Event.TOUCH_MOVE = 0x2a; +Event.TOUCH_START = 0x2b; +Event.UPDATE_FROM_INSTANCE_AFTER = 0x2c; +Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2d; +Event.UPDATE_INSTANCE_AFTER = 0x2e; +Event.UPDATE_INSTANCE_BEFORE = 0x2f; +Event.UPDATE_INSTANCE_PROPERTY = 0x30; +Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x31; +Event.MAX_EVENTS = 0x32; Event.GetEventName = function(eventId) { @@ -2316,43 +2319,42 @@ Event.GetEventName = function(eventId) { case 0xb : return 'entity_initialized'; case 0xc : return 'entity_started'; case 0xd : return 'final_initialize'; - case 0xe : return 'future_ready_state_false'; - case 0xf : return 'future_ready_state_true'; - case 0x10 : return 'get_api_url'; - case 0x11 : return 'get_runtime'; - case 0x12 : return 'get_window_size'; - case 0x13 : return 'graphics_component_initialized'; - case 0x14 : return 'image_component_initialized'; - case 0x15 : return 'image_instance_created'; - case 0x16 : return 'input_component_initialized'; - case 0x17 : return 'instance_created'; - case 0x18 : return 'instance_disposed'; - case 0x19 : return 'keyboard_down'; - case 0x1a : return 'keyboard_up'; - case 0x1b : return 'mouse_down'; - case 0x1c : return 'mouse_move'; - case 0x1d : return 'mouse_up'; - case 0x1e : return 'mouse_wheel'; - case 0x1f : return 'object_created'; - case 0x20 : return 'object_property_update'; - case 0x21 : return 'object_property_updated'; - case 0x22 : return 'pause'; - case 0x23 : return 'project_initialized'; - case 0x24 : return 'restart'; - case 0x25 : return 'runtime_created'; - case 0x26 : return 'slider_entity_initialized'; - case 0x27 : return 'start'; - case 0x28 : return 'touch_cancel'; - case 0x29 : return 'touch_component_initialized'; - case 0x2a : return 'touch_end'; - case 0x2b : return 'touch_move'; - case 0x2c : return 'touch_start'; - case 0x2d : return 'update_from_instance_after'; - case 0x2e : return 'update_from_instance_before'; - case 0x2f : return 'update_instance_after'; - case 0x30 : return 'update_instance_before'; - case 0x31 : return 'update_instance_property'; - case 0x32 : return 'update_property_from_instance'; + case 0xe : return 'get_api_url'; + case 0xf : return 'get_runtime'; + case 0x10 : return 'get_window_size'; + case 0x11 : return 'graphics_component_initialized'; + case 0x12 : return 'image_component_initialized'; + case 0x13 : return 'image_instance_created'; + case 0x14 : return 'input_component_initialized'; + case 0x15 : return 'instance_created'; + case 0x16 : return 'instance_disposed'; + case 0x17 : return 'keyboard_down'; + case 0x18 : return 'keyboard_up'; + case 0x19 : return 'mouse_down'; + case 0x1a : return 'mouse_move'; + case 0x1b : return 'mouse_up'; + case 0x1c : return 'mouse_wheel'; + case 0x1d : return 'object_created'; + case 0x1e : return 'object_property_update'; + case 0x1f : return 'object_property_updated'; + case 0x20 : return 'on_ready_state_change'; + case 0x21 : return 'pause'; + case 0x22 : return 'project_initialized'; + case 0x23 : return 'restart'; + case 0x24 : return 'runtime_created'; + case 0x25 : return 'slider_entity_initialized'; + case 0x26 : return 'start'; + case 0x27 : return 'touch_cancel'; + case 0x28 : return 'touch_component_initialized'; + case 0x29 : return 'touch_end'; + case 0x2a : return 'touch_move'; + case 0x2b : return 'touch_start'; + case 0x2c : return 'update_from_instance_after'; + case 0x2d : return 'update_from_instance_before'; + case 0x2e : return 'update_instance_after'; + case 0x2f : return 'update_instance_before'; + case 0x30 : return 'update_instance_property'; + case 0x31 : return 'update_property_from_instance'; default : throw new Error('Event type not defined : ' + eventId); } @@ -2382,8 +2384,8 @@ class R3Object extends Event { super(options); /** - * id - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client and - * server side) + * id - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client + * and server side) */ if (typeof options.id === 'undefined') { options.id = Utils.RandomId(15); @@ -2395,17 +2397,18 @@ class R3Object extends Event { options.name = this.constructor.name + '(' + options.id + ')'; } /** - * ready - Normally all objects are 'ready' to have their instances created, unless it has some required - * Object which is not present at time of construction and will be assigned later. All objects - * have multiple sets of 'required' objects which affect its 'ready' state. + * ready - Normally all objects are 'ready' to have their instances created, unless it has some + * required Object which is not present at time of construction and will be assigned later. + * All objects have multiple sets of 'required' objects which affect its 'ready' state. */ if (typeof options.ready === 'undefined') { options.ready = []; } /** - * dirty - When dirty is true, it means that this object is in transition from having a child Object to - * not having this child Object, and will probably end up in an uninitialized state. During the - * next few clock cycles this child Object will have its parent reference to this Object removed. + * dirty - When dirty is true, it means that this object is in transition from having a child Object + * to not having this child Object, and will probably end up in an uninitialized state. + * During the next few clock cycles this child Object will have its parent reference to this + * Object removed. */ if (typeof options.dirty === 'undefined') { options.dirty = false; @@ -2435,8 +2438,8 @@ class R3Object extends Event { options.children = []; } /** - * required - All Objects could have some required Objects which need to initialize before this Object can - * initialize + * required - All Objects could have some required Objects which need to initialize before this Object + * can initialize */ if (typeof options.required === 'undefined') { options.required = []; @@ -2470,6 +2473,132 @@ class R3Object extends Event { } + /** + * isReady() + * - Checks whether or not at least one set of requirements pass the ready state (i.e. required objects are + * assigned and ready) + */ + isReady() { + + if (this.required.length === 0) { + return true; + } + + for (let r = 0; r < this.required.length; r++) { + + /** + * We assume it is ready and will fail the ready test if a requirementValueCheck() fails + */ + let ready = true; + + let requirements = this.required[r]; + + for (let property in requirements) { + if (requirements.hasOwnProperty(property)) { + if (!this.requirementValueCheck(requirements[property], this[property])) { + ready = false; + } + } + } + + /** + * The ready state could have changed or not - regardless it should cascade this information in case + * new instances need to be created (ex. an image is added to an array and needs its instance created). + */ + + let readyStateChange = false; + + if (this.ready[r] !== ready) { + readyStateChange = true; + } + + this.ready[r] = ready; + + if (readyStateChange) { + if (this.ready[r]) { + this.emit( + Event.ON_READY_STATE_CHANGE, + { + r3Object: this, + readyState: R3Object.READY_STATE_TRUE, + readyStateIndex: r + } + ); + } else { + this.emit( + Event.ON_READY_STATE_CHANGE, + { + r3Object: this, + readyState: R3Object.READY_STATE_FALSE, + readyStateIndex: r + } + ); + } + } + } + + /** + * If at least one requirements set pass - return true. + */ + for (let r = 0; r < this.required.length; r++) { + if (this.ready[r]) { + return true; + } + } + + return false; + + } + + /** + * requirementValueCheck() + * - Checks whether or not the property / value pair meets the requirements of setting this ready to true. It + * handles values of type Object and Array properly. + * @param property + * @param value + */ + requirementValueCheck( + property, + value + ) { + + /** + * The property change is one of the required properties of this Object, so it affects the overall + * 'readiness' of this object. + */ + if (property instanceof Array) { + + if (!(value instanceof Array)) { + return false; + } + + if (value.length === 0) { + return false; + } + + for (let v = 0; v < value.length; v++) { + if (!(value[v] instanceof property[0])) { + return false; + } + + if (!(value[v].isReady())) { + return false; + } + } + + return true; + + } else { + + if (!(value instanceof property)) { + return false; + } + + return value.isReady(); + } + + } + } R3Object.PROJECT = 0x0; @@ -2491,6 +2620,11 @@ R3Object.COMPONENT_MESH = 0xf; R3Object.COMPONENT_TEXTURE = 0x10; R3Object.MAX_R3OBJECT = 0x11; +R3Object.READY_STATE_FALSE = 0x1; +R3Object.READY_STATE_PENDING_FALSE = 0x2; +R3Object.READY_STATE_PENDING_TRUE = 0x3; +R3Object.READY_STATE_TRUE = 0x4; + class Project extends R3Object { constructor(options) { @@ -2649,8 +2783,8 @@ class EntitySlider extends Entity { options.started = false; } /** - * subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ if (typeof options.subscriptions === 'undefined') { options.subscriptions = {}; @@ -2688,15 +2822,21 @@ class EntitySlider extends Entity { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].images = [ComponentImage]; - this.imagesBackup = options.images; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['images'] = options.images; Object.defineProperty( this, 'images', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -2705,7 +2845,7 @@ class EntitySlider extends Entity { value : x } ); - this.imagesBackup = x; + this._cache['images'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -2716,8 +2856,8 @@ class EntitySlider extends Entity { ); return x; }, - get : function() { - return this.imagesBackup; + get : () => { + return this._cache['images']; } } ) /** @@ -2726,15 +2866,21 @@ class EntitySlider extends Entity { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].canvas = ComponentCanvas; - this.canvasBackup = options.canvas; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['canvas'] = options.canvas; Object.defineProperty( this, 'canvas', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -2743,7 +2889,7 @@ class EntitySlider extends Entity { value : x } ); - this.canvasBackup = x; + this._cache['canvas'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -2754,8 +2900,8 @@ class EntitySlider extends Entity { ); return x; }, - get : function() { - return this.canvasBackup; + get : () => { + return this._cache['canvas']; } } ) /** @@ -2764,15 +2910,21 @@ class EntitySlider extends Entity { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].touch = ComponentTouch; - this.touchBackup = options.touch; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['touch'] = options.touch; Object.defineProperty( this, 'touch', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -2781,7 +2933,7 @@ class EntitySlider extends Entity { value : x } ); - this.touchBackup = x; + this._cache['touch'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -2792,8 +2944,8 @@ class EntitySlider extends Entity { ); return x; }, - get : function() { - return this.touchBackup; + get : () => { + return this._cache['touch']; } } ) @@ -2862,7 +3014,7 @@ class EntitySlider extends Entity { this.started = true; - if (this instanceof R3.Entity) { + if (this instanceof Entity) { this.emit( Event.ENTITY_STARTED, this @@ -4429,15 +4581,21 @@ class ComponentTouch extends ComponentInput { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].domComponent = ComponentDOM; - this.domComponentBackup = options.domComponent; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['domComponent'] = options.domComponent; Object.defineProperty( this, 'domComponent', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -4446,7 +4604,7 @@ class ComponentTouch extends ComponentInput { value : x } ); - this.domComponentBackup = x; + this._cache['domComponent'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -4457,8 +4615,8 @@ class ComponentTouch extends ComponentInput { ); return x; }, - get : function() { - return this.domComponentBackup; + get : () => { + return this._cache['domComponent']; } } ) @@ -4648,6 +4806,15 @@ class ComponentMaterial extends Component { } +/** + + [0]material=ComponentMaterial + [0]geometry=ComponentGeometry + [1]material=[ComponentMaterial] + [1]geometry=ComponentGeometry + + **/ + class ComponentMesh extends Component { constructor(options) { @@ -4677,6 +4844,191 @@ class ComponentMesh extends Component { options.instance = null; } + /** + * material - No comment + */ + if (typeof options.material === 'undefined') { + options.material = null; + } + + /** + * material - No comment + */ + if (typeof options.required[0] === 'undefined') { + options.required[0] = {}; + } + + options.required[0].material = ComponentMaterial; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['material'] = options.material; + Object.defineProperty( + this, + 'material', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'material', + value : x + } + ); + this._cache['material'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'material', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['material']; + } + } + ) /** + * geometry - No comment + */ + if (typeof options.required[0] === 'undefined') { + options.required[0] = {}; + } + + options.required[0].geometry = ComponentGeometry; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['geometry'] = options.geometry; + Object.defineProperty( + this, + 'geometry', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + this._cache['geometry'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['geometry']; + } + } + ) /** + * material - No comment + */ + if (typeof options.required[1] === 'undefined') { + options.required[1] = {}; + } + + options.required[1].material = [ComponentMaterial]; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['material'] = options.material; + Object.defineProperty( + this, + 'material', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'material', + value : x + } + ); + this._cache['material'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'material', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['material']; + } + } + ) /** + * geometry - No comment + */ + if (typeof options.required[1] === 'undefined') { + options.required[1] = {}; + } + + options.required[1].geometry = ComponentGeometry; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['geometry'] = options.geometry; + Object.defineProperty( + this, + 'geometry', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + this._cache['geometry'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['geometry']; + } + } + ) + for (let r = 0; r < this.required.length; r++) { this.ready[r] = true; } @@ -4720,6 +5072,21 @@ class ComponentMesh extends Component { this.emit(Event.UPDATE_INSTANCE_BEFORE, this); + if (property === 'material') { + this.instance.material = this.material; + this.emit( + Event.UPDATE_INSTANCE_PROPERTY, + { + component : this, + property : 'material', + instanceProperty : 'material' + } + ); + if (property !== 'all') { + return; + } + } + this.emit(Event.UPDATE_INSTANCE_AFTER, this); } @@ -4733,6 +5100,21 @@ class ComponentMesh extends Component { this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this); + if (property === 'material' || property === 'all') { + this.material = this.instance.material; + this.emit( + Event.UPDATE_PROPERTY_FROM_INSTANCE, + { + component : this, + property : 'material', + instanceProperty : 'material' + } + ); + if (property !== 'all') { + return; + } + } + this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this); } @@ -4830,6 +5212,368 @@ class ComponentTexture extends Component { } +class Graph { + + constructor(options) { + + if (typeof options === 'undefined') { + options = {}; + } + + /** + * open - Internal structure required for traversing the graph + */ + if (typeof options.open === 'undefined') { + options.open = []; + } + /** + * closed - Internal structure required for traversing the graph + */ + if (typeof options.closed === 'undefined') { + options.closed = []; + } + /** + * relevant - By default we traverse all parents and children of a node when performing a search + */ + if (typeof options.relevant === 'undefined') { + options.relevant = ['parents', 'children']; + } + /** + * solutions - Internal structure for holding solutions from n0 to n. n passed the goalFunction() test. + */ + if (typeof options.solutions === 'undefined') { + options.solutions = []; + } + /** + * terminateOnFirstGoal - By default we want to collect all goal nodes which pass the goalFunction(). Set this to + * true to terminate immediately after discovering the first goal node. + */ + if (typeof options.terminateOnFirstGoal === 'undefined') { + options.terminateOnFirstGoal = false; + } + /** + * startNode - The start node from which the graph will build + */ + if (typeof options.startNode === 'undefined') { + options.startNode = null; + } + /** + * goalFunction - By having no goal as a default, on construction of a Graph object we will traverse and + * build the entire graph starting from the startNode. + */ + if (typeof options.goalFunction === 'undefined') { + options.goalFunction = (node)=>{return false;}; + } + + Object.assign(this, options); + + if (this.startNode) { + this.build(); + } + } + + /** + * build() + * - Uses A* algorithm to build a graph of all nodes which represents the dependency structure of this graph. + */ + build() { + + if (this.startNode === null) { + throw new Error('startNode cannot be null'); + } + + /** + * Step 1. Push start node on open[] + */ + this.open.push(this.startNode); + + /** + * Step 2. Clear the closed[] list (we also clear the solutions[] list because we maintain it this way) + */ + this.closed = []; + this.solutions = []; + + /** + * Start with step 3 to 8 + */ + this.process(); + + } + + /** + * process() + * - Repeats steps 3 to 8. Should indicate whether a goal node was found. + */ + process() { + + /** + * Step 3. If open[] is empty - exit with failure + */ + if (this.open.length === 0) { + console.log('open[] is empty'); + return false; + } + + /** + * Step 4. Select first node on open[] - remove it from open[] and put it on closed[] + */ + let node = this.open.pop(); + this.closed.push(node); + + /** + * Step 5. If node is a goal function - exit successfully (or continue if we do not terminate on first goal) + */ + if (this.goalFunction(node)) { + + this.solutions.push(this.buildSolution(node)); + + if (this.terminateOnFirstGoal) { + return this.solutions[0]; + } + + } + + /** + * Step 6.a Expand node n, generating the set M of its successors that are not already ancestors of n in G. + */ + let M = this.expand(node); + + /** + * Step 7 - Establish pointers to node + */ + this.establishPointers(M, node); + + /** + * Step 8 - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved + * in favor of the deepest node in the search tree. + * We skip this step because we are not so interested in the shortest path to the solution (yet, for now at least) + */ + //this.reOrder(); + + /** + * Continue back to step 3 + */ + this.process(); + + } + + /** + * expand() + * - Expands a node generating a set M of its successors which are not already ancestors of the node (n) in the + * graph (G). i.e. *NOT* already in either OPEN or CLOSED. Install those members of M as successors of n in G. + * @param node + */ + expand(node) { + + let successors = { + onOpen : [], + onClosed : [], + notInG : [] + }; + + for (let r = 0; r < this.relevant.length; r++) { + + let relevant = this.relevant[r]; + + for (let n = 0; n < node.object[relevant].length; n++) { + + let notInG = true; + + /** + * Check if this child is part of an open[] node + */ + let onOpen = this.open.reduce( + (onOpen, openNode) => { + if (openNode.object === node.object[relevant][n]) { + onOpen = true; + notInG = false; + } + return onOpen; + }, + false + ); + + let onClosed = this.closed.reduce( + (onClosed, closedNode) => { + if (closedNode.object === node.object[relevant][n]) { + onClosed = true; + notInG = false; + } + return onClosed; + }, + false + ); + + let type = 'child'; + + if (relevant === 'parents') { + type = 'parent'; + } + + let newNode = new Node( + { + object: node.object[relevant][n], + type: type + } + ); + + if (onOpen) { + successors.onOpen.push(newNode); + } + + if (onClosed) { + successors.onClosed.push(newNode); + } + + if (notInG) { + successors.notInG.push(newNode); + } + + } + } + + /** + * Return the set of successors (M) to be used later in processing + */ + return successors; + + + } + + /** + * establishPointers() + * - Establish a pointer to n from each of those members of M that were not already in G. Add these members of M to + * OPEN. For each member M that was already on OPEN or CLOSED, update the pointer to point to n if the best path + * so far is through n. For each member of M that was already on CLOSED, redirect the pointers of each of its + * descendants in G so that they point backward along the best paths found so far to these descendants. + * @param M + * @param node + */ + establishPointers( + M, + node + ) { + + /** + * We now have a list of successors (M) which is not already an ancestor of n in G. + * Install them as successors of n in G. We do part of step 7 here to save some processing steps: + * We additionally set the pointer of the successor to n, and we push the successor to OPEN. + */ + M.notInG.map( + (successor) => { + successor.pointer = node; + node.successors.push(successor); + this.open.push(successor); + } + ) + + /** + * Redirect pointers of successors that were in OPEN to n + */ + M.onOpen.map( + (successor) => { + successor.pointer = node; + } + ); + + /** + * Redirect pointers of successors that were in CLOSED to n + */ + M.onClosed.map( + (successor) => { + successor.pointer = node; + /** + * We skip a part of 7 here - we could alternatively redirect the pointers of each descendant of the successor + * in G to point backward along the best paths found so far to these descendants - but we don't do this because + * we are not really interested in the shortest paths - + */ + } + ) + + } + + /** + * reOrder() + * - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved in favor of + * the deepest node in the search tree. + */ + reOrder() { + + } + + /** + * buildSolution() + * - Traverses node pointers from n (goal node) to n0 (start node) and stores the path in a solution list. + * @param node + * @param solution=[] + */ + buildSolution( + node, + solution=[] + ) { + + solution.push(node); + + if (node.pointer) { + this.buildSolution(node.pointer, solution); + } else { + return solution; + } + + } + + /** + * isGoal() + * - No comment + * @param callback + */ + isGoal(callback) { + + return callback(); + + } + +} + +class Node { + + constructor(options) { + + if (typeof options === 'undefined') { + options = {}; + } + + /** + * object - No comment + */ + if (typeof options.object === 'undefined') { + options.object = null; + } + /** + * pointer - No comment + */ + if (typeof options.pointer === 'undefined') { + options.pointer = null; + } + /** + * type - No comment + */ + if (typeof options.type === 'undefined') { + options.type = 'start-node'; + } + /** + * successors - No comment + */ + if (typeof options.successors === 'undefined') { + options.successors = []; + } + + Object.assign(this, options); + + } + +} + class Utils { constructor(options) { @@ -6056,6 +6800,7 @@ Runtime.Coder = RuntimeCoder; Runtime.Coder.CodeMirror = RuntimeCodeMirror; Runtime.DOM = RuntimeDOM; Runtime.DOM.Document = RuntimeDocument; +Runtime.DOM.JsDOM = RuntimeJsDOM; Runtime.GUI = RuntimeGUI; Runtime.GUI.ControlKit = RuntimeControlKit; Runtime.Graphics = RuntimeGraphics; @@ -6078,6 +6823,8 @@ System.Storage = SystemStorage; R3.System = System; R3.Runtime = Runtime; R3.Event = Event; +R3.Graph = Graph; +R3.Node = Node; R3.Utils = Utils; R3.Object = R3Object; R3.Project = Project; diff --git a/package-lock.json b/package-lock.json index 3138655..6d43560 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "r3", - "version": "3.0.117", + "version": "3.0.333", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -141,6 +141,11 @@ } } }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, "@types/body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", @@ -244,6 +249,11 @@ "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==" }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -253,11 +263,60 @@ "negotiator": "0.6.2" } }, + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + } + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -283,6 +342,11 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -334,6 +398,11 @@ "concat-map": "0.0.1" } }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -367,6 +436,14 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -410,6 +487,36 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + } + } + }, + "data-urls": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.1.tgz", + "integrity": "sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==", + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -418,6 +525,11 @@ "ms": "2.0.0" } }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==" + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -426,6 +538,16 @@ "type-detect": "^4.0.0" } }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -441,6 +563,14 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" }, + "domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "requires": { + "webidl-conversions": "^7.0.0" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -539,6 +669,33 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -586,6 +743,11 @@ "vary": "~1.1.2" } }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -605,6 +767,16 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -668,6 +840,14 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -687,6 +867,55 @@ } } }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -745,6 +974,11 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -763,6 +997,56 @@ "argparse": "^2.0.1" } }, + "jsdom": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-18.0.0.tgz", + "integrity": "sha512-HVLuBcFmwdWulStv5U+J59b1AyzXhM92KXlM8HQ3ecYtRM2OQEUCPMa4oNuDeCBmtRcC7tJvb0Xz5OeFXMOKTA==", + "requires": { + "abab": "^2.0.5", + "acorn": "^8.5.0", + "acorn-globals": "^6.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.1", + "decimal.js": "^10.3.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^10.0.0", + "ws": "^8.2.3", + "xml-name-validator": "^4.0.0" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + } + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1181,6 +1465,11 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1197,6 +1486,19 @@ "wrappy": "1" } }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -1213,6 +1515,11 @@ "p-limit": "^3.0.2" } }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, "parseqs": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", @@ -1248,6 +1555,11 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1257,6 +1569,16 @@ "ipaddr.js": "1.9.1" } }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", @@ -1306,6 +1628,14 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "requires": { + "xmlchars": "^2.2.0" + } + }, "send": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", @@ -1478,6 +1808,12 @@ } } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -1506,6 +1842,11 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", @@ -1516,6 +1857,32 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + } + }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -1535,6 +1902,11 @@ "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.6.tgz", "integrity": "sha512-68H97HffZoFaa3HFtpstahWorN9dSp5uTU6jo3GjIQ6JkJBR3hC2Nx/e/HFOoYHdUyT/Z1MRWfxN1EiQJZUyCQ==" }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1550,6 +1922,59 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "requires": { + "xml-name-validator": "^4.0.0" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "requires": { + "iconv-lite": "0.6.3" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==" + }, + "whatwg-url": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", + "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -1558,6 +1983,11 @@ "string-width": "^1.0.2 || 2" } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, "workerpool": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.4.tgz", @@ -1573,6 +2003,16 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==" + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, "xmlhttprequest-ssl": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", diff --git a/package.json b/package.json index 6b14106..18ac1b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "r3", - "version": "3.0.262", + "version": "3.0.339", "description": "", "private": true, "dependencies": { @@ -8,6 +8,7 @@ "@feathersjs/feathers": "^4.5.3", "@feathersjs/socketio": "^4.5.3", "chai": "^4.3.4", + "jsdom": "^18.0.0", "mocha": "^9.0.0" }, "scripts": { diff --git a/r3.php b/r3.php index 2325cda..0779aac 100755 --- a/r3.php +++ b/r3.php @@ -594,7 +594,7 @@ function extractOption($item, $template) $numSpaces = strlen($str); } - $comment = wordwrap($comment, 95, "\n" . str_pad('', $numSpaces, ' ', STR_PAD_LEFT) . "* "); + $comment = wordwrap($comment, 90, "\n" . str_pad('', $numSpaces, ' ', STR_PAD_LEFT) . "* "); } $updated = str_replace('COMMENT', $comment, $template); $updated = str_replace('KEY', $key, $updated); diff --git a/src/r3/index.js b/src/r3/index.js index fde9de3..59cfa82 100644 --- a/src/r3/index.js +++ b/src/r3/index.js @@ -3,6 +3,8 @@ const R3 = require('./r3.js'); const System = require('./r3-system/'); const Runtime = require('./r3-runtime/'); const Event = require('./r3-event.js'); +const Graph = require('./r3-graph.js'); +const Node = require('./r3-node.js'); const Utils = require('./r3-utils.js'); const R3Object = require('./r3-object/'); const Project = require('./r3-object/r3-project.js'); @@ -14,6 +16,8 @@ const Component = require('./r3-component/'); R3.System = System; R3.Runtime = Runtime; R3.Event = Event; +R3.Graph = Graph; +R3.Node = Node; R3.Utils = Utils; R3.Object = R3Object; R3.Project = Project; diff --git a/src/r3/r3-component/r3-component-mesh.js b/src/r3/r3-component/r3-component-mesh.js index f6cc3a8..42ebb1f 100644 --- a/src/r3/r3-component/r3-component-mesh.js +++ b/src/r3/r3-component/r3-component-mesh.js @@ -19,9 +19,14 @@ const Event = require('../r3-event.js'); TEMPLATE_OPTIONS_END CUSTOM_OPTIONS_START + material=null CUSTOM_OPTIONS_END CUSTOM_REQUIRED_COMPONENTS_START + [0]material=ComponentMaterial + [0]geometry=ComponentGeometry + [1]material=[ComponentMaterial] + [1]geometry=ComponentGeometry CUSTOM_REQUIRED_COMPONENTS_END TEMPLATE_STATIC_OPTIONS_START @@ -93,9 +98,192 @@ class ComponentMesh extends Component { //GENERATED_TEMPLATE_OPTIONS_INIT_END //GENERATED_OPTIONS_INIT_START + /** + * material - No comment + */ + if (typeof options.material === 'undefined') { + options.material = null; + } //GENERATED_OPTIONS_INIT_END //GENERATED_REQUIRED_COMPONENTS_START + /** + * material - No comment + */ + if (typeof options.required[0] === 'undefined') { + options.required[0] = {}; + } + + options.required[0].material = ComponentMaterial; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['material'] = options.material; + Object.defineProperty( + this, + 'material', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'material', + value : x + } + ); + this._cache['material'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'material', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['material']; + } + } + ) /** + * geometry - No comment + */ + if (typeof options.required[0] === 'undefined') { + options.required[0] = {}; + } + + options.required[0].geometry = ComponentGeometry; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['geometry'] = options.geometry; + Object.defineProperty( + this, + 'geometry', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + this._cache['geometry'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['geometry']; + } + } + ) /** + * material - No comment + */ + if (typeof options.required[1] === 'undefined') { + options.required[1] = {}; + } + + options.required[1].material = [ComponentMaterial]; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['material'] = options.material; + Object.defineProperty( + this, + 'material', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'material', + value : x + } + ); + this._cache['material'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'material', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['material']; + } + } + ) /** + * geometry - No comment + */ + if (typeof options.required[1] === 'undefined') { + options.required[1] = {}; + } + + options.required[1].geometry = ComponentGeometry; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['geometry'] = options.geometry; + Object.defineProperty( + this, + 'geometry', + { + configurable : true, + enumerable : true, + set: (x) => { + Event.Emit( + Event.OBJECT_PROPERTY_UPDATE, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + this._cache['geometry'] = x; + Event.Emit( + Event.OBJECT_PROPERTY_UPDATED, + { + r3Object : this, + property : 'geometry', + value : x + } + ); + return x; + }, + get : () => { + return this._cache['geometry']; + } + } + ) //GENERATED_REQUIRED_COMPONENTS_END //GENERATED_AFTER_REQUIRED_COMPONENTS_START @@ -163,6 +351,20 @@ class ComponentMesh extends Component { this.emit(Event.UPDATE_INSTANCE_BEFORE, this); //GENERATED_UPDATE_INSTANCE_OPTIONS_START + if (property === 'material') { + this.instance.material = this.material; + this.emit( + Event.UPDATE_INSTANCE_PROPERTY, + { + component : this, + property : 'material', + instanceProperty : 'material' + } + ); + if (property !== 'all') { + return; + } + } //GENERATED_UPDATE_INSTANCE_OPTIONS_END //GENERATED_TEMPLATE_UPDATE_INSTANCE_OPTIONS_START @@ -190,6 +392,20 @@ class ComponentMesh extends Component { this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this); //GENERATED_UPDATE_FROM_INSTANCE_OPTIONS_START + if (property === 'material' || property === 'all') { + this.material = this.instance.material; + this.emit( + Event.UPDATE_PROPERTY_FROM_INSTANCE, + { + component : this, + property : 'material', + instanceProperty : 'material' + } + ); + if (property !== 'all') { + return; + } + } //GENERATED_UPDATE_FROM_INSTANCE_OPTIONS_END //GENERATED_TEMPLATE_UPDATE_FROM_INSTANCE_OPTIONS_START diff --git a/src/r3/r3-component/r3-component-touch.js b/src/r3/r3-component/r3-component-touch.js index 2f62e68..eb6c68d 100644 --- a/src/r3/r3-component/r3-component-touch.js +++ b/src/r3/r3-component/r3-component-touch.js @@ -112,15 +112,21 @@ class ComponentTouch extends ComponentInput { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].domComponent = ComponentDOM; - this.domComponentBackup = options.domComponent; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['domComponent'] = options.domComponent; Object.defineProperty( this, 'domComponent', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -129,7 +135,7 @@ class ComponentTouch extends ComponentInput { value : x } ); - this.domComponentBackup = x; + this._cache['domComponent'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -140,8 +146,8 @@ class ComponentTouch extends ComponentInput { ); return x; }, - get : function() { - return this.domComponentBackup; + get : () => { + return this._cache['domComponent']; } } ) diff --git a/src/r3/r3-entity/r3-entity-slider.js b/src/r3/r3-entity/r3-entity-slider.js index 7edea1c..6a5a893 100644 --- a/src/r3/r3-entity/r3-entity-slider.js +++ b/src/r3/r3-entity/r3-entity-slider.js @@ -102,8 +102,8 @@ class EntitySlider extends Entity { options.started = false; } /** - * subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ if (typeof options.subscriptions === 'undefined') { options.subscriptions = {}; @@ -145,15 +145,21 @@ class EntitySlider extends Entity { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].images = [ComponentImage]; - this.imagesBackup = options.images; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['images'] = options.images; Object.defineProperty( this, 'images', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -162,7 +168,7 @@ class EntitySlider extends Entity { value : x } ); - this.imagesBackup = x; + this._cache['images'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -173,8 +179,8 @@ class EntitySlider extends Entity { ); return x; }, - get : function() { - return this.imagesBackup; + get : () => { + return this._cache['images']; } } ) /** @@ -183,15 +189,21 @@ class EntitySlider extends Entity { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].canvas = ComponentCanvas; - this.canvasBackup = options.canvas; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['canvas'] = options.canvas; Object.defineProperty( this, 'canvas', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -200,7 +212,7 @@ class EntitySlider extends Entity { value : x } ); - this.canvasBackup = x; + this._cache['canvas'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -211,8 +223,8 @@ class EntitySlider extends Entity { ); return x; }, - get : function() { - return this.canvasBackup; + get : () => { + return this._cache['canvas']; } } ) /** @@ -221,15 +233,21 @@ class EntitySlider extends Entity { if (typeof options.required[0] === 'undefined') { options.required[0] = {}; } + options.required[0].touch = ComponentTouch; - this.touchBackup = options.touch; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['touch'] = options.touch; Object.defineProperty( this, 'touch', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -238,7 +256,7 @@ class EntitySlider extends Entity { value : x } ); - this.touchBackup = x; + this._cache['touch'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -249,8 +267,8 @@ class EntitySlider extends Entity { ); return x; }, - get : function() { - return this.touchBackup; + get : () => { + return this._cache['touch']; } } ) @@ -347,7 +365,7 @@ class EntitySlider extends Entity { this.started = true; - if (this instanceof R3.Entity) { + if (this instanceof Entity) { this.emit( Event.ENTITY_STARTED, this diff --git a/src/r3/r3-event.js b/src/r3/r3-event.js index 1ba5d48..331d18f 100644 --- a/src/r3/r3-event.js +++ b/src/r3/r3-event.js @@ -372,44 +372,43 @@ Event.ENTITY_CREATED = 0xa; Event.ENTITY_INITIALIZED = 0xb; Event.ENTITY_STARTED = 0xc; Event.FINAL_INITIALIZE = 0xd; -Event.FUTURE_READY_STATE_FALSE = 0xe; -Event.FUTURE_READY_STATE_TRUE = 0xf; -Event.GET_API_URL = 0x10; -Event.GET_RUNTIME = 0x11; -Event.GET_WINDOW_SIZE = 0x12; -Event.GRAPHICS_COMPONENT_INITIALIZED = 0x13; -Event.IMAGE_COMPONENT_INITIALIZED = 0x14; -Event.IMAGE_INSTANCE_CREATED = 0x15; -Event.INPUT_COMPONENT_INITIALIZED = 0x16; -Event.INSTANCE_CREATED = 0x17; -Event.INSTANCE_DISPOSED = 0x18; -Event.KEYBOARD_DOWN = 0x19; -Event.KEYBOARD_UP = 0x1a; -Event.MOUSE_DOWN = 0x1b; -Event.MOUSE_MOVE = 0x1c; -Event.MOUSE_UP = 0x1d; -Event.MOUSE_WHEEL = 0x1e; -Event.OBJECT_CREATED = 0x1f; -Event.OBJECT_PROPERTY_UPDATE = 0x20; -Event.OBJECT_PROPERTY_UPDATED = 0x21; -Event.PAUSE = 0x22; -Event.PROJECT_INITIALIZED = 0x23; -Event.RESTART = 0x24; -Event.RUNTIME_CREATED = 0x25; -Event.SLIDER_ENTITY_INITIALIZED = 0x26; -Event.START = 0x27; -Event.TOUCH_CANCEL = 0x28; -Event.TOUCH_COMPONENT_INITIALIZED = 0x29; -Event.TOUCH_END = 0x2a; -Event.TOUCH_MOVE = 0x2b; -Event.TOUCH_START = 0x2c; -Event.UPDATE_FROM_INSTANCE_AFTER = 0x2d; -Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2e; -Event.UPDATE_INSTANCE_AFTER = 0x2f; -Event.UPDATE_INSTANCE_BEFORE = 0x30; -Event.UPDATE_INSTANCE_PROPERTY = 0x31; -Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x32; -Event.MAX_EVENTS = 0x33; +Event.GET_API_URL = 0xe; +Event.GET_RUNTIME = 0xf; +Event.GET_WINDOW_SIZE = 0x10; +Event.GRAPHICS_COMPONENT_INITIALIZED = 0x11; +Event.IMAGE_COMPONENT_INITIALIZED = 0x12; +Event.IMAGE_INSTANCE_CREATED = 0x13; +Event.INPUT_COMPONENT_INITIALIZED = 0x14; +Event.INSTANCE_CREATED = 0x15; +Event.INSTANCE_DISPOSED = 0x16; +Event.KEYBOARD_DOWN = 0x17; +Event.KEYBOARD_UP = 0x18; +Event.MOUSE_DOWN = 0x19; +Event.MOUSE_MOVE = 0x1a; +Event.MOUSE_UP = 0x1b; +Event.MOUSE_WHEEL = 0x1c; +Event.OBJECT_CREATED = 0x1d; +Event.OBJECT_PROPERTY_UPDATE = 0x1e; +Event.OBJECT_PROPERTY_UPDATED = 0x1f; +Event.ON_READY_STATE_CHANGE = 0x20; +Event.PAUSE = 0x21; +Event.PROJECT_INITIALIZED = 0x22; +Event.RESTART = 0x23; +Event.RUNTIME_CREATED = 0x24; +Event.SLIDER_ENTITY_INITIALIZED = 0x25; +Event.START = 0x26; +Event.TOUCH_CANCEL = 0x27; +Event.TOUCH_COMPONENT_INITIALIZED = 0x28; +Event.TOUCH_END = 0x29; +Event.TOUCH_MOVE = 0x2a; +Event.TOUCH_START = 0x2b; +Event.UPDATE_FROM_INSTANCE_AFTER = 0x2c; +Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2d; +Event.UPDATE_INSTANCE_AFTER = 0x2e; +Event.UPDATE_INSTANCE_BEFORE = 0x2f; +Event.UPDATE_INSTANCE_PROPERTY = 0x30; +Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x31; +Event.MAX_EVENTS = 0x32; Event.GetEventName = function(eventId) { @@ -427,43 +426,42 @@ Event.GetEventName = function(eventId) { case 0xb : return 'entity_initialized'; case 0xc : return 'entity_started'; case 0xd : return 'final_initialize'; - case 0xe : return 'future_ready_state_false'; - case 0xf : return 'future_ready_state_true'; - case 0x10 : return 'get_api_url'; - case 0x11 : return 'get_runtime'; - case 0x12 : return 'get_window_size'; - case 0x13 : return 'graphics_component_initialized'; - case 0x14 : return 'image_component_initialized'; - case 0x15 : return 'image_instance_created'; - case 0x16 : return 'input_component_initialized'; - case 0x17 : return 'instance_created'; - case 0x18 : return 'instance_disposed'; - case 0x19 : return 'keyboard_down'; - case 0x1a : return 'keyboard_up'; - case 0x1b : return 'mouse_down'; - case 0x1c : return 'mouse_move'; - case 0x1d : return 'mouse_up'; - case 0x1e : return 'mouse_wheel'; - case 0x1f : return 'object_created'; - case 0x20 : return 'object_property_update'; - case 0x21 : return 'object_property_updated'; - case 0x22 : return 'pause'; - case 0x23 : return 'project_initialized'; - case 0x24 : return 'restart'; - case 0x25 : return 'runtime_created'; - case 0x26 : return 'slider_entity_initialized'; - case 0x27 : return 'start'; - case 0x28 : return 'touch_cancel'; - case 0x29 : return 'touch_component_initialized'; - case 0x2a : return 'touch_end'; - case 0x2b : return 'touch_move'; - case 0x2c : return 'touch_start'; - case 0x2d : return 'update_from_instance_after'; - case 0x2e : return 'update_from_instance_before'; - case 0x2f : return 'update_instance_after'; - case 0x30 : return 'update_instance_before'; - case 0x31 : return 'update_instance_property'; - case 0x32 : return 'update_property_from_instance'; + case 0xe : return 'get_api_url'; + case 0xf : return 'get_runtime'; + case 0x10 : return 'get_window_size'; + case 0x11 : return 'graphics_component_initialized'; + case 0x12 : return 'image_component_initialized'; + case 0x13 : return 'image_instance_created'; + case 0x14 : return 'input_component_initialized'; + case 0x15 : return 'instance_created'; + case 0x16 : return 'instance_disposed'; + case 0x17 : return 'keyboard_down'; + case 0x18 : return 'keyboard_up'; + case 0x19 : return 'mouse_down'; + case 0x1a : return 'mouse_move'; + case 0x1b : return 'mouse_up'; + case 0x1c : return 'mouse_wheel'; + case 0x1d : return 'object_created'; + case 0x1e : return 'object_property_update'; + case 0x1f : return 'object_property_updated'; + case 0x20 : return 'on_ready_state_change'; + case 0x21 : return 'pause'; + case 0x22 : return 'project_initialized'; + case 0x23 : return 'restart'; + case 0x24 : return 'runtime_created'; + case 0x25 : return 'slider_entity_initialized'; + case 0x26 : return 'start'; + case 0x27 : return 'touch_cancel'; + case 0x28 : return 'touch_component_initialized'; + case 0x29 : return 'touch_end'; + case 0x2a : return 'touch_move'; + case 0x2b : return 'touch_start'; + case 0x2c : return 'update_from_instance_after'; + case 0x2d : return 'update_from_instance_before'; + case 0x2e : return 'update_instance_after'; + case 0x2f : return 'update_instance_before'; + case 0x30 : return 'update_instance_property'; + case 0x31 : return 'update_property_from_instance'; default : throw new Error('Event type not defined : ' + eventId); } diff --git a/src/r3/r3-graph.js b/src/r3/r3-graph.js new file mode 100644 index 0000000..c41742c --- /dev/null +++ b/src/r3/r3-graph.js @@ -0,0 +1,479 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +const Node = require('./r3-node.js'); +//CUSTOM_IMPORTS_END + +/** + + GENERATED_INHERITED_START + + GENERATED_INHERITED_END + + TEMPLATE_OPTIONS_START + TEMPLATE_OPTIONS_END + + CUSTOM_OPTIONS_START + open=[] - Internal structure required for traversing the graph + closed=[] - Internal structure required for traversing the graph + relevant=['parents', 'children'] - By default we traverse all parents and children of a node when performing a search + solutions=[] - Internal structure for holding solutions from n0 to n. n passed the goalFunction() test. + terminateOnFirstGoal=false - By default we want to collect all goal nodes which pass the goalFunction(). Set this to true to terminate immediately after discovering the first goal node. + startNode=null - The start node from which the graph will build + goalFunction=(node)=>{return false;} - By having no goal as a default, on construction of a Graph object we will traverse and build the entire graph starting from the startNode. + CUSTOM_OPTIONS_END + + TEMPLATE_STATIC_OPTIONS_START + TEMPLATE_STATIC_OPTIONS_END + + CUSTOM_STATIC_OPTIONS_START + CUSTOM_STATIC_OPTIONS_END + + TEMPLATE_METHODS_START + TEMPLATE_METHODS_END + + CUSTOM_METHODS_START + build() - Uses A* algorithm to build a graph of all nodes which represents the dependency structure of this graph. + process() - Repeats steps 3 to 8. Should indicate whether a goal node was found. + expand(node) - Expands a node generating a set M of its successors which are not already ancestors of the node (n) in the graph (G). i.e. *NOT* already in either OPEN or CLOSED. Install those members of M as successors of n in G. + establishPointers(M, node) - Establish a pointer to n from each of those members of M that were not already in G. Add these members of M to OPEN. For each member M that was already on OPEN or CLOSED, update the pointer to point to n if the best path so far is through n. For each member of M that was already on CLOSED, redirect the pointers of each of its descendants in G so that they point backward along the best paths found so far to these descendants. + reOrder() - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved in favor of the deepest node in the search tree. + buildSolution(node, solution=[]) - Traverses node pointers from n (goal node) to n0 (start node) and stores the path in a solution list. + isGoal(callback) + CUSTOM_METHODS_END + + TEMPLATE_STATIC_METHODS_START + TEMPLATE_STATIC_METHODS_END + + CUSTOM_STATIC_METHODS_START + CUSTOM_STATIC_METHODS_END + + **/ + +class Graph { + + //GENERATED_CONSTRUCTOR_START + constructor(options) { + + if (typeof options === 'undefined') { + options = {}; + } + + //GENERATED_TEMPLATE_OPTIONS_INIT_START + //GENERATED_TEMPLATE_OPTIONS_INIT_END + + //GENERATED_OPTIONS_INIT_START + /** + * open - Internal structure required for traversing the graph + */ + if (typeof options.open === 'undefined') { + options.open = []; + } + /** + * closed - Internal structure required for traversing the graph + */ + if (typeof options.closed === 'undefined') { + options.closed = []; + } + /** + * relevant - By default we traverse all parents and children of a node when performing a search + */ + if (typeof options.relevant === 'undefined') { + options.relevant = ['parents', 'children']; + } + /** + * solutions - Internal structure for holding solutions from n0 to n. n passed the goalFunction() test. + */ + if (typeof options.solutions === 'undefined') { + options.solutions = []; + } + /** + * terminateOnFirstGoal - By default we want to collect all goal nodes which pass the goalFunction(). Set this to + * true to terminate immediately after discovering the first goal node. + */ + if (typeof options.terminateOnFirstGoal === 'undefined') { + options.terminateOnFirstGoal = false; + } + /** + * startNode - The start node from which the graph will build + */ + if (typeof options.startNode === 'undefined') { + options.startNode = null; + } + /** + * goalFunction - By having no goal as a default, on construction of a Graph object we will traverse and + * build the entire graph starting from the startNode. + */ + if (typeof options.goalFunction === 'undefined') { + options.goalFunction = (node)=>{return false;}; + } + //GENERATED_OPTIONS_INIT_END + + //CUSTOM_OPTIONS_INIT_START + //CUSTOM_OPTIONS_INIT_END + + Object.assign(this, options); + + //CUSTOM_BEFORE_INIT_START + //CUSTOM_BEFORE_INIT_END + + //CUSTOM_AFTER_INIT_START + if (this.startNode) { + this.build(); + } + //CUSTOM_AFTER_INIT_END + } + //GENERATED_CONSTRUCTOR_END + + //GENERATED_TEMPLATE_METHODS_START + //GENERATED_TEMPLATE_METHODS_END + + //GENERATED_METHODS_START + + /** + * build() + * - Uses A* algorithm to build a graph of all nodes which represents the dependency structure of this graph. + */ + build() { + + //GENERATED_BUILD_METHOD_START + //GENERATED_BUILD_METHOD_END + + //CUSTOM_BUILD_METHOD_START + if (this.startNode === null) { + throw new Error('startNode cannot be null'); + } + + /** + * Step 1. Push start node on open[] + */ + this.open.push(this.startNode); + + /** + * Step 2. Clear the closed[] list (we also clear the solutions[] list because we maintain it this way) + */ + this.closed = []; + this.solutions = []; + + /** + * Start with step 3 to 8 + */ + this.process(); + //CUSTOM_BUILD_METHOD_END + + //GENERATED_BUILD_METHOD_AFTER_START + //GENERATED_BUILD_METHOD_AFTER_END + + } + + /** + * process() + * - Repeats steps 3 to 8. Should indicate whether a goal node was found. + */ + process() { + + //GENERATED_PROCESS_METHOD_START + //GENERATED_PROCESS_METHOD_END + + //CUSTOM_PROCESS_METHOD_START + /** + * Step 3. If open[] is empty - exit with failure + */ + if (this.open.length === 0) { + console.log('open[] is empty'); + return false; + } + + /** + * Step 4. Select first node on open[] - remove it from open[] and put it on closed[] + */ + let node = this.open.pop(); + this.closed.push(node); + + /** + * Step 5. If node is a goal function - exit successfully (or continue if we do not terminate on first goal) + */ + if (this.goalFunction(node)) { + + this.solutions.push(this.buildSolution(node)); + + if (this.terminateOnFirstGoal) { + return this.solutions[0]; + } + + } + + /** + * Step 6.a Expand node n, generating the set M of its successors that are not already ancestors of n in G. + */ + let M = this.expand(node); + + /** + * Step 7 - Establish pointers to node + */ + this.establishPointers(M, node); + + /** + * Step 8 - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved + * in favor of the deepest node in the search tree. + * We skip this step because we are not so interested in the shortest path to the solution (yet, for now at least) + */ + //this.reOrder(); + + /** + * Continue back to step 3 + */ + this.process(); + //CUSTOM_PROCESS_METHOD_END + + //GENERATED_PROCESS_METHOD_AFTER_START + //GENERATED_PROCESS_METHOD_AFTER_END + + } + + /** + * expand() + * - Expands a node generating a set M of its successors which are not already ancestors of the node (n) in the + * graph (G). i.e. *NOT* already in either OPEN or CLOSED. Install those members of M as successors of n in G. + * @param node + */ + expand(node) { + + //GENERATED_EXPAND_METHOD_START + //GENERATED_EXPAND_METHOD_END + + //CUSTOM_EXPAND_METHOD_START + + let successors = { + onOpen : [], + onClosed : [], + notInG : [] + }; + + for (let r = 0; r < this.relevant.length; r++) { + + let relevant = this.relevant[r]; + + for (let n = 0; n < node.object[relevant].length; n++) { + + let notInG = true; + + /** + * Check if this child is part of an open[] node + */ + let onOpen = this.open.reduce( + (onOpen, openNode) => { + if (openNode.object === node.object[relevant][n]) { + onOpen = true; + notInG = false; + } + return onOpen; + }, + false + ); + + let onClosed = this.closed.reduce( + (onClosed, closedNode) => { + if (closedNode.object === node.object[relevant][n]) { + onClosed = true; + notInG = false; + } + return onClosed; + }, + false + ); + + let type = 'child'; + + if (relevant === 'parents') { + type = 'parent'; + } + + let newNode = new Node( + { + object: node.object[relevant][n], + type: type + } + ); + + if (onOpen) { + successors.onOpen.push(newNode); + } + + if (onClosed) { + successors.onClosed.push(newNode); + } + + if (notInG) { + successors.notInG.push(newNode); + } + + } + } + + /** + * Return the set of successors (M) to be used later in processing + */ + return successors; + + //CUSTOM_EXPAND_METHOD_END + + //GENERATED_EXPAND_METHOD_AFTER_START + //GENERATED_EXPAND_METHOD_AFTER_END + + } + + /** + * establishPointers() + * - Establish a pointer to n from each of those members of M that were not already in G. Add these members of M to + * OPEN. For each member M that was already on OPEN or CLOSED, update the pointer to point to n if the best path + * so far is through n. For each member of M that was already on CLOSED, redirect the pointers of each of its + * descendants in G so that they point backward along the best paths found so far to these descendants. + * @param M + * @param node + */ + establishPointers( + M, + node + ) { + + //GENERATED_ESTABLISH_POINTERS_METHOD_START + //GENERATED_ESTABLISH_POINTERS_METHOD_END + + //CUSTOM_ESTABLISH_POINTERS_METHOD_START + + /** + * We now have a list of successors (M) which is not already an ancestor of n in G. + * Install them as successors of n in G. We do part of step 7 here to save some processing steps: + * We additionally set the pointer of the successor to n, and we push the successor to OPEN. + */ + M.notInG.map( + (successor) => { + successor.pointer = node; + node.successors.push(successor); + this.open.push(successor); + } + ) + + /** + * Redirect pointers of successors that were in OPEN to n + */ + M.onOpen.map( + (successor) => { + successor.pointer = node; + } + ); + + /** + * Redirect pointers of successors that were in CLOSED to n + */ + M.onClosed.map( + (successor) => { + successor.pointer = node; + /** + * We skip a part of 7 here - we could alternatively redirect the pointers of each descendant of the successor + * in G to point backward along the best paths found so far to these descendants - but we don't do this because + * we are not really interested in the shortest paths - + */ + } + ) + + //CUSTOM_ESTABLISH_POINTERS_METHOD_END + + //GENERATED_ESTABLISH_POINTERS_METHOD_AFTER_START + //GENERATED_ESTABLISH_POINTERS_METHOD_AFTER_END + + } + + /** + * reOrder() + * - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved in favor of + * the deepest node in the search tree. + */ + reOrder() { + + //GENERATED_RE_ORDER_METHOD_START + //GENERATED_RE_ORDER_METHOD_END + + //CUSTOM_RE_ORDER_METHOD_START + //CUSTOM_RE_ORDER_METHOD_END + + //GENERATED_RE_ORDER_METHOD_AFTER_START + //GENERATED_RE_ORDER_METHOD_AFTER_END + + } + + /** + * buildSolution() + * - Traverses node pointers from n (goal node) to n0 (start node) and stores the path in a solution list. + * @param node + * @param solution=[] + */ + buildSolution( + node, + solution=[] + ) { + + //GENERATED_BUILD_SOLUTION_METHOD_START + //GENERATED_BUILD_SOLUTION_METHOD_END + + //CUSTOM_BUILD_SOLUTION_METHOD_START + solution.push(node); + + if (node.pointer) { + this.buildSolution(node.pointer, solution); + } else { + return solution; + } + //CUSTOM_BUILD_SOLUTION_METHOD_END + + //GENERATED_BUILD_SOLUTION_METHOD_AFTER_START + //GENERATED_BUILD_SOLUTION_METHOD_AFTER_END + + } + + /** + * isGoal() + * - No comment + * @param callback + */ + isGoal(callback) { + + //GENERATED_IS_GOAL_METHOD_START + //GENERATED_IS_GOAL_METHOD_END + + //CUSTOM_IS_GOAL_METHOD_START + return callback(); + //CUSTOM_IS_GOAL_METHOD_END + + //GENERATED_IS_GOAL_METHOD_AFTER_START + //GENERATED_IS_GOAL_METHOD_AFTER_END + + } + //GENERATED_METHODS_END + + //GENERATED_TEMPLATE_STATIC_METHODS_START + //GENERATED_TEMPLATE_STATIC_METHODS_END + + //GENERATED_STATIC_METHODS_START + //GENERATED_STATIC_METHODS_END + + //CUSTOM_IMPLEMENTATION_START + //CUSTOM_IMPLEMENTATION_END + +} + +//GENERATED_TEMPLATE_STATIC_OPTIONS_INIT_START +//GENERATED_TEMPLATE_STATIC_OPTIONS_INIT_END + +//GENERATED_STATIC_OPTIONS_INIT_START +//GENERATED_STATIC_OPTIONS_INIT_END + +//GENERATED_OUT_OF_CLASS_IMPLEMENTATION_START +//GENERATED_OUT_OF_CLASS_IMPLEMENTATION_END + +//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START +//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END + +module.exports = Graph; diff --git a/src/r3/r3-node.js b/src/r3/r3-node.js new file mode 100644 index 0000000..e4de70c --- /dev/null +++ b/src/r3/r3-node.js @@ -0,0 +1,124 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + +/** + + GENERATED_INHERITED_START + + GENERATED_INHERITED_END + + TEMPLATE_OPTIONS_START + TEMPLATE_OPTIONS_END + + CUSTOM_OPTIONS_START + object=null + pointer=null + type='start-node' + successors=[] + CUSTOM_OPTIONS_END + + TEMPLATE_STATIC_OPTIONS_START + TEMPLATE_STATIC_OPTIONS_END + + CUSTOM_STATIC_OPTIONS_START + CUSTOM_STATIC_OPTIONS_END + + TEMPLATE_METHODS_START + TEMPLATE_METHODS_END + + CUSTOM_METHODS_START + CUSTOM_METHODS_END + + TEMPLATE_STATIC_METHODS_START + TEMPLATE_STATIC_METHODS_END + + CUSTOM_STATIC_METHODS_START + CUSTOM_STATIC_METHODS_END + + **/ + +class Node { + + //GENERATED_CONSTRUCTOR_START + constructor(options) { + + if (typeof options === 'undefined') { + options = {}; + } + + //GENERATED_TEMPLATE_OPTIONS_INIT_START + //GENERATED_TEMPLATE_OPTIONS_INIT_END + + //GENERATED_OPTIONS_INIT_START + /** + * object - No comment + */ + if (typeof options.object === 'undefined') { + options.object = null; + } + /** + * pointer - No comment + */ + if (typeof options.pointer === 'undefined') { + options.pointer = null; + } + /** + * type - No comment + */ + if (typeof options.type === 'undefined') { + options.type = 'start-node'; + } + /** + * successors - No comment + */ + if (typeof options.successors === 'undefined') { + options.successors = []; + } + //GENERATED_OPTIONS_INIT_END + + //CUSTOM_OPTIONS_INIT_START + //CUSTOM_OPTIONS_INIT_END + + Object.assign(this, options); + + //CUSTOM_BEFORE_INIT_START + //CUSTOM_BEFORE_INIT_END + + //CUSTOM_AFTER_INIT_START + //CUSTOM_AFTER_INIT_END + } + //GENERATED_CONSTRUCTOR_END + + //GENERATED_TEMPLATE_METHODS_START + //GENERATED_TEMPLATE_METHODS_END + + //GENERATED_METHODS_START + //GENERATED_METHODS_END + + //GENERATED_TEMPLATE_STATIC_METHODS_START + //GENERATED_TEMPLATE_STATIC_METHODS_END + + //GENERATED_STATIC_METHODS_START + //GENERATED_STATIC_METHODS_END + + //CUSTOM_IMPLEMENTATION_START + //CUSTOM_IMPLEMENTATION_END + +} + +//GENERATED_TEMPLATE_STATIC_OPTIONS_INIT_START +//GENERATED_TEMPLATE_STATIC_OPTIONS_INIT_END + +//GENERATED_STATIC_OPTIONS_INIT_START +//GENERATED_STATIC_OPTIONS_INIT_END + +//GENERATED_OUT_OF_CLASS_IMPLEMENTATION_START +//GENERATED_OUT_OF_CLASS_IMPLEMENTATION_END + +//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START +//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END + +module.exports = Node; diff --git a/src/r3/r3-object/r3-object.js b/src/r3/r3-object/r3-object.js index 1bbdcb5..1a80c87 100644 --- a/src/r3/r3-object/r3-object.js +++ b/src/r3/r3-object/r3-object.js @@ -38,6 +38,8 @@ const Utils = require('.././r3-utils'); TEMPLATE_METHODS_START initialize() - Initializes this Object if all of its required Objects are initialized + isReady() - Checks whether or not at least one set of requirements pass the ready state (i.e. required objects are assigned and ready) + requirementValueCheck(property, value) - Checks whether or not the property / value pair meets the requirements of setting this ready to true. It handles values of type Object and Array properly. TEMPLATE_METHODS_END CUSTOM_METHODS_START @@ -76,8 +78,8 @@ class R3Object extends Event { //GENERATED_TEMPLATE_OPTIONS_INIT_START /** - * id - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client and - * server side) + * id - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client + * and server side) */ if (typeof options.id === 'undefined') { options.id = Utils.RandomId(15); @@ -89,17 +91,18 @@ class R3Object extends Event { options.name = this.constructor.name + '(' + options.id + ')'; } /** - * ready - Normally all objects are 'ready' to have their instances created, unless it has some required - * Object which is not present at time of construction and will be assigned later. All objects - * have multiple sets of 'required' objects which affect its 'ready' state. + * ready - Normally all objects are 'ready' to have their instances created, unless it has some + * required Object which is not present at time of construction and will be assigned later. + * All objects have multiple sets of 'required' objects which affect its 'ready' state. */ if (typeof options.ready === 'undefined') { options.ready = []; } /** - * dirty - When dirty is true, it means that this object is in transition from having a child Object to - * not having this child Object, and will probably end up in an uninitialized state. During the - * next few clock cycles this child Object will have its parent reference to this Object removed. + * dirty - When dirty is true, it means that this object is in transition from having a child Object + * to not having this child Object, and will probably end up in an uninitialized state. + * During the next few clock cycles this child Object will have its parent reference to this + * Object removed. */ if (typeof options.dirty === 'undefined') { options.dirty = false; @@ -129,8 +132,8 @@ class R3Object extends Event { options.children = []; } /** - * required - All Objects could have some required Objects which need to initialize before this Object can - * initialize + * required - All Objects could have some required Objects which need to initialize before this Object + * can initialize */ if (typeof options.required === 'undefined') { options.required = []; @@ -184,6 +187,151 @@ class R3Object extends Event { } //GENERATED_INITIALIZE_METHOD_AFTER_END + } + + /** + * isReady() + * - Checks whether or not at least one set of requirements pass the ready state (i.e. required objects are + * assigned and ready) + */ + isReady() { + + //GENERATED_IS_READY_METHOD_START + //GENERATED_IS_READY_METHOD_END + + //CUSTOM_IS_READY_METHOD_START + if (this.required.length === 0) { + return true; + } + + for (let r = 0; r < this.required.length; r++) { + + /** + * We assume it is ready and will fail the ready test if a requirementValueCheck() fails + */ + let ready = true; + + let requirements = this.required[r]; + + for (let property in requirements) { + if (requirements.hasOwnProperty(property)) { + if (!this.requirementValueCheck(requirements[property], this[property])) { + ready = false; + } + } + } + + /** + * The ready state could have changed or not - regardless it should cascade this information in case + * new instances need to be created (ex. an image is added to an array and needs its instance created). + */ + + let readyStateChange = false; + + if (this.ready[r] !== ready) { + readyStateChange = true; + } + + this.ready[r] = ready; + + if (readyStateChange) { + if (this.ready[r]) { + this.emit( + Event.ON_READY_STATE_CHANGE, + { + r3Object: this, + readyState: R3Object.READY_STATE_TRUE, + readyStateIndex: r + } + ); + } else { + this.emit( + Event.ON_READY_STATE_CHANGE, + { + r3Object: this, + readyState: R3Object.READY_STATE_FALSE, + readyStateIndex: r + } + ); + } + } + } + + /** + * If at least one requirements set pass - return true. + */ + for (let r = 0; r < this.required.length; r++) { + if (this.ready[r]) { + return true; + } + } + + return false; + + //CUSTOM_IS_READY_METHOD_END + + //GENERATED_IS_READY_METHOD_AFTER_START + //GENERATED_IS_READY_METHOD_AFTER_END + + } + + /** + * requirementValueCheck() + * - Checks whether or not the property / value pair meets the requirements of setting this ready to true. It + * handles values of type Object and Array properly. + * @param property + * @param value + */ + requirementValueCheck( + property, + value + ) { + + //GENERATED_REQUIREMENT_VALUE_CHECK_METHOD_START + //GENERATED_REQUIREMENT_VALUE_CHECK_METHOD_END + + //CUSTOM_REQUIREMENT_VALUE_CHECK_METHOD_START + + /** + * The property change is one of the required properties of this Object, so it affects the overall + * 'readiness' of this object. + */ + if (property instanceof Array) { + + if (!(value instanceof Array)) { + return false; + } + + if (value.length === 0) { + return false; + } + + for (let v = 0; v < value.length; v++) { + if (!(value[v] instanceof property[0])) { + return false; + } + + if (!(value[v].isReady())) { + return false; + } + } + + return true; + + } else { + + if (!(value instanceof property)) { + return false; + } + + return value.isReady(); + } + + //CUSTOM_REQUIREMENT_VALUE_CHECK_METHOD_END + + //GENERATED_REQUIREMENT_VALUE_CHECK_METHOD_AFTER_START + //GENERATED_REQUIREMENT_VALUE_CHECK_METHOD_AFTER_END + } //GENERATED_TEMPLATE_METHODS_END @@ -229,6 +377,10 @@ R3Object.MAX_R3OBJECT = 0x11; //GENERATED_OUT_OF_CLASS_IMPLEMENTATION_END //CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START +R3Object.READY_STATE_FALSE = 0x1; +R3Object.READY_STATE_PENDING_FALSE = 0x2; +R3Object.READY_STATE_PENDING_TRUE = 0x3; +R3Object.READY_STATE_TRUE = 0x4; //CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END module.exports = R3Object; diff --git a/src/r3/r3-runtime/index.js b/src/r3/r3-runtime/index.js index cdb8854..d9364bd 100644 --- a/src/r3/r3-runtime/index.js +++ b/src/r3/r3-runtime/index.js @@ -4,6 +4,7 @@ const RuntimeCoder = require('./r3-runtime-coder.js'); const RuntimeCodeMirror = require('./r3-runtime-code-mirror.js'); const RuntimeDOM = require('./r3-runtime-d-o-m.js'); const RuntimeDocument = require('./r3-runtime-document.js'); +const RuntimeJsDOM = require('./r3-runtime-js-d-o-m.js'); const RuntimeGUI = require('./r3-runtime-g-u-i.js'); const RuntimeControlKit = require('./r3-runtime-control-kit.js'); const RuntimeGraphics = require('./r3-runtime-graphics.js'); @@ -23,6 +24,7 @@ Runtime.Coder = RuntimeCoder; Runtime.Coder.CodeMirror = RuntimeCodeMirror; Runtime.DOM = RuntimeDOM; Runtime.DOM.Document = RuntimeDocument; +Runtime.DOM.JsDOM = RuntimeJsDOM; Runtime.GUI = RuntimeGUI; Runtime.GUI.ControlKit = RuntimeControlKit; Runtime.Graphics = RuntimeGraphics; diff --git a/src/r3/r3-runtime/r3-runtime-bullet.js b/src/r3/r3-runtime/r3-runtime-bullet.js index bceb2fa..1a9a6f7 100644 --- a/src/r3/r3-runtime/r3-runtime-bullet.js +++ b/src/r3/r3-runtime/r3-runtime-bullet.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimePhysics = require('./r3-runtime-physics.js'); diff --git a/src/r3/r3-runtime/r3-runtime-code-mirror.js b/src/r3/r3-runtime/r3-runtime-code-mirror.js index ec0c621..9695c7f 100644 --- a/src/r3/r3-runtime/r3-runtime-code-mirror.js +++ b/src/r3/r3-runtime/r3-runtime-code-mirror.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeCoder = require('./r3-runtime-coder.js'); diff --git a/src/r3/r3-runtime/r3-runtime-control-kit.js b/src/r3/r3-runtime/r3-runtime-control-kit.js index fe4ce10..62f0b46 100644 --- a/src/r3/r3-runtime/r3-runtime-control-kit.js +++ b/src/r3/r3-runtime/r3-runtime-control-kit.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeGUI = require('./r3-runtime-g-u-i.js'); diff --git a/src/r3/r3-runtime/r3-runtime-document.js b/src/r3/r3-runtime/r3-runtime-document.js index 8936303..7e39c41 100644 --- a/src/r3/r3-runtime/r3-runtime-document.js +++ b/src/r3/r3-runtime/r3-runtime-document.js @@ -1,3 +1,10 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +const ComponentCanvas = require('../r3-component/r3-component-canvas'); +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeDOM = require('./r3-runtime-d-o-m.js'); @@ -70,7 +77,7 @@ class RuntimeDocument extends RuntimeDOM { //GENERATED_BUILD_INSTANCE_METHOD_END //CUSTOM_BUILD_INSTANCE_METHOD_START - if (component instanceof R3.Component.DOM.Canvas) { + if (component instanceof ComponentCanvas) { let canvas = document.createElement('canvas'); canvas.setAttribute('width', component.width); canvas.setAttribute('height', component.height); diff --git a/src/r3/r3-runtime/r3-runtime-js-d-o-m.js b/src/r3/r3-runtime/r3-runtime-js-d-o-m.js new file mode 100644 index 0000000..7c4a882 --- /dev/null +++ b/src/r3/r3-runtime/r3-runtime-js-d-o-m.js @@ -0,0 +1,130 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +const jsdom = require('jsdom'); +const {JSDOM} = jsdom; +const ComponentCanvas = require('../r3-component/r3-component-canvas'); +//CUSTOM_IMPORTS_END + +const Event = require('.././r3-event'); +const Utils = require('.././r3-utils'); +const RuntimeDOM = require('./r3-runtime-d-o-m.js'); + +/** + + GENERATED_INHERITED_START + + GENERATED_INHERITED_END + + TEMPLATE_OPTIONS_START + TEMPLATE_OPTIONS_END + + CUSTOM_OPTIONS_START + dom=new JSDOM(`

R3 NodeJS DOM

`); + CUSTOM_OPTIONS_END + + TEMPLATE_STATIC_OPTIONS_START + TEMPLATE_STATIC_OPTIONS_END + + CUSTOM_STATIC_OPTIONS_START + CUSTOM_STATIC_OPTIONS_END + + TEMPLATE_METHODS_START + buildInstance(component) - Creates a runtime instance object based on the R3.Component representing it. + TEMPLATE_METHODS_END + + CUSTOM_METHODS_START + CUSTOM_METHODS_END + + TEMPLATE_STATIC_METHODS_START + TEMPLATE_STATIC_METHODS_END + + CUSTOM_STATIC_METHODS_START + CUSTOM_STATIC_METHODS_END + + **/ + +class RuntimeJsDOM extends RuntimeDOM { + + //GENERATED_CONSTRUCTOR_START + constructor(options) { + + if (typeof options === 'undefined') { + options = {}; + } + + super(options); + + //GENERATED_TEMPLATE_OPTIONS_INIT_START + //GENERATED_TEMPLATE_OPTIONS_INIT_END + + //GENERATED_OPTIONS_INIT_START + /** + * dom - No comment + */ + if (typeof options.dom === 'undefined') { + options.dom = new JSDOM(`

R3 NodeJS DOM

`);; + } + //GENERATED_OPTIONS_INIT_END + + Object.assign(this, options); + + } + //GENERATED_CONSTRUCTOR_END + + //GENERATED_TEMPLATE_METHODS_START + + /** + * buildInstance() + * - Creates a runtime instance object based on the R3.Component representing it. + * @param component + */ + buildInstance(component) { + + //GENERATED_BUILD_INSTANCE_METHOD_START + //GENERATED_BUILD_INSTANCE_METHOD_END + + //CUSTOM_BUILD_INSTANCE_METHOD_START + if (component instanceof ComponentCanvas) { + let canvas = this.dom.window.document.createElement('canvas'); + canvas.setAttribute('width', component.width); + canvas.setAttribute('height', component.height); + canvas.setAttribute('style', component.style); + return canvas; + } + //CUSTOM_BUILD_INSTANCE_METHOD_END + + //GENERATED_BUILD_INSTANCE_METHOD_AFTER_START + //GENERATED_BUILD_INSTANCE_METHOD_AFTER_END + + } + //GENERATED_TEMPLATE_METHODS_END + + //GENERATED_METHODS_START + //GENERATED_METHODS_END + + //GENERATED_TEMPLATE_STATIC_METHODS_START + //GENERATED_TEMPLATE_STATIC_METHODS_END + + //GENERATED_STATIC_METHODS_START + //GENERATED_STATIC_METHODS_END + + //CUSTOM_IMPLEMENTATION_START + //CUSTOM_IMPLEMENTATION_END + +} + +//GENERATED_TEMPLATE_STATIC_OPTIONS_INIT_START +//GENERATED_TEMPLATE_STATIC_OPTIONS_INIT_END + +//GENERATED_STATIC_OPTIONS_INIT_START +//GENERATED_STATIC_OPTIONS_INIT_END + +//GENERATED_OUT_OF_CLASS_IMPLEMENTATION_START +//GENERATED_OUT_OF_CLASS_IMPLEMENTATION_END + +//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START +//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END + +module.exports = RuntimeJsDOM; diff --git a/src/r3/r3-runtime/r3-runtime-node-j-s-image.js b/src/r3/r3-runtime/r3-runtime-node-j-s-image.js index 43771d1..93cdae7 100644 --- a/src/r3/r3-runtime/r3-runtime-node-j-s-image.js +++ b/src/r3/r3-runtime/r3-runtime-node-j-s-image.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeImage = require('./r3-runtime-image.js'); diff --git a/src/r3/r3-runtime/r3-runtime-stats.js b/src/r3/r3-runtime/r3-runtime-stats.js index cb57ce3..3aad1e4 100644 --- a/src/r3/r3-runtime/r3-runtime-stats.js +++ b/src/r3/r3-runtime/r3-runtime-stats.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeStatistics = require('./r3-runtime-statistics.js'); diff --git a/src/r3/r3-runtime/r3-runtime-three.js b/src/r3/r3-runtime/r3-runtime-three.js index 05f2154..ca2a6a4 100644 --- a/src/r3/r3-runtime/r3-runtime-three.js +++ b/src/r3/r3-runtime/r3-runtime-three.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeGraphics = require('./r3-runtime-graphics.js'); diff --git a/src/r3/r3-runtime/r3-runtime-web-image.js b/src/r3/r3-runtime/r3-runtime-web-image.js index 131e3ee..14c180e 100644 --- a/src/r3/r3-runtime/r3-runtime-web-image.js +++ b/src/r3/r3-runtime/r3-runtime-web-image.js @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('.././r3-event'); const Utils = require('.././r3-utils'); const RuntimeImage = require('./r3-runtime-image.js'); diff --git a/src/r3/r3-runtime/r3-runtime.js b/src/r3/r3-runtime/r3-runtime.js index 80c735c..823a9ad 100644 --- a/src/r3/r3-runtime/r3-runtime.js +++ b/src/r3/r3-runtime/r3-runtime.js @@ -98,12 +98,13 @@ Runtime.BASE_SOCKET = 0x6; Runtime.BASE_STATISTICS = 0x7; Runtime.CODE_MIRROR = 0x8; Runtime.DOCUMENT = 0x9; -Runtime.CONTROL_KIT = 0xa; -Runtime.THREE = 0xb; -Runtime.NODE_JS_IMAGE = 0xc; -Runtime.WEB_IMAGE = 0xd; -Runtime.BULLET = 0xe; -Runtime.STATS = 0xf; +Runtime.JS_DOM = 0xa; +Runtime.CONTROL_KIT = 0xb; +Runtime.THREE = 0xc; +Runtime.NODE_JS_IMAGE = 0xd; +Runtime.WEB_IMAGE = 0xe; +Runtime.BULLET = 0xf; +Runtime.STATS = 0x10; //GENERATED_OUT_OF_CLASS_IMPLEMENTATION_END //CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START diff --git a/src/r3/r3-system/r3-system-d-o-m.js b/src/r3/r3-system/r3-system-d-o-m.js index 6b2da14..4e3454b 100644 --- a/src/r3/r3-system/r3-system-d-o-m.js +++ b/src/r3/r3-system/r3-system-d-o-m.js @@ -182,8 +182,8 @@ class SystemDOM extends System { SystemDOM.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemDOM.Subscriptions = {}; diff --git a/src/r3/r3-system/r3-system-input.js b/src/r3/r3-system/r3-system-input.js index b3a1139..27182e5 100644 --- a/src/r3/r3-system/r3-system-input.js +++ b/src/r3/r3-system/r3-system-input.js @@ -433,8 +433,8 @@ class SystemInput extends System { SystemInput.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemInput.Subscriptions = {}; diff --git a/src/r3/r3-system/r3-system-linking.js b/src/r3/r3-system/r3-system-linking.js index d6c8ae6..182dd40 100644 --- a/src/r3/r3-system/r3-system-linking.js +++ b/src/r3/r3-system/r3-system-linking.js @@ -5,6 +5,9 @@ const R3Object = require('../r3-object/r3-object.js'); const Utils = require('../r3-utils.js'); const Entity = require('../r3-entity/r3-entity.js'); +const Component = require('../r3-component/r3-component.js'); +const Graph = require('../r3-graph.js'); +const Node = require('../r3-node.js'); //CUSTOM_IMPORTS_END const Event = require('.././r3-event'); @@ -42,6 +45,8 @@ const System = require('./r3-system.js'); Event.CREATE_INSTANCE_BEFORE - @returns boolean delayInstance which indicates whether or not instance creation is delayed (handled) by another system. (i.e. where instance creation order is of importance) Event.OBJECT_PROPERTY_UPDATE Event.OBJECT_PROPERTY_UPDATED + Event.ON_READY_STATE_CHANGE + Event.FINAL_INITIALIZE CUSTOM_STATIC_EVENT_LISTENERS_END TEMPLATE_METHODS_START @@ -57,11 +62,10 @@ const System = require('./r3-system.js'); CUSTOM_STATIC_METHODS_START SanityChecks(r3Object, property, value) - When an object gets some value assigned to a property, we need to check if this property is a required property, and if so, the value assigned to this property needs to conform to the type restrictions enforced by the requirements objects. - SetParentChildRelationships(r3Object, property, value) - When an object gets some value assigned to a property, and it is a required property, we need to ensure that the proper parent / child relationships are maintained - DetermineFutureReadyState(r3Object, property, value) - When an object is assigned some value to one of its required properties, we should determine the future 'readiness' state of this R3 Object. If an object will fall out of readiness, we need to notify all relevant systems of the eventual demise of this object, so that they have the opportunity to cleanly stop using running instances of this object. - DetermineActualReadyState(r3Object, property, value) - When an object is assigned some value to one of its required properties, we should determine the current 'readiness' state of this R3 Object after its property has assumed the value. If the ready state of an object changed - we need to start / stop this Object or Entity, create / delete instances of the Component - RequirementsValueCheck(requirementProperty, value) - Does a quick check of the value against the requirement - ActivateInstances() + SetParentChildRelationships(r3Object, property, value) - When an object gets some value assigned to a property, and it is a required property, we need to ensure that the proper parent and child relationships are maintained + DetermineFutureReadyState(r3Object, property, value) - When an object is assigned some value to one of its required properties, we should determine the future 'readiness' state of this R3 Object. Only if its ready state becomes false, we need to cascade this information to all parents forcing them to emit a Only if its ready state becomes false, we force all parents to emit a READY_STATE_PENDING_FALSE event. + CascadeFutureReadyState(r3Object, readyState) - We start at the current node - emit READY_STATE_PENDING_FALSE event, afterwards calling asking all parents to emit a READY_STATE_PENDING_FALSE event. This allows the SystemLinking to stop Entities before the cleanup occurs. + CascadeActualReadyState(r3Object) - We start at the current node, determine its current ready state (it triggers the appropriate events), afterwards we work from the first parent upwards, determining it's ready state, taking appropriate action and cascading upwards. CUSTOM_STATIC_METHODS_END **/ @@ -146,6 +150,16 @@ class SystemLinking extends System { SystemLinking.OnObjectPropertyUpdated ); + SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'] = Event.Subscribe( + Event.ON_READY_STATE_CHANGE, + SystemLinking.OnOnReadyStateChange + ); + + SystemLinking.Subscriptions['FINAL_INITIALIZE'] = Event.Subscribe( + Event.FINAL_INITIALIZE, + SystemLinking.OnFinalInitialize + ); + //GENERATED_STATIC_EVENT_LISTENERS_START_END //CUSTOM_BEFORE_STATIC_SYSTEM_START_START @@ -193,6 +207,12 @@ class SystemLinking extends System { SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED'].remove(); delete SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED']; + SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'].remove(); + delete SystemLinking.Subscriptions['ON_READY_STATE_CHANGE']; + + SystemLinking.Subscriptions['FINAL_INITIALIZE'].remove(); + delete SystemLinking.Subscriptions['FINAL_INITIALIZE']; + //GENERATED_STATIC_EVENT_LISTENERS_STOP_END //CUSTOM_BEFORE_STATIC_SYSTEM_STOP_START @@ -335,7 +355,7 @@ class SystemLinking extends System { /** * SetParentChildRelationships() * - When an object gets some value assigned to a property, and it is a required property, we need to ensure that - * the proper parent / child relationships are maintained + * the proper parent and child relationships are maintained * @param r3Object * @param property * @param value @@ -421,9 +441,9 @@ class SystemLinking extends System { /** * DetermineFutureReadyState() * - When an object is assigned some value to one of its required properties, we should determine the future - * 'readiness' state of this R3 Object. If an object will fall out of readiness, we need to notify all relevant - * systems of the eventual demise of this object, so that they have the opportunity to cleanly stop using running - * instances of this object. + * 'readiness' state of this R3 Object. Only if its ready state becomes false, we need to cascade this + * information to all parents forcing them to emit a Only if its ready state becomes false, we force all parents + * to emit a READY_STATE_PENDING_FALSE event. * @param r3Object * @param property * @param value @@ -444,65 +464,25 @@ class SystemLinking extends System { if (r3Object.ready[r]) { + /** + * This object is currently ready - we need to check if this object will fall out of a ready state. + * We only need to compare the current property. + */ + let ready = true; - /** - * This object is currently ready - we need to check if this object will fall out of a ready state - */ let requirements = r3Object.required[r]; if (requirements.hasOwnProperty(property)) { - ready = SystemLinking.RequirementsValueCheck(requirements[property], value); + ready = r3Object.requirementValueCheck(requirements[property], value); } if (!ready) { /** * This object will fall out of readiness state - notify all systems */ - Event.Emit( - Event.FUTURE_READY_STATE_FALSE, - { - r3Object, - property, - value, - requiredIndex : r - } - ); - } - - } else { - - let ready = true; - - /** - * This object is current *NOT* ready - we need to check if this object will fall into a ready state. - */ - let requirements = r3Object.required[r]; - - for (let requirementProperty in requirements) { - if (requirements.hasOwnProperty(requirementProperty)) { - - if (requirementProperty === property) { - /** - * Compare against the current value and not the r3Object[requirementProperty] - */ - ready = SystemLinking.RequirementsValueCheck(requirements[requirementProperty], value); - } else { - ready = SystemLinking.RequirementsValueCheck(requirements[requirementProperty], r3Object[requirementProperty]); - } - } - } - - if (ready) { - Event.Emit( - Event.FUTURE_READY_STATE_TRUE, - { - r3Object, - property, - value, - requiredIndex: r - } - ); + console.log('Future ready state will transition from true to false'); + SystemLinking.CascadeFutureReadyState(r3Object, R3Object.READY_STATE_PENDING_FALSE); } } } @@ -512,121 +492,108 @@ class SystemLinking extends System { } /** - * DetermineActualReadyState() - * - When an object is assigned some value to one of its required properties, we should determine the current - * 'readiness' state of this R3 Object after its property has assumed the value. If the ready state of an object - * changed - we need to start / stop this Object or Entity, create / delete instances of the Component + * CascadeFutureReadyState() + * - We start at the current node - emit READY_STATE_PENDING_FALSE event, afterwards calling asking all parents to + * emit a READY_STATE_PENDING_FALSE event. This allows the SystemLinking to stop Entities before the cleanup + * occurs. * @param r3Object - * @param property - * @param value + * @param readyState */ - static DetermineActualReadyState( + static CascadeFutureReadyState( r3Object, - property, - value + readyState ) { - //GENERATED_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_START - //GENERATED_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_END + //GENERATED_STATIC_CASCADE_FUTURE_READY_STATE_METHOD_START + //GENERATED_STATIC_CASCADE_FUTURE_READY_STATE_METHOD_END - //CUSTOM_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_START - console.log('Determining actual ready state of ' + r3Object.name); + //CUSTOM_STATIC_CASCADE_FUTURE_READY_STATE_METHOD_START - for (let r = 0; r < r3Object.required.length; r++) { - - let ready = true; - - /** - * This object is currently ready - we need to check if this object will fall out of a ready state - */ - let requirements = r3Object.required[r]; - - for (let property in requirements) { - if (requirements.hasOwnProperty(property)) { - ready = SystemLinking.RequirementsValueCheck(requirements[property], r3Object[property]); - } + let node = new Node( + { + object : r3Object } + ); - r3Object.ready[r] = ready; - } + let graph = new Graph( + { + startNode : node, + relevant : ['parents'] + } + ) - //CUSTOM_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD_END - - } - - /** - * RequirementsValueCheck() - * - Does a quick check of the value against the requirement - * @param requirementProperty - * @param value - */ - static RequirementsValueCheck( - requirementProperty, - value - ) { - - //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START - //GENERATED_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END - - //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_START + let nodes = graph.closed; /** - * The property change is one of the required properties of this Object, so it affects the overall - * 'readiness' of this object. + * nodes contains a list of current node and parent Objects which are affected by the ready state of this object. */ - if (requirementProperty instanceof Array) { + for (let n = 0; n < nodes.length; n++) { + + let node = nodes[n]; /** - * + * The parent does not know directly why it falls out of ready state necessarily - because from its perspective + * it may have all its children requirements met - however a child of one of its children is going out of ready + * state. So - without adding too much complexity here, we just notify all parents (including the current node) + * that it's impending ready state will be false. We don't care about the readyStateIndex because of this. (for + * the sake of complexity) */ - if (!(value instanceof Array)) { - return false; - } - - if (value.length === 0) { - return false; - } - - for (let v = 0; v < value.length; v++) { - if (!(value[v] instanceof requirementProperty[0])) { - return false; + Event.Emit( + Event.ON_READY_STATE_CHANGE, + { + r3Object: node.object, + readyState: readyState } - } - - } else { - - if (!(value instanceof requirementProperty)) { - return false; - } - + ); } - return true; - - //CUSTOM_STATIC_REQUIREMENTS_VALUE_CHECK_METHOD_END + //CUSTOM_STATIC_CASCADE_FUTURE_READY_STATE_METHOD_END } /** - * ActivateInstances() - * - No comment + * CascadeActualReadyState() + * - We start at the current node, determine its current ready state (it triggers the appropriate events), + * afterwards we work from the first parent upwards, determining it's ready state, taking appropriate action and + * cascading upwards. + * @param r3Object */ - static ActivateInstances() { + static CascadeActualReadyState(r3Object) { - //GENERATED_STATIC_ACTIVATE_INSTANCES_METHOD_START - //GENERATED_STATIC_ACTIVATE_INSTANCES_METHOD_END + //GENERATED_STATIC_CASCADE_ACTUAL_READY_STATE_METHOD_START + //GENERATED_STATIC_CASCADE_ACTUAL_READY_STATE_METHOD_END - //CUSTOM_STATIC_ACTIVATE_INSTANCES_METHOD_START + //CUSTOM_STATIC_CASCADE_ACTUAL_READY_STATE_METHOD_START + console.log('Cascading actual ready state of ' + r3Object.name); - // if (this instanceof Component && this.initialized) { - // this.createInstance(); - // } - // - // if (this instanceof Entity && this.initialized && !this.started) { - // this.start(); - // } + let node = new Node( + { + object : r3Object + } + ); - //CUSTOM_STATIC_ACTIVATE_INSTANCES_METHOD_END + let graph = new Graph( + { + startNode : node, + relevant : ['parents'] + } + ) + + let nodes = graph.closed; + + /** + * nodes contains the current node as it's first object, followed by its parents + */ + for (let n = 0; n < nodes.length; n++) { + + let node = nodes[n]; + + /** + * A simple node.object.isReady() check will trigger the required READY_STATE_CHANGE events + */ + node.object.isReady(); + } + //CUSTOM_STATIC_CASCADE_ACTUAL_READY_STATE_METHOD_END } //GENERATED_STATIC_METHODS_END @@ -823,15 +790,112 @@ class SystemLinking extends System { //GENERATED_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD_END //CUSTOM_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD_START - let {r3Object, property, value} = object; + let {r3Object} = object; /** * Determine the actual ready state of the r3Object */ - SystemLinking.DetermineActualReadyState(r3Object, property, value); + SystemLinking.CascadeActualReadyState(r3Object); //CUSTOM_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD_END + } + + /** + * OnOnReadyStateChange() + * - Listens to events of type Event.ON_READY_STATE_CHANGE and executes this function. + * @param object (The event data passed as argument - typically an R3Object) + * @return + */ + static OnOnReadyStateChange(object) { + + //GENERATED_STATIC_ON_ON_READY_STATE_CHANGE_METHOD_START + //GENERATED_STATIC_ON_ON_READY_STATE_CHANGE_METHOD_END + + //CUSTOM_STATIC_ON_ON_READY_STATE_CHANGE_METHOD_START + + let {r3Object, readyState, readyStateIndex} = object; + + + if (readyState === R3Object.READY_STATE_TRUE) { + + console.log('Ready state changed to true for ' + r3Object.name + ' by passing requirements set ' + readyStateIndex); + + /** + * If it is a Component and it has no instance, call its createInstance(). + */ + if (r3Object instanceof Component && !r3Object.instance) { + r3Object.createInstance(); + } + + /** + * If it is an Entity and it is stopped, call the start() method. + */ + if (r3Object instanceof Entity && r3Object.started === false) { + r3Object.start(); + } + + } + + if (readyState === R3Object.READY_STATE_FALSE) { + console.log('Ready state false for : ' + r3Object.name); + + /** + * If it is a Component and it has an instance, dispose of it + */ + if (r3Object instanceof Component && r3Object.instance) { + r3Object.disposeInstance(); + } + } + + if (readyState === R3Object.READY_STATE_PENDING_FALSE) { + console.log('Ready state pending false for : ' + r3Object.name); + + /** + * If it is an Entity and is started, stop it. + */ + if (r3Object instanceof Entity && r3Object.started === true) { + r3Object.stop(); + } + } + + if (readyState === R3Object.READY_STATE_PENDING_TRUE) { + + /** + * We don't do anything at the moment - we just log this information. + */ + console.log('Ready state pending true for ' + r3Object.name + ' by passing requirements set ' + readyStateIndex); + } + + //CUSTOM_STATIC_ON_ON_READY_STATE_CHANGE_METHOD_END + + } + + /** + * OnFinalInitialize() + * - Listens to events of type Event.FINAL_INITIALIZE and executes this function. + * @param object (The event data passed as argument - typically an R3Object) + * @return + */ + static OnFinalInitialize(object) { + + //GENERATED_STATIC_ON_FINAL_INITIALIZE_METHOD_START + //GENERATED_STATIC_ON_FINAL_INITIALIZE_METHOD_END + + //CUSTOM_STATIC_ON_FINAL_INITIALIZE_METHOD_START + if (object instanceof Component) { + if (object.required.length === 0) { + object.createInstance(); + } + } + + if (object instanceof Entity) { + if (object.required.length === 0) { + object.start(); + } + } + //CUSTOM_STATIC_ON_FINAL_INITIALIZE_METHOD_END + } //GENERATED_STATIC_EVENT_LISTENER_METHODS_END @@ -846,8 +910,8 @@ class SystemLinking extends System { SystemLinking.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemLinking.Subscriptions = {}; @@ -855,7 +919,8 @@ SystemLinking.Subscriptions = {}; //GENERATED_STATIC_OPTIONS_INIT_START /** - * static BlacklistedComponents - A list of component constructors which should not be permitted to create instances immediately + * static BlacklistedComponents - A list of component constructors which should not be permitted to create instances + * immediately */ SystemLinking.BlacklistedComponents = []; diff --git a/src/r3/r3-system/r3-system-render.js b/src/r3/r3-system/r3-system-render.js index df3ed0a..3f68e01 100644 --- a/src/r3/r3-system/r3-system-render.js +++ b/src/r3/r3-system/r3-system-render.js @@ -2,6 +2,10 @@ //GENERATED_IMPORTS_END //CUSTOM_IMPORTS_START +const ComponentDOM = require('../r3-component/r3-component-d-o-m'); +const ComponentImage = require('../r3-component/r3-component-image'); +const RuntimeDocument = require('../r3-runtime/r3-runtime-document'); +const RuntimeWebImage = require('../r3-runtime/r3-runtime-web-image'); //CUSTOM_IMPORTS_END const Event = require('.././r3-event'); @@ -166,14 +170,14 @@ class SystemRender extends System { //GENERATED_STATIC_ON_INSTANCE_CREATED_METHOD_END //CUSTOM_STATIC_ON_INSTANCE_CREATED_METHOD_START - if (object instanceof R3.Component.DOM) { - if (object.runtime instanceof R3.Runtime.DOM.Document) { + if (object instanceof ComponentDOM) { + if (object.runtime instanceof RuntimeDocument) { document.body.appendChild(object.instance); } } - if (object instanceof R3.Component.Graphics.Image) { - if (object.runtime instanceof R3.Runtime.Image.WebImage) { + if (object instanceof ComponentImage) { + if (object.runtime instanceof RuntimeWebImage) { document.body.appendChild(object.instance); } } @@ -194,8 +198,8 @@ class SystemRender extends System { SystemRender.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemRender.Subscriptions = {}; diff --git a/src/r3/r3-system/r3-system-runtime.js b/src/r3/r3-system/r3-system-runtime.js index 16e3a4e..75e9db3 100644 --- a/src/r3/r3-system/r3-system-runtime.js +++ b/src/r3/r3-system/r3-system-runtime.js @@ -2,6 +2,13 @@ //GENERATED_IMPORTS_END //CUSTOM_IMPORTS_START +const ComponentDOM = require('../r3-component/r3-component-d-o-m.js'); +const ComponentInput = require('../r3-component/r3-component-input.js'); +const ComponentImage = require('../r3-component/r3-component-image.js'); +const RuntimeDocument = require('../r3-runtime/r3-runtime-document.js'); +const RuntimeWebImage = require('../r3-runtime/r3-runtime-web-image.js'); +const RuntimeJsDOM = require('../r3-runtime/r3-runtime-js-d-o-m.js'); +const Utils = require('.././r3-utils.js'); //CUSTOM_IMPORTS_END const Event = require('.././r3-event'); @@ -27,12 +34,15 @@ const System = require('./r3-system.js'); CUSTOM_STATIC_OPTIONS_START Projects=[] CurrentProject=null + ServerSide=(typeof process !== 'undefined') RuntimeCoder={} RuntimeDOM={} RuntimeGUI={} RuntimeGraphics={} RuntimePhysics={} RuntimeStatistics={} + RuntimeJsDOM=null + RuntimeDocument=null CUSTOM_STATIC_OPTIONS_END CUSTOM_EVENT_LISTENERS_START @@ -223,23 +233,41 @@ class SystemRuntime extends System { * the DOM. */ if ( - object instanceof R3.Component.DOM || - object instanceof R3.Component.Input + object instanceof ComponentDOM || + object instanceof ComponentImage || + object instanceof ComponentInput ) { if (SystemRuntime.CurrentProject === null) { - return new R3.Runtime.DOM.Document(); + + if (SystemRuntime.ServerSide) { + + if (!SystemRuntime.RuntimeJsDOM) { + SystemRuntime.RuntimeJsDOM = new RuntimeJsDOM(); + } + + return SystemRuntime.RuntimeJsDOM; + + } else { + + if (!SystemRuntime.RuntimeDocument) { + SystemRuntime.RuntimeDocument = new RuntimeDocument(); + } + + return SystemRuntime.RuntimeDocument; + + } } else { console.log('TODO: implement a project based DOM runtime'); } } - if (object instanceof R3.Component.Graphics.Image) { - if (SystemRuntime.CurrentProject === null) { - return new R3.Runtime.Image.WebImage(); - } else { - console.log('TODO: implement a project based Image runtime'); - } - } + // if (object instanceof ComponentImage) { + // if (SystemRuntime.CurrentProject === null) { + // return new RuntimeWebImage(); + // } else { + // console.log('TODO: implement a project based Image runtime'); + // } + // } //CUSTOM_STATIC_ON_GET_RUNTIME_METHOD_END } @@ -306,8 +334,8 @@ class SystemRuntime extends System { SystemRuntime.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemRuntime.Subscriptions = {}; @@ -324,6 +352,11 @@ SystemRuntime.Projects = []; */ SystemRuntime.CurrentProject = null; +/** + * static ServerSide - No comment + */ +SystemRuntime.ServerSide = (typeof process !== 'undefined'); + /** * static RuntimeCoder - No comment */ @@ -354,6 +387,16 @@ SystemRuntime.RuntimePhysics = {}; */ SystemRuntime.RuntimeStatistics = {}; +/** + * static RuntimeJsDOM - No comment + */ +SystemRuntime.RuntimeJsDOM = null; + +/** + * static RuntimeDocument - No comment + */ +SystemRuntime.RuntimeDocument = null; + //GENERATED_STATIC_OPTIONS_INIT_END //GENERATED_OUT_OF_CLASS_IMPLEMENTATION_START diff --git a/src/r3/r3-system/r3-system-socket.js b/src/r3/r3-system/r3-system-socket.js index 73ce59b..256adeb 100644 --- a/src/r3/r3-system/r3-system-socket.js +++ b/src/r3/r3-system/r3-system-socket.js @@ -158,8 +158,8 @@ class SystemSocket extends System { SystemSocket.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemSocket.Subscriptions = {}; diff --git a/src/r3/r3-system/r3-system-storage.js b/src/r3/r3-system/r3-system-storage.js index 735db3f..1bd0dc7 100644 --- a/src/r3/r3-system/r3-system-storage.js +++ b/src/r3/r3-system/r3-system-storage.js @@ -189,8 +189,8 @@ class SystemStorage extends System { SystemStorage.Started = false; /** - * static Subscriptions - An association object which hold the subscription handles for Events this system is listening - * to. The system can stop receiving events by calling remove() on a handle. + * static Subscriptions - An association object which hold the subscription handles for Events this system is + * listening to. The system can stop receiving events by calling remove() on a handle. */ SystemStorage.Subscriptions = {}; diff --git a/src/r3/r3.js b/src/r3/r3.js index b012f96..2490b54 100644 --- a/src/r3/r3.js +++ b/src/r3/r3.js @@ -90,12 +90,12 @@ class R3 { /** * static Version - Current R3 version */ -R3.Version = '3.0.261'; +R3.Version = '3.0.338'; /** * static CompileDate - Current compile date of R3 */ -R3.CompileDate = '2021 Oct 03 - 07:35:08 am'; +R3.CompileDate = '2021 Oct 10 - 15:24:05 pm'; //GENERATED_STATIC_OPTIONS_INIT_END diff --git a/src/templates/generated_required_components.template b/src/templates/generated_required_components.template index 7a59def..f60b071 100644 --- a/src/templates/generated_required_components.template +++ b/src/templates/generated_required_components.template @@ -4,15 +4,21 @@ if (typeof options.required[INDEX] === 'undefined') { options.required[INDEX] = {}; } + options.required[INDEX].KEY = VALUE; - this.KEYBackup = options.KEY; + + if (typeof this._cache === 'undefined') { + this._cache = {}; + } + + this._cache['KEY'] = options.KEY; Object.defineProperty( this, 'KEY', { configurable : true, enumerable : true, - set: function(x) { + set: (x) => { Event.Emit( Event.OBJECT_PROPERTY_UPDATE, { @@ -21,7 +27,7 @@ value : x } ); - this.KEYBackup = x; + this._cache['KEY'] = x; Event.Emit( Event.OBJECT_PROPERTY_UPDATED, { @@ -32,8 +38,8 @@ ); return x; }, - get : function() { - return this.KEYBackup; + get : () => { + return this._cache['KEY']; } } ) \ No newline at end of file diff --git a/src/templates/object_base.template b/src/templates/object_base.template index 5fe82d1..036b72b 100644 --- a/src/templates/object_base.template +++ b/src/templates/object_base.template @@ -36,6 +36,8 @@ const Utils = require('INCLUDE_PATH/r3-utils'); TEMPLATE_METHODS_START initialize() - Initializes this Object if all of its required Objects are initialized + isReady() - Checks whether or not at least one set of requirements pass the ready state (i.e. required objects are assigned and ready) + requirementValueCheck(property, value) - Checks whether or not the property / value pair meets the requirements of setting this ready to true. It handles values of type Object and Array properly. TEMPLATE_METHODS_END CUSTOM_METHODS_START diff --git a/src/templates/runtime_extends.template b/src/templates/runtime_extends.template index ec645c5..63b7f06 100644 --- a/src/templates/runtime_extends.template +++ b/src/templates/runtime_extends.template @@ -1,3 +1,9 @@ +//GENERATED_IMPORTS_START +//GENERATED_IMPORTS_END + +//CUSTOM_IMPORTS_START +//CUSTOM_IMPORTS_END + const Event = require('INCLUDE_PATH/r3-event'); const Utils = require('INCLUDE_PATH/r3-utils'); const EXTEND_CLASS = require('./EXTEND_CLASS_FILE_NAME'); diff --git a/src/templates/start.template b/src/templates/start.template index 8404af5..47a525f 100644 --- a/src/templates/start.template +++ b/src/templates/start.template @@ -7,7 +7,7 @@ this.started = true; - if (this instanceof R3.Entity) { + if (this instanceof Entity) { this.emit( Event.ENTITY_STARTED, this diff --git a/src/templates/token.db b/src/templates/token.db index d7cc18f..93c4ce1 100644 --- a/src/templates/token.db +++ b/src/templates/token.db @@ -3,6 +3,10 @@ GENERATED_ASYNC_METHOD GENERATED_ASYNC_METHOD_AFTER GENERATED_BUILD_INSTANCE_METHOD GENERATED_BUILD_INSTANCE_METHOD_AFTER +GENERATED_BUILD_METHOD +GENERATED_BUILD_METHOD_AFTER +GENERATED_BUILD_SOLUTION_METHOD +GENERATED_BUILD_SOLUTION_METHOD_AFTER GENERATED_CONSTRUCTOR GENERATED_CREATE_INSTANCE_METHOD GENERATED_CREATE_INSTANCE_METHOD_AFTER @@ -13,16 +17,24 @@ GENERATED_DISPOSE_METHOD GENERATED_DISPOSE_METHOD_AFTER GENERATED_EMIT_METHOD GENERATED_EMIT_METHOD_AFTER +GENERATED_ESTABLISH_POINTERS_METHOD +GENERATED_ESTABLISH_POINTERS_METHOD_AFTER GENERATED_EVENT_LISTENER_METHODS GENERATED_EVENT_LISTENERS_START GENERATED_EVENT_LISTENERS_STOP GENERATED_EVENTS +GENERATED_EXPAND_METHOD +GENERATED_EXPAND_METHOD_AFTER GENERATED_EXPORTS GENERATED_IMPORTS GENERATED_INDEX_BODY GENERATED_INHERITED GENERATED_INITIALIZE_METHOD GENERATED_INITIALIZE_METHOD_AFTER +GENERATED_IS_GOAL_METHOD +GENERATED_IS_GOAL_METHOD_AFTER +GENERATED_IS_READY_METHOD +GENERATED_IS_READY_METHOD_AFTER GENERATED_METHOD_NAME_UPPERCASE_METHOD GENERATED_METHOD_NAME_UPPERCASE_METHOD_AFTER GENERATED_METHODS @@ -36,15 +48,21 @@ GENERATED_ON_TOUCH_START_METHOD GENERATED_ON_TOUCH_START_METHOD_AFTER GENERATED_OPTIONS_INIT GENERATED_OUT_OF_CLASS_IMPLEMENTATION +GENERATED_PROCESS_METHOD +GENERATED_PROCESS_METHOD_AFTER +GENERATED_RE_ORDER_METHOD +GENERATED_RE_ORDER_METHOD_AFTER GENERATED_REQUIRED_COMPONENTS +GENERATED_REQUIREMENT_VALUE_CHECK_METHOD +GENERATED_REQUIREMENT_VALUE_CHECK_METHOD_AFTER GENERATED_SET_RUNTIME_METHOD GENERATED_SET_RUNTIME_METHOD_AFTER GENERATED_SOURCE GENERATED_START_METHOD GENERATED_START_METHOD_AFTER -GENERATED_STATIC_ACTIVATE_INSTANCES_METHOD GENERATED_STATIC_ASYNC_METHOD -GENERATED_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD +GENERATED_STATIC_CASCADE_ACTUAL_READY_STATE_METHOD +GENERATED_STATIC_CASCADE_FUTURE_READY_STATE_METHOD GENERATED_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD GENERATED_STATIC_EMIT_METHOD GENERATED_STATIC_EVENT_LISTENER_METHODS @@ -56,6 +74,7 @@ GENERATED_STATIC_ON_COMPONENT_INITIALIZED_METHOD GENERATED_STATIC_ON_CREATE_INSTANCE_BEFORE_METHOD GENERATED_STATIC_ON_DOM_COMPONENT_INITIALIZED_METHOD GENERATED_STATIC_ON_ENTITY_INITIALIZED_METHOD +GENERATED_STATIC_ON_FINAL_INITIALIZE_METHOD GENERATED_STATIC_ON_GET_API_URL_METHOD GENERATED_STATIC_ON_GET_RUNTIME_METHOD GENERATED_STATIC_ON_IMAGE_INSTANCE_CREATED_METHOD @@ -69,6 +88,7 @@ GENERATED_STATIC_ON_MOUSE_WHEEL_METHOD GENERATED_STATIC_ON_OBJECT_CREATED_METHOD GENERATED_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD GENERATED_STATIC_ON_OBJECT_PROPERTY_UPDATE_METHOD +GENERATED_STATIC_ON_ON_READY_STATE_CHANGE_METHOD GENERATED_STATIC_ON_PROJECT_INITIALIZED_METHOD GENERATED_STATIC_ON_RUNTIME_CREATED_METHOD GENERATED_STATIC_ON_SLIDER_ENTITY_INITIALIZED_METHOD @@ -107,17 +127,23 @@ CUSTOM_BEFORE_STATIC_SYSTEM_STOP CUSTOM_BEFORE_SYSTEM_START CUSTOM_BEFORE_SYSTEM_STOP CUSTOM_BUILD_INSTANCE_METHOD +CUSTOM_BUILD_METHOD +CUSTOM_BUILD_SOLUTION_METHOD CUSTOM_CREATE_INSTANCE_METHOD CUSTOM_DEFINES CUSTOM_DISPOSE_INSTANCE_METHOD CUSTOM_DISPOSE_METHOD CUSTOM_EMIT_METHOD +CUSTOM_ESTABLISH_POINTERS_METHOD CUSTOM_EVENT_LISTENERS CUSTOM_EXCLUDED_FROM_INSTANCE_OPTIONS +CUSTOM_EXPAND_METHOD CUSTOM_IMPLEMENTATION CUSTOM_IMPORTS CUSTOM_INITIALIZE_METHOD CUSTOM_INSTANCE_OPTIONS_MAPPING +CUSTOM_IS_GOAL_METHOD +CUSTOM_IS_READY_METHOD CUSTOM_METHOD_NAME_UPPERCASE_METHOD CUSTOM_METHODS CUSTOM_ON_BEFORE_RENDER_METHOD @@ -127,12 +153,15 @@ CUSTOM_ON_TOUCH_START_METHOD CUSTOM_OPTIONS CUSTOM_OPTIONS_INIT CUSTOM_OUT_OF_CLASS_IMPLEMENTATION +CUSTOM_PROCESS_METHOD +CUSTOM_RE_ORDER_METHOD CUSTOM_REQUIRED_COMPONENTS +CUSTOM_REQUIREMENT_VALUE_CHECK_METHOD CUSTOM_SET_RUNTIME_METHOD CUSTOM_START_METHOD -CUSTOM_STATIC_ACTIVATE_INSTANCES_METHOD CUSTOM_STATIC_ASYNC_METHOD -CUSTOM_STATIC_DETERMINE_ACTUAL_READY_STATE_METHOD +CUSTOM_STATIC_CASCADE_ACTUAL_READY_STATE_METHOD +CUSTOM_STATIC_CASCADE_FUTURE_READY_STATE_METHOD CUSTOM_STATIC_DETERMINE_FUTURE_READY_STATE_METHOD CUSTOM_STATIC_EMIT_METHOD CUSTOM_STATIC_EVENT_LISTENERS @@ -142,6 +171,7 @@ CUSTOM_STATIC_ON_COMPONENT_INITIALIZED_METHOD CUSTOM_STATIC_ON_CREATE_INSTANCE_BEFORE_METHOD CUSTOM_STATIC_ON_DOM_COMPONENT_INITIALIZED_METHOD CUSTOM_STATIC_ON_ENTITY_INITIALIZED_METHOD +CUSTOM_STATIC_ON_FINAL_INITIALIZE_METHOD CUSTOM_STATIC_ON_GET_API_URL_METHOD CUSTOM_STATIC_ON_GET_RUNTIME_METHOD CUSTOM_STATIC_ON_IMAGE_INSTANCE_CREATED_METHOD @@ -155,6 +185,7 @@ CUSTOM_STATIC_ON_MOUSE_WHEEL_METHOD CUSTOM_STATIC_ON_OBJECT_CREATED_METHOD CUSTOM_STATIC_ON_OBJECT_PROPERTY_UPDATED_METHOD CUSTOM_STATIC_ON_OBJECT_PROPERTY_UPDATE_METHOD +CUSTOM_STATIC_ON_ON_READY_STATE_CHANGE_METHOD CUSTOM_STATIC_ON_PROJECT_INITIALIZED_METHOD CUSTOM_STATIC_ON_RUNTIME_CREATED_METHOD CUSTOM_STATIC_ON_SLIDER_ENTITY_INITIALIZED_METHOD diff --git a/test/R3.test.js b/test/R3.test.js index 75b6316..a1a5b51 100644 --- a/test/R3.test.js +++ b/test/R3.test.js @@ -26,6 +26,7 @@ const RuntimeCoder = require('../src/r3/r3-runtime/./r3-runtime-coder.js'); const RuntimeCodeMirror = require('../src/r3/r3-runtime/./r3-runtime-code-mirror.js'); const RuntimeDOM = require('../src/r3/r3-runtime/./r3-runtime-d-o-m.js'); const RuntimeDocument = require('../src/r3/r3-runtime/./r3-runtime-document.js'); +const RuntimeJsDOM = require('../src/r3/r3-runtime/./r3-runtime-js-d-o-m.js'); const RuntimeGUI = require('../src/r3/r3-runtime/./r3-runtime-g-u-i.js'); const RuntimeControlKit = require('../src/r3/r3-runtime/./r3-runtime-control-kit.js'); const RuntimeGraphics = require('../src/r3/r3-runtime/./r3-runtime-graphics.js'); @@ -118,6 +119,7 @@ describe('R3 Tests', () => { const runtimeCodeMirror = new RuntimeCodeMirror(); const runtimeDOM = new RuntimeDOM(); const runtimeDocument = new RuntimeDocument(); + const runtimeJsDOM = new RuntimeJsDOM(); const runtimeGUI = new RuntimeGUI(); const runtimeControlKit = new RuntimeControlKit(); const runtimeGraphics = new RuntimeGraphics(); @@ -284,6 +286,8 @@ describe('R3 Tests', () => { 'Linking system detects future ready state correctly', () => { + const R3 = require('../src/r3/'); + let touch1 = new ComponentTouch( { name : 'touch1' @@ -298,6 +302,72 @@ describe('R3 Tests', () => { assert.isTrue(touch1.ready[0]); + let slider1 = new EntitySlider(); + + assert.isFalse(slider1.ready[0]); + + let images = []; + + slider1.images = images; + + assert.isFalse(slider1.ready[0]); + + let image1 = new ComponentImage(); + + slider1.images = [image1]; + + assert.isFalse(slider1.ready[0]); + + slider1.canvas = canvas; + + assert.isFalse(slider1.ready[0]); + + slider1.touch = touch1; + + assert.isTrue(slider1.ready[0]); + + touch1.domComponent = null; + + assert.isFalse(touch1.ready[0]); + assert.isFalse(slider1.ready[0]); + + } + ); + + + it( + 'Tests the Graph building process', + () => { + const R3 = require('../src/r3/'); + let canvas = new ComponentCanvas(); + let image1 = new ComponentImage(); + let image2 = new ComponentImage(); + let image3 = new ComponentImage(); + let image4 = new ComponentImage(); + + let touch = new ComponentTouch( + { + domComponent : canvas + } + ); + let slider = new EntitySlider( + { + canvas, + images : [image1, image2, image3, image4], + } + ) + slider.touch = touch; + + assert.isTrue(slider.ready[0]); + + touch.domComponent = null; + + assert.isFalse(slider.ready[0]); + + touch.domComponent = canvas; + + assert.isTrue(slider.ready[0]); + } ); diff --git a/version b/version index 31ee48a..0d6ca30 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.0.262 \ No newline at end of file +3.0.339 \ No newline at end of file