5f0756cf8a842b614be942542daf3953d41d6e7b
[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
44         // potem spr na dotychczasowych undo/redo tests;
45         this.args.forEach(function(arg, idx, args) {
46             if(arg.nodeType) { // ~
47                 var path = arg.getPath();
48                 Object.defineProperty(args, idx, {
49                     get: function() {
50                         if(transformation.hasRun) {
51                             return transformation.document.getNodeByPath(path);
52                         } else {
53                             return arg;
54                         }
55                     }
56                 });
57             }
58         });
59
60         this.document = document;
61         this.hasRun = false;
62         if(desc.init) {
63             desc.init.call(this);
64         }
65     };
66     _.extend(GenericTransformation.prototype, {
67         name: name,
68         run: function() {
69             var changeRoot;
70             if(!desc.undo) {
71                 changeRoot = desc.getChangeRoot ? desc.getChangeRoot.call(this) : this.document.root;
72                 this.snapshot = changeRoot.clone();
73                 this.changeRootPath = changeRoot.getPath();
74             }
75             //var toret = desc.impl.call(this.context, this.args); // a argumenty do metody?
76             var toret = desc.impl.apply(this.context, this.args);
77             this.hasRun = true;
78             return toret;
79         },
80         undo: function() {
81             if(desc.undo) {
82                 desc.undo.call(this.context);
83             } else {
84                 this.document.getNodeByPath(this.changeRootPath).replaceWith(this.snapshot);
85             }
86         },
87     });
88
89     return GenericTransformation;
90 };
91 // var T = createGenericTransformation({impl: function() {}});
92 // var t = T(doc, {a:1,b:2,c3:3});
93
94
95 toret.createContextTransformation = function(desc, name) {
96     // mozna sie pozbyc przez przeniesienie object/context na koniec argumentow konstruktora generic transformation
97     var GenericTransformation = toret.createGenericTransformation(desc, name);
98
99     var ContextTransformation = function(document, object, args) {
100         GenericTransformation.call(this, document, args);
101
102         if(document === object) {
103             this.context = document;
104         } else {      
105             var contextPath = object.getPath(),
106                 transformation = this;
107             Object.defineProperty(this, 'context', {
108                 get: function() {
109                     // todo: to jakos inaczej, bo np. this.context w undo transformacji before to juz nie ten sam obiekt
110                     // moze transformacja powinna zwracac zmodyfikowana sciezke do obiektu po dzialaniu run?
111                     
112                     if(transformation.hasRun) {
113                         //console.log('returning via path');
114                         return transformation.document.getNodeByPath(contextPath);
115                     } else {
116                         //console.log('returning original arg');
117                         return object;
118
119                     }
120                 }
121             });
122         }
123     }
124     ContextTransformation.prototype = Object.create(GenericTransformation.prototype);
125     return ContextTransformation;
126 }
127 // var T = createContextTransformation({impl: function() {}});
128 // var t = T(doc, node, {a:1,b:2,c3:3});
129 ///
130
131
132
133 toret.TransformationStorage = function() {
134     this._transformations = {};
135 };
136
137 _.extend(toret.TransformationStorage.prototype, {
138     
139     register: function(Transformation) {
140         var list = (this._transformations[Transformation.prototype.name] = this._transformations[Transformation.prototype.name] || []);
141         list.push(Transformation);
142     },
143
144     get: function(name) {
145         var transformations = this._transformations[name];
146         if(!transformations) {
147             throw new Error('Transformation "' + name + '" not found!');
148         }
149         // na razie zwraca pierwsza
150         return transformations[0];
151     }
152 });
153
154
155
156 // var registerTransformationFromMethod = (object, methodName, desc) {
157 //         if(!object[methodName]) {
158 //             throw new Exeption('Cannot register transformation from unknown method ' + methodName + ' on ' + object);
159 //         }
160 //         desc.impl = object[name];
161 //         Transformation = createContextTransformation(desc);
162 //         object.prototype.registerContextTransformation(name, createContextTransformation(method));
163 // };
164
165
166 // registerTransformationFromMethod(ElementNode, 'setAttr', {
167 //     impl: function(args) {
168 //         this.setAttr(args.name, args.value);
169 //     },
170 //     getChangeRoot: function() {
171 //         return this.context;
172 //     }
173
174 // });
175
176 return toret;
177
178 });