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