<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:#954F72;
        text-decoration:underline;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style></head><body lang=EN-US link=blue vlink="#954F72"><div class=WordSection1><p class=MsoNormal>Perhaps this translation will make it more palatable!  I can proxy to any field in the subtree of a node!  The only issue is that proxyAction properties must be unique, therefore, you need the full path (which is okay in a single object, and in a tree).  It’s essentially the identical code! Scenegraph == Node and path == field.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>John</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>'use strict';</p><p class=MsoNormal>/*</p><p class=MsoNormal>Copyright (c) 2017, John Carlson</p><p class=MsoNormal>All rights reserved.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Redistribution and use in source and binary forms, with or without</p><p class=MsoNormal>modification, are permitted provided that the following conditions are met:</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>* Redistributions of source code must retain the above copyright notice, this</p><p class=MsoNormal>  list of conditions and the following disclaimer.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>* Redistributions in binary form must reproduce the above copyright notice,</p><p class=MsoNormal>  this list of conditions and the following disclaimer in the documentation</p><p class=MsoNormal>  and/or other materials provided with the distribution.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>* Neither the name of content nor the names of its</p><p class=MsoNormal>  contributors may be used to endorse or promote products derived from</p><p class=MsoNormal>  this software without specific prior written permission.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</p><p class=MsoNormal>AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</p><p class=MsoNormal>IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</p><p class=MsoNormal>DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</p><p class=MsoNormal>FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</p><p class=MsoNormal>DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</p><p class=MsoNormal>SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</p><p class=MsoNormal>CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</p><p class=MsoNormal>OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</p><p class=MsoNormal>OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE</p><p class=MsoNormal>*/</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>test();</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * Override this to get rid of self-test code</p><p class=MsoNormal> * proxyAction should be paired with a node exclusively</p><p class=MsoNormal> */</p><p class=MsoNormal>function test() {</p><p class=MsoNormal>                let fromNode = [ {d: { f: 7 , e: [1, 2, 3]}}, { c : [4]}]</p><p class=MsoNormal>                let toNode = fromNode;</p><p class=MsoNormal>                info("Node originally "+stringify(fromNode));</p><p class=MsoNormal>                assert(fromNode, toNode);</p><p class=MsoNormal>                let proxyAction = {};</p><p class=MsoNormal>                let proxy = createProxy(proxyAction, fromNode);</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>                // Create actionable fields in the fromNode, that set</p><p class=MsoNormal>                // fields in the toNode</p><p class=MsoNormal>                //</p><p class=MsoNormal>                // fields are MFStrings which follow a path down the node, one</p><p class=MsoNormal>                // element at a time.  The final SFSTring is thei field to modify.</p><p class=MsoNormal>                //</p><p class=MsoNormal>                // This does not handle script nodes yet (both getting and setting</p><p class=MsoNormal>                // values, but could possibly be handled by modifying SetInternalField.</p><p class=MsoNormal>                //</p><p class=MsoNormal>                route(proxyAction,</p><p class=MsoNormal>                                fromNode, '"0" "d" "e" "0"',</p><p class=MsoNormal>                                toNode, '"1" "c"');</p><p class=MsoNormal>                route(proxyAction,</p><p class=MsoNormal>                                fromNode, '"0" "d"',</p><p class=MsoNormal>                                toNode, '"1"');</p><p class=MsoNormal>                route(proxyAction,</p><p class=MsoNormal>                                fromNode, '"0" "A"',</p><p class=MsoNormal>                                toNode, '"0" "B"');</p><p class=MsoNormal>                // no changes to node yet</p><p class=MsoNormal>                assert(fromNode, [{"d":{"f":7,"e":[1,2,3]}},{"c":[4]}]);</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>                setField(proxy, '"0" "d" "e" "0"', 5); </p><p class=MsoNormal>                assert(fromNode, [{"d":{"f":7,"e":[5,2,3]}},{"c":5}]);</p><p class=MsoNormal>                setField(proxy, '"0" "d" "e" "1"', 8); </p><p class=MsoNormal>                assert(fromNode, [{"d":{"f":7,"e":[5,8,3]}},{"c":5}]);</p><p class=MsoNormal>                setField(proxy, '"0" "d"', 6);</p><p class=MsoNormal>                assert(fromNode, [{"d":6},6]);</p><p class=MsoNormal>                setField(proxy, '"0" "d"', 9);</p><p class=MsoNormal>                assert(fromNode, [{"d":9},9]);</p><p class=MsoNormal>                // add field'</p><p class=MsoNormal>                setField(proxy, '"0" "A"',  10);</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":10,"A":10},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', [ "Test!" ]);</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":["Test!"],"A":["Test!"]},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "B"', null);</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":null,"A":["Test!"]},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "0" "0"', ["Cr"]);  // set a part of a string</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":null,"A":["Crest!"]},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "/": "/" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"/":"/"},"A":{"/":"/"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "/"', "\\");</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"/":"\\"},"A":{"/":"\\"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "\\": "\\" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"\\":"\\"},"A":{"\\":"\\"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "\\"', "]");</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"\\":"]"},"A":{"\\":"]"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "]" : "]" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"]":"]"},"A":{"]":"]"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "]"', "[");</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"]":"["},"A":{"]":"["}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "[" : "[" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"[":"["},"A":{"[":"["}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "["', "][");</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"[":"]["},"A":{"[":"]["}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "][" : "][" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"][":"]["},"A":{"][":"]["}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "]["', "][][" );</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"][":"][]["},"A":{"][":"][]["}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "][][" : "][][" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"][][":"][]["},"A":{"][][":"][]["}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "][]["',   "[][]");</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"][][":"[][]"},"A":{"][][":"[][]"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A"', { "[][]" : "[][]" }); // now A and B point to same</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"[][]":"[][]"},"A":{"[][]":"[][]"}},9]);</p><p class=MsoNormal>                setField(proxy, '"0" "A" "[][]"', "C");</p><p class=MsoNormal>                assert(fromNode, [{"d":9,"B":{"[][]":"C"},"A":{"[][]":"C"}},9]);</p><p class=MsoNormal>                assert(fromNode, toNode);</p><p class=MsoNormal>                info("Node finally "+stringify(fromNode));</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>function setField(proxy, fromField, value) {</p><p class=MsoNormal>                let selector = MFStringToProperty(fromField);</p><p class=MsoNormal>                raw("\n");</p><p class=MsoNormal>                info("Storing "+fromField+" = "+selector+" = "+stringify(value)+" in Proxy");</p><p class=MsoNormal>                proxy[selector] = value;</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * Override this if you don't want test warnings about node</p><p class=MsoNormal> */</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>function assert(modifiedNode, goldenNode) {</p><p class=MsoNormal>                var mod = stringify(modifiedNode);</p><p class=MsoNormal>                var testcase = stringify(goldenNode);</p><p class=MsoNormal>                if (mod !== testcase) {</p><p class=MsoNormal>                                fatal("Node "+mod)</p><p class=MsoNormal>                                fatal("        != "+testcase);</p><p class=MsoNormal>                } else {</p><p class=MsoNormal>                                debug("Node "+mod+" == "+testcase);</p><p class=MsoNormal>                                info("TEST PASSED");</p><p class=MsoNormal>                }</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * Pass in a JSON parseable object be stringified,</p><p class=MsoNormal> * or a regular JSON object.  Or a string to be parsed.</p><p class=MsoNormal> * selector returned the is the field into the proxy.</p><p class=MsoNormal> *</p><p class=MsoNormal> * This should normalize the string, but there may be issues</p><p class=MsoNormal> * with ordering objects.</p><p class=MsoNormal> */</p><p class=MsoNormal>function stringify(selectorField) {</p><p class=MsoNormal>                if (typeof selectorField === 'string') {</p><p class=MsoNormal>                                debug("selector output "+selectorField);</p><p class=MsoNormal>                                return selectorField;</p><p class=MsoNormal>                /*</p><p class=MsoNormal>                                let indexes = parse(selectorField);</p><p class=MsoNormal>                                let selector = JSON.stringify(indexes);</p><p class=MsoNormal>                                debug("selector output "+selector);</p><p class=MsoNormal>                                return selector;</p><p class=MsoNormal>                */</p><p class=MsoNormal>                } else {</p><p class=MsoNormal>                                let selector = JSON.stringify(selectorField);</p><p class=MsoNormal>                                debug("selector output "+selector);</p><p class=MsoNormal>                                return selector;</p><p class=MsoNormal>                }</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * breaks up selectorField into component pieces and returns them</p><p class=MsoNormal> */</p><p class=MsoNormal>function parse(selectorField) {</p><p class=MsoNormal>                debug("selector input "+selectorField);</p><p class=MsoNormal>                if (typeof selectorField === 'string') {</p><p class=MsoNormal>                                let indexes = JSON.parse(selectorField);</p><p class=MsoNormal>                                return indexes;</p><p class=MsoNormal>                } else {</p><p class=MsoNormal>                                return selectorField;</p><p class=MsoNormal>                }</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>function MFStringToProperty(string) {</p><p class=MsoNormal>                debug("MFString input "+string+" "+typeof string);</p><p class=MsoNormal>                string = string.replace(/" "/g, ',');</p><p class=MsoNormal>                string = string.substr(1, string.length-2);</p><p class=MsoNormal>                return string;</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/*</p><p class=MsoNormal>function JsonToMFString(json) {</p><p class=MsoNormal>                let str = stringify(json).split(/,/).join('" "')</p><p class=MsoNormal>                str = "'"+str.substr(1, str.length-2)+'"';</p><p class=MsoNormal>                return str;</p><p class=MsoNormal>}</p><p class=MsoNormal>*/</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>function PropertyToJson(string) {</p><p class=MsoNormal>                debug("property input "+string+" "+typeof string);</p><p class=MsoNormal>                return string.split(/,/);</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/** override this function if you want a feature other than a raw message</p><p class=MsoNormal> */</p><p class=MsoNormal>function raw(string) {</p><p class=MsoNormal>                console.log(string);</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/** override this function if you want a feature other than a fatal message</p><p class=MsoNormal> */</p><p class=MsoNormal>function fatal(string) {</p><p class=MsoNormal>                console.error("FATAL: "+string);</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/** override this function if you want a feature other than a warning message</p><p class=MsoNormal> */</p><p class=MsoNormal>function warning(string) {</p><p class=MsoNormal>                console.error("============ WARNING: "+string);</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/** override this function if you want a feature other than console.log or to</p><p class=MsoNormal> * disable this function</p><p class=MsoNormal> */</p><p class=MsoNormal>function debug(string) {</p><p class=MsoNormal>                // raw(string);</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/** override this function if you want a feature other than console.log or to</p><p class=MsoNormal> * disable this function</p><p class=MsoNormal> */</p><p class=MsoNormal>function info(string) {</p><p class=MsoNormal>                raw("****** "+string);</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * setInternalField() --  set a field in a node internally.  Use</p><p class=MsoNormal> * setField() and set up routes and the proxy object on the node so</p><p class=MsoNormal> * events flow.</p><p class=MsoNormal> * Override this if you want a different selector language.</p><p class=MsoNormal> * The node is the javascript object to set the field to value on.</p><p class=MsoNormal> * selectorField is a JSON array path of keys and indexes into the node.</p><p class=MsoNormal> *            You may use quotes to backslashes to escape things</p><p class=MsoNormal> * The value is set in the node at the selectorField location</p><p class=MsoNormal> *</p><p class=MsoNormal> * The client may want the select to impact several objects.  That is up</p><p class=MsoNormal> * to the implementer of setInternalField().  The selectorField affects the</p><p class=MsoNormal> * node.</p><p class=MsoNormal> * Right now we just have a simple JavaScript implementation.  Something like</p><p class=MsoNormal> * JSONField is realizable in this framework I think.</p><p class=MsoNormal> *</p><p class=MsoNormal> * You should not use this method to set values on the proxy.</p><p class=MsoNormal> *</p><p class=MsoNormal> * Calls:</p><p class=MsoNormal> *            stringify: to return a string for viewing.</p><p class=MsoNormal> *            parse: to return javascript object indexes as a selector.</p><p class=MsoNormal> */</p><p class=MsoNormal>function setInternalField(node, selectorField, value) {</p><p class=MsoNormal>                debug("Node before "+ stringify(node));</p><p class=MsoNormal>                let skipDescendants = 0; // number of descendents to skip</p><p class=MsoNormal>                let selectedValue = node;</p><p class=MsoNormal>                let higherValue = selectedValue;</p><p class=MsoNormal>                var selector  = PropertyToJson(selectorField);</p><p class=MsoNormal>                let depth = (selector.length - skipDescendants);</p><p class=MsoNormal>                debug("Trying to Set "+stringify(node)+stringify(selector)+" = "+</p><p class=MsoNormal>                                stringify(value));</p><p class=MsoNormal>                for (var index = 0; index < depth - 1; index++) {</p><p class=MsoNormal>                                debug("Index "+index+" is "+selector[index]);</p><p class=MsoNormal>                                higherValue = selectedValue;</p><p class=MsoNormal>                                debug("Previous downselected selectedValue === "+</p><p class=MsoNormal>                                                stringify(selectedValue));</p><p class=MsoNormal>                                debug("Index "+index+" is "+selector[index]);</p><p class=MsoNormal>                                debug("New Selected Value === "+selectedValue[selector[index]]);</p><p class=MsoNormal>                                selectedValue = selectedValue[selector[index]];</p><p class=MsoNormal>                                debug("Now downselected selectedValue === "+selectedValue);</p><p class=MsoNormal>                }</p><p class=MsoNormal>                if (typeof value === 'string') {</p><p class=MsoNormal>                                value = value.replace(/\\\\/g, '\u005c');</p><p class=MsoNormal>                }</p><p class=MsoNormal>                debug("Index "+index+" is "+selector[index]);</p><p class=MsoNormal>                /**</p><p class=MsoNormal>                 * This is the code that has to change to call functions in X3D Scripts</p><p class=MsoNormal>                 * fields.   For toField, I would check to make sure the LHS is a</p><p class=MsoNormal>                 * function, and pass a value to the function (along with a timestamp),</p><p class=MsoNormal>                 * for From Field, I would make sure value is a function, and call it</p><p class=MsoNormal>                 * with a timestamp.</p><p class=MsoNormal>                 */</p><p class=MsoNormal>                if (typeof selectedValue === 'string') {</p><p class=MsoNormal>                    var str = selectedValue.split('');</p><p class=MsoNormal>                                    info("Setting "+ stringify(higherValue) +</p><p class=MsoNormal>                                                "[" + selector[depth-2] + "] = "+</p><p class=MsoNormal>                                                stringify(value));</p><p class=MsoNormal>                                    str[selector[depth-1]] = value;</p><p class=MsoNormal>                                    higherValue[selector[depth-2]] = str.join('');</p><p class=MsoNormal>                                    // unless there's more than one</p><p class=MsoNormal>                } else {</p><p class=MsoNormal>                                info("Setting "+</p><p class=MsoNormal>                                                stringify(selectedValue) +</p><p class=MsoNormal>                                                "[" + selector[depth-1] + "] = "+ stringify(value));</p><p class=MsoNormal>                                selectedValue[selector[depth-1]] = value;</p><p class=MsoNormal>                                // unless there's more than one</p><p class=MsoNormal>                }</p><p class=MsoNormal>                raw("RESULT node "+stringify(node));</p><p class=MsoNormal>                return true;</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * This proxy works on individual values in a node, because a shadow</p><p class=MsoNormal> * node is keep with fromField kept as proxy objects.</p><p class=MsoNormal> *</p><p class=MsoNormal> * If a route hasn't been set up yet, then the toNode is not affected,</p><p class=MsoNormal> * unless it's a part of the fromSceneGraph.</p><p class=MsoNormal> */</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>function createProxy(proxyAction, fromNode) {</p><p class=MsoNormal>                var proxy = new Proxy(proxyAction, {</p><p class=MsoNormal>                                set : function(target, property, value, receiver) {</p><p class=MsoNormal>                                                debug("Value set is "+value);</p><p class=MsoNormal>                                                debug("property is "+ property);</p><p class=MsoNormal>                                                for (let action in proxyAction) {</p><p class=MsoNormal>                                                                debug(" "+action+" "+typeof proxyAction[property]);</p><p class=MsoNormal>                                                }</p><p class=MsoNormal>                                                if (typeof proxyAction[property] === 'function') {</p><p class=MsoNormal>                                                                // set the toNode, act on the route</p><p class=MsoNormal>                                                                proxyAction[property](property, value);</p><p class=MsoNormal>                                                } else {</p><p class=MsoNormal>                                                                warning("Failed to set value on toNode (no route)");</p><p class=MsoNormal>                                                }</p><p class=MsoNormal>                                                return setInternalField(fromNode, property, value);</p><p class=MsoNormal>                                }</p><p class=MsoNormal>                });</p><p class=MsoNormal>                return proxy;</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * Proxy action, set on route.   This should only be called when a route</p><p class=MsoNormal> * is in place.  It's private an should not be called by others.</p><p class=MsoNormal> * Node are JavaSCript objects</p><p class=MsoNormal> * Field are selectors into node.</p><p class=MsoNormal> * property is the property being set and should be equal to fromField</p><p class=MsoNormal> * value is the value being set on the toNode.   To set the</p><p class=MsoNormal> * fromNode, use setField() on the proxy or setInternalField, if you don'</p><p class=MsoNormal> * want to affect the toNode.</p><p class=MsoNormal> */</p><p class=MsoNormal>function proxySetAction(fromNode, fromField, toNode, toField, property, value) {</p><p class=MsoNormal>                let fromProperty = MFStringToProperty(fromField);</p><p class=MsoNormal>                if (fromProperty != property) {</p><p class=MsoNormal>                                fatal("from"+fromField+" out of sync with property "+property+".  Did you forget to set a route?");</p><p class=MsoNormal>                }</p><p class=MsoNormal>                debug("fromField is "+fromField);</p><p class=MsoNormal>                debug("toField is "+toField);</p><p class=MsoNormal>                debug("property is "+property);</p><p class=MsoNormal>                let toProperty = MFStringToProperty(toField);</p><p class=MsoNormal>                debug("toProperty is "+toProperty);</p><p class=MsoNormal>                if (toNode == fromNode && fromField == toField) {</p><p class=MsoNormal>                                warning("We don't need to set the same value twice!");</p><p class=MsoNormal>                } else {</p><p class=MsoNormal>                                setInternalField(toNode, toProperty, value);</p><p class=MsoNormal>                }</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>                return true;</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>/**</p><p class=MsoNormal> * Activate a proxy route from fromField to toField</p><p class=MsoNormal> * The proxy map is a private object which must be passed around.  I will later</p><p class=MsoNormal> * make it unaccessible.</p><p class=MsoNormal> * Field are selectors which can be used with setInternalField()</p><p class=MsoNormal> * fromNode and toNode may be separate.  If they are the</p><p class=MsoNormal> * same, be sure that fromField and toField are distinct, or else the</p><p class=MsoNormal> * results may be undetermined.</p><p class=MsoNormal> */</p><p class=MsoNormal>function route(proxyAction, fromNode, fromField, toNode, toField) {</p><p class=MsoNormal>                info("<ROUTE fromField='"+ fromField+ "' "+ "toField='"+ toField+ "'/>"</p><p class=MsoNormal>                                );</p><p class=MsoNormal>                if (fromNode === toNode &&</p><p class=MsoNormal>                                fromField.startsWith(toField) &&</p><p class=MsoNormal>                                toField.startsWith(fromField) &&</p><p class=MsoNormal>                                fromField !== toField) {</p><p class=MsoNormal>                                warning("possible undetermined behavior, fromField "+fromField+" and toField "+toField+" overlap and the node are the same");</p><p class=MsoNormal>                }</p><p class=MsoNormal>                proxyAction[MFStringToProperty(fromField)] = function(property, value) {</p><p class=MsoNormal>                                return proxySetAction(fromNode, fromField,</p><p class=MsoNormal>                                                toNode, toField,</p><p class=MsoNormal>                                                property, value);</p><p class=MsoNormal>                };</p><p class=MsoNormal>}<o:p></o:p></p></div></body></html>