refactoring
[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     desc.name = desc.name || name;
16     return desc;
17 };
18
19 toret.createGenericTransformation = function(desc, name) {
20     desc = getTransDesc(desc, name);
21     
22     var GenericTransformation = function(document, args) {
23         this.args = args || {};
24
25         var transformation = this;
26         _.keys(this.args).forEach(function(key) {
27             if(transformation.args[key].nodeType) { //@@ change to instanceof check, fix circular dependency
28                 var value = transformation.args[key],
29                     path = value.getPath();
30                 Object.defineProperty(transformation.args, key, {
31                     get: function() {
32                         if(transformation.hasRun) {
33                             //console.log('returning via path');
34                             return transformation.document.getNodeByPath(path);
35                         } else {
36                             //console.log('returning original arg');
37                             return value;
38
39                         }
40                     }
41                 });
42             }
43         });
44         this.document = document;
45         this.hasRun = false;
46         if(desc.init) {
47             desc.init.call(this);
48         }
49     };
50     _.extend(GenericTransformation.prototype, {
51         name: desc.name,
52         run: function() {
53             var changeRoot;
54             if(!desc.undo) {
55                 changeRoot = desc.getChangeRoot ? desc.getChangeRoot.call(this) : this.document.root;
56                 this.snapshot = changeRoot.clone();
57                 this.changeRootPath = changeRoot.getPath();
58             }
59             var toret = desc.impl.call(this.context, this.args); // a argumenty do metody?
60             this.hasRun = true;
61             return toret;
62         },
63         undo: function() {
64             if(desc.undo) {
65                 desc.undo.call(this.context);
66             } else {
67                 this.document.getNodeByPath(this.changeRootPath).replaceWith(this.snapshot);
68             }
69         },
70     });
71
72     return GenericTransformation;
73 };
74 // var T = createGenericTransformation({impl: function() {}});
75 // var t = T(doc, {a:1,b:2,c3:3});
76
77
78 toret.createContextTransformation = function(desc, name) {
79     // mozna sie pozbyc przez przeniesienie object/context na koniec argumentow konstruktora generic transformation
80     var GenericTransformation = toret.createGenericTransformation(desc, name);
81
82     var ContextTransformation = function(document, object, args) {
83         GenericTransformation.call(this, document, args);
84
85         if(document === object) {
86             this.context = document;
87         } else {      
88             var contextPath = object.getPath();
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                     // tu tez trick z hasRun
95                     return document.getNodeByPath(contextPath);
96                 }
97             });
98         }
99     }
100     ContextTransformation.prototype = Object.create(GenericTransformation.prototype);
101     return ContextTransformation;
102 }
103 // var T = createContextTransformation({impl: function() {}});
104 // var t = T(doc, node, {a:1,b:2,c3:3});
105 ///
106
107
108
109 toret.TransformationStorage = function() {
110     this._transformations = {};
111 };
112
113 _.extend(toret.TransformationStorage.prototype, {
114     
115     register: function(Transformation) {
116         var list = (this._transformations[Transformation.prototype.name] = this._transformations[Transformation.prototype.name] || []);
117         list.push(Transformation);
118     },
119
120     get: function(name) {
121         var transformations = this._transformations[name];
122         if(!transformations) {
123             throw new Error('Transformation "' + name + '" not found!');
124         }
125         // na razie zwraca pierwsza
126         return transformations[0];
127     }
128 });
129
130
131
132 // var registerTransformationFromMethod = (object, methodName, desc) {
133 //         if(!object[methodName]) {
134 //             throw new Exeption('Cannot register transformation from unknown method ' + methodName + ' on ' + object);
135 //         }
136 //         desc.impl = object[name];
137 //         Transformation = createContextTransformation(desc);
138 //         object.prototype.registerContextTransformation(name, createContextTransformation(method));
139 // };
140
141
142 // registerTransformationFromMethod(ElementNode, 'setAttr', {
143 //     impl: function(args) {
144 //         this.setAttr(args.name, args.value);
145 //     },
146 //     getChangeRoot: function() {
147 //         return this.context;
148 //     }
149
150 // });
151
152 return toret;
153
154 });