wlxml: Allow for setting non-function properties via extension
[fnpeditor.git] / src / smartxml / transformations.js
index 25c0ec1..4a8e5a8 100644 (file)
@@ -5,6 +5,7 @@ define(function(require) {
 var _ = require('libs/underscore'),
     toret = {};
 
+
 var getTransDesc = function(desc) {
     if(typeof desc === 'function') {
         desc = {impl: desc};
@@ -20,67 +21,37 @@ toret.createGenericTransformation = function(desc, name) {
     
     var GenericTransformation = function(document, args) {
         this.args = args || [];
-
         var transformation = this;
-        // _.keys(this.args).forEach(function(key) {
-        //     if(transformation.args[key].nodeType) { //@@ change to instanceof check, fix circular dependency
-        //         var value = transformation.args[key],
-        //             path = value.getPath();
-        //         Object.defineProperty(transformation.args, key, {
-        //             get: function() {
-        //                 if(transformation.hasRun) {
-        //                     //console.log('returning via path');
-        //                     return transformation.document.getNodeByPath(path);
-        //                 } else {
-        //                     //console.log('returning original arg');
-        //                     return value;
-
-        //                 }
-        //             }
-        //         });
-        //     }
-        // });
-
-        // potem spr na dotychczasowych undo/redo tests;
         
+        var patchObject = function(obj, depth) {
+            depth = _.isNumber(depth) ? depth : 1;
+            if(depth > 3) {
+                return;
+            }
+            _.keys(obj).forEach(function(key) {
+                var value = obj[key];
+                if(value) {
+                    if(value.nodeType) {
+                        transformation.wrapNodeProperty(obj, key);
+                    } else if(_.isObject(value)) {
+                        patchObject(value, depth+1);
+                    }
+                }
+            });
+        };
 
         this.args.forEach(function(arg, idx, args) {
-            var path;
             if(arg) {
                 if(arg.nodeType) { // ~
-                    path = arg.getPath();
-                    Object.defineProperty(args, idx, {
-                        get: function() {
-                            if(transformation.hasRun && path) {
-                                return transformation.document.getNodeByPath(path);
-                            } else {
-                                return arg;
-                            }
-                        }
-                    });
+                    transformation.wrapNodeProperty(args, idx);
                 } else if(_.isObject(arg)) {
-                    _.keys(arg).forEach(function(key) {
-                        var value = arg[key],
-                            path;
-                        if(value && value.nodeType) {
-                            path = value.getPath();
-                            Object.defineProperty(arg, key, {
-                                get: function() {
-                                    if(transformation.hasRun && path) {
-                                        return transformation.document.getNodeByPath(path);
-                                    } else {
-                                        return value;
-                                    }
-                                }
-                            });
-                        }
-                    });
+                    patchObject(arg);
                 }
             }
         });
 
         this.document = document;
-        this.hasRun = false;
+        this.runCount = 0;
         if(desc.init) {
             desc.init.call(this);
         }
@@ -90,22 +61,51 @@ toret.createGenericTransformation = function(desc, name) {
         run: function(options) {
             var changeRoot;
             if(!desc.undo && options.beUndoable) {
-                changeRoot = desc.getChangeRoot ? desc.getChangeRoot.call(this) : this.document.root;
-                this.snapshot = changeRoot.clone();
+                changeRoot = this.getChangeRoot();
+                if(!changeRoot) {
+                     throw new Error(
+                         'Transformation {name} returned invalid change root value'
+                         .replace('{name}', name)
+                     );
+                }
                 this.changeRootPath = changeRoot.getPath();
+                this.snapshot = changeRoot.clone();
             }
             var argsToPass = desc.undo ? [this].concat(this.args) : this.args;
             var toret = desc.impl.apply(this.context, argsToPass);
-            this.hasRun = true;
+            this.runCount++;
             return toret;
         },
         undo: function() {
             if(desc.undo) {
                 desc.undo.call(this.context, this);
+                this.runCount++;
             } else {
                 this.document.getNodeByPath(this.changeRootPath).replaceWith(this.snapshot);
             }
         },
+        getChangeRoot: desc.getChangeRoot || function() {
+            return this.document.root;
+        },
+        wrapNodeProperty: function(object, propName, value) {
+            var transformation = this,
+                lastRunNumber = 0,
+                path;
+            
+            value = value || object[propName];
+            if(value && value.nodeType) {
+                path = value.getPath();
+                Object.defineProperty(object, propName, {
+                    get: function() {
+                        if((lastRunNumber !== transformation.runCount) && path) {
+                            value = transformation.document.getNodeByPath(path);
+                            lastRunNumber = transformation.runCount;
+                        }
+                        return value;
+                    }
+                });
+            }
+        }
     });
 
     return GenericTransformation;
@@ -120,17 +120,7 @@ toret.createContextTransformation = function(desc, name) {
         if(document === object) {
             this.context = document;
         } else {
-            var contextPath = object.getPath(),
-                transformation = this;
-            Object.defineProperty(this, 'context', {
-                get: function() {
-                    if(transformation.hasRun) {
-                        return transformation.document.getNodeByPath(contextPath);
-                    } else {
-                        return object;
-                    }
-                }
-            });
+            this.wrapNodeProperty(this, 'context', object);
         }
     };
     ContextTransformation.prototype = Object.create(GenericTransformation.prototype);