wip: context transformation - return original context instance during first run
[fnpeditor.git] / src / smartxml / transformations.js
1 define(function(require) {
2     
3 'use strict';
4
5 var _ = require('libs/underscore'),
6     toret = {};
7
8 var getTransDesc = function(desc, name) {
9     if(typeof desc === 'function') {
10         desc = {impl: desc};
11     }
12     if(!desc.impl) {
13         throw new Error('Got transformation description without implementation.')
14     }
15     return desc;
16 };
17
18 toret.createGenericTransformation = function(desc, name) {
19     desc = getTransDesc(desc);
20     
21     var GenericTransformation = function(document, args) {
22         this.args = args || {};
23
24         var transformation = this;
25         _.keys(this.args).forEach(function(key) {
26             if(transformation.args[key].nodeType) { //@@ change to instanceof check, fix circular dependency
27                 var value = transformation.args[key],
28                     path = value.getPath();
29                 Object.defineProperty(transformation.args, key, {
30                     get: function() {
31                         if(transformation.hasRun) {
32                             //console.log('returning via path');
33                             return transformation.document.getNodeByPath(path);
34                         } else {
35                             //console.log('returning original arg');
36                             return value;
37
38                         }
39                     }
40                 });
41             }
42         });
43         this.document = document;
44         this.hasRun = false;
45         if(desc.init) {
46             desc.init.call(this);
47         }
48     };
49     _.extend(GenericTransformation.prototype, {
50         name: name,
51         run: function() {
52             var changeRoot;
53             if(!desc.undo) {
54                 changeRoot = desc.getChangeRoot ? desc.getChangeRoot.call(this) : this.document.root;
55                 this.snapshot = changeRoot.clone();
56                 this.changeRootPath = changeRoot.getPath();
57             }
58             var toret = desc.impl.call(this.context, this.args); // a argumenty do metody?
59             this.hasRun = true;
60             return toret;
61         },
62         undo: function() {
63             if(desc.undo) {
64                 desc.undo.call(this.context);
65             } else {
66                 this.document.getNodeByPath(this.changeRootPath).replaceWith(this.snapshot);
67             }
68         },
69     });
70
71     return GenericTransformation;
72 };
73 // var T = createGenericTransformation({impl: function() {}});
74 // var t = T(doc, {a:1,b:2,c3:3});
75
76
77 toret.createContextTransformation = function(desc, name) {
78     // mozna sie pozbyc przez przeniesienie object/context na koniec argumentow konstruktora generic transformation
79     var GenericTransformation = toret.createGenericTransformation(desc, name);
80
81     var ContextTransformation = function(document, object, args) {
82         GenericTransformation.call(this, document, args);
83
84         if(document === object) {
85             this.context = document;
86         } else {      
87             var contextPath = object.getPath(),
88                 transformation = this;
89             Object.defineProperty(this, 'context', {
90                 get: function() {
91                     // todo: to jakos inaczej, bo np. this.context w undo transformacji before to juz nie ten sam obiekt
92                     // moze transformacja powinna zwracac zmodyfikowana sciezke do obiektu po dzialaniu run?
93                     
94                     if(transformation.hasRun) {
95                         //console.log('returning via path');
96                         return transformation.document.getNodeByPath(contextPath);
97                     } else {
98                         //console.log('returning original arg');
99                         return object;
100
101                     }
102                 }
103             });
104         }
105     }
106     ContextTransformation.prototype = Object.create(GenericTransformation.prototype);
107     return ContextTransformation;
108 }
109 // var T = createContextTransformation({impl: function() {}});
110 // var t = T(doc, node, {a:1,b:2,c3:3});
111 ///
112
113
114
115 toret.TransformationStorage = function() {
116     this._transformations = {};
117 };
118
119 _.extend(toret.TransformationStorage.prototype, {
120     
121     register: function(Transformation) {
122         var list = (this._transformations[Transformation.prototype.name] = this._transformations[Transformation.prototype.name] || []);
123         list.push(Transformation);
124     },
125
126     get: function(name) {
127         var transformations = this._transformations[name];
128         if(!transformations) {
129             throw new Error('Transformation "' + name + '" not found!');
130         }
131         // na razie zwraca pierwsza
132         return transformations[0];
133     }
134 });
135
136
137
138 // var registerTransformationFromMethod = (object, methodName, desc) {
139 //         if(!object[methodName]) {
140 //             throw new Exeption('Cannot register transformation from unknown method ' + methodName + ' on ' + object);
141 //         }
142 //         desc.impl = object[name];
143 //         Transformation = createContextTransformation(desc);
144 //         object.prototype.registerContextTransformation(name, createContextTransformation(method));
145 // };
146
147
148 // registerTransformationFromMethod(ElementNode, 'setAttr', {
149 //     impl: function(args) {
150 //         this.setAttr(args.name, args.value);
151 //     },
152 //     getChangeRoot: function() {
153 //         return this.context;
154 //     }
155
156 // });
157
158 return toret;
159
160 });