]> err.no Git - sope/blob - Recycler/NGObjDOM/Dynamic.subproj/ODR_bind_form.m
more directory hierarchy reorganisations,
[sope] / Recycler / NGObjDOM / Dynamic.subproj / ODR_bind_form.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include <NGObjDOM/ODNodeRenderer.h>
24 #include <EOControl/EOKeyValueCoding.h>
25
26 /*
27    attributes:
28
29    usage:
30
31      <var:form const:src="/blah.sfm">
32        <var:param const:name="color"    const:value="green"/>
33        <var:param const:name="document" value="document"/>
34      </var:form>
35
36    form attributes
37      src
38
39    param attributes
40      name
41      value
42      type
43
44    NOTE: currently the context is stacked to the parent during the
45    synchronizations !!!
46 */
47
48 @interface ODR_bind_form : ODNodeRenderer
49 @end
50
51 //#define PROFILE 1
52
53 #include "common.h"
54 #include "used_privates.h"
55 #include <NGObjDOM/ODNodeRendererFactory.h>
56 #include <NGObjDOM/ODNamespaces.h>
57 #include <DOM/EDOM.h>
58 #include <NGObjWeb/NGObjWeb.h>
59
60 @interface _ODRBindFormTemplateWrapper : WODynamicElement
61 @end
62
63 @interface WOComponent(BindFormSupport)
64 - (void)_addChildForm:(WOComponent *)_form withId:(NSString *)_fid;
65 - (void)setSubComponents:(NSDictionary *)_sc;
66 - (NSDictionary *)_subComponents;
67 - (WOComponent *)childComponentWithName:(NSString *)_name;
68 @end
69
70 @implementation WOComponent(ChildForms)
71
72 - (void)_addChildForm:(WOComponent *)_form withId:(NSString *)_fid {
73   NSMutableDictionary *msc;
74   NSDictionary *sc;
75   
76   if (_form == nil)       return;
77   if ([_fid length] == 0) return;
78   
79   sc = [self _subComponents];
80   msc = sc
81     ? [sc mutableCopy]
82     : [[NSMutableDictionary alloc] initWithCapacity:4];
83   
84   [msc setObject:_form forKey:_fid];
85   
86   [self setSubComponents:msc];
87   RELEASE(msc); msc = nil;
88 }
89
90 @end /* WOComponent(ChildForms) */
91
92 @implementation ODR_bind_form
93
94 - (WOComponent *)_childComponentForNode:(id)_node
95   inContext:(WOContext *)_ctx
96 {
97   WOComponent *form, *parent;
98   NSString    *src;
99   NSString    *fid;
100   
101   BEGIN_PROFILE;
102   
103   form   = nil;
104   parent = [_ctx component];
105   
106   /* try to lookup in cache */
107
108   fid = [self stringFor:@"id" node:_node ctx:_ctx];
109   
110   if ([fid length] == 0)
111     fid = [self uniqueIDForNode:_node inContext:_ctx];
112   
113   if ([fid length] > 0) {
114     fid = [NSString stringWithFormat:@"ODR_bind_form:%@", fid];
115 #if DEBUG && 0
116     NSLog(@"FID: %@", fid);
117 #endif
118     
119     if ((form = [parent childComponentWithName:fid]))
120       return form;
121   }
122   
123   /* try to instantiate form */
124   
125   if ((src = [self stringFor:@"src" node:_node ctx:_ctx])) {
126     //NSLog(@"%s: embed form '%@'", __PRETTY_FUNCTION__, src);
127     
128     PROFILE_CHECKPOINT("begin loading ..");
129     
130     //    NSLog(@"loading '%@' ...", src);
131     form = [parent pageWithName:src];
132     
133     PROFILE_CHECKPOINT("and not a page form ..");
134     
135     if (form == nil) {
136       [parent logWithFormat:@"(%@): found no subform at src '%@'",
137                 NSStringFromClass([parent class]), src];
138     }
139   }
140   
141   /* insert form in cache ... */
142   if (form) [[_ctx component] _addChildForm:form withId:fid];
143   
144   END_PROFILE;
145   
146   return form;
147 }
148
149 - (WOElement *)_childContentForNode:(id)_node inContext:(WOContext *)_ctx {
150   return nil;
151 }
152
153 - (void)_syncComponent:(WOComponent *)_form
154   parent:(WOComponent *)_parent
155   node:(id)_node
156   syncUp:(BOOL)_syncUp
157   inContext:(WOContext *)_ctx
158 {
159   /* Watch out for correct context when calling this method ! */
160   static DOMQueryPathExpression *qpexpr = nil;
161   NSEnumerator *childNodes;
162   id           childNode;
163   
164   BEGIN_PROFILE;
165   
166   if (_node == nil)
167     return;
168   
169   if (qpexpr == nil)
170     qpexpr = [[DOMQueryPathExpression queryPathWithString:@"-param"] retain];
171   
172   childNodes = _syncUp
173     ? [(NSArray *)[_node childNodes] objectEnumerator]
174     : [(NSArray *)[_node childNodes] reverseObjectEnumerator];
175   
176   while ((childNode = [childNodes nextObject])) {
177     NSString *pname;
178     NSString *ptype;
179     id       pvalue;
180     
181     if ([childNode nodeType] != DOM_ELEMENT_NODE)
182       continue;
183     if (![[childNode tagName] isEqualToString:@"param"])
184       continue;
185     
186     pname = [self stringFor:@"name" node:childNode ctx:_ctx];
187     ptype = [self stringFor:@"type" node:childNode ctx:_ctx];
188     
189     if (_syncUp) {
190       id attrNode;
191       
192       if ([ptype isEqualToString:@"in"])
193         continue;
194       
195       attrNode = [[childNode attributes]
196                              namedItem:@"value"
197                              namespaceURI:XMLNS_OD_BIND];
198       if (attrNode == nil) {
199 #if DEBUG && 0
200         NSLog(@"%s: no up sync possible, missing proper value attribute ..",
201               __PRETTY_FUNCTION__);
202 #endif
203         continue;
204       }
205       
206       pvalue = [_form valueForKey:pname];
207       
208 #if DEBUG && 0
209       [[_ctx component]
210              logWithFormat:@"sync up value %@ to %@", pvalue, [attrNode value]];
211 #endif
212       
213       [_parent takeValue:pvalue forKeyPath:[attrNode value]];
214     }
215     else {
216       if ([ptype isEqualToString:@"out"])
217         continue;
218       
219       pvalue = [self valueFor:@"value" node:childNode ctx:_ctx];
220 #if DEBUG && 0
221       [[_ctx component]
222              logWithFormat:
223                @"sync down value '%@' to '%@'", pvalue, pname];
224 #endif
225
226       [_form takeValue:pvalue forKey:pname];
227     }
228   }
229   
230   END_PROFILE;
231 }
232
233 - (void)takeValuesForNode:(id)_node
234   fromRequest:(WORequest *)_request
235   inContext:(WOContext *)_ctx
236 {
237   WOComponent *childComponent;
238   WOComponent *parentComponent;
239   
240   childComponent = [self _childComponentForNode:_node inContext:_ctx];
241   if (childComponent == nil)
242     return;
243
244   parentComponent = [_ctx component];
245   
246   [self _syncComponent:childComponent
247         parent:parentComponent
248         node:_node
249         syncUp:NO
250         inContext:_ctx];
251   
252   [_ctx enterComponent:childComponent
253         content:[self _childContentForNode:_node inContext:_ctx]];
254   
255   [childComponent takeValuesFromRequest:_request inContext:_ctx];
256
257   [_ctx leaveComponent:childComponent];
258   
259   [self _syncComponent:childComponent
260         parent:parentComponent
261         node:_node
262         syncUp:YES
263         inContext:_ctx];
264 }
265
266 - (id)invokeActionForNode:(id)_node
267   fromRequest:(WORequest *)_request
268   inContext:(WOContext *)_ctx
269 {
270   WOComponent *childComponent;
271   WOComponent *parentComponent;
272   id result;
273
274   BEGIN_PROFILE;
275
276   childComponent = [self _childComponentForNode:_node inContext:_ctx];
277   if (childComponent == nil) {
278 #if DEBUG
279     [[_ctx component] debugWithFormat:@"missing child component .."];
280 #endif
281     return nil;
282   }
283   
284   parentComponent = [_ctx component];
285   
286   [self _syncComponent:childComponent
287         parent:parentComponent
288         node:_node
289         syncUp:NO
290         inContext:_ctx];
291   
292   [_ctx enterComponent:childComponent
293         content:[self _childContentForNode:_node inContext:_ctx]];
294   
295 #if DEBUG && 0
296   [[_ctx component] debugWithFormat:@" %s\nsid=%@\neid=%@",
297                       __PRETTY_FUNCTION__,
298                       [_ctx senderID], [_ctx elementID]];
299 #endif
300   
301   result = [childComponent invokeActionForRequest:_request inContext:_ctx];
302   
303   [_ctx leaveComponent:childComponent];
304   
305   [self _syncComponent:childComponent
306         parent:parentComponent
307         node:_node
308         syncUp:YES
309         inContext:_ctx];
310
311   END_PROFILE;
312   
313   return result;
314 }
315
316 - (void)appendNode:(id)_node
317   toResponse:(WOResponse *)_response
318   inContext:(WOContext *)_ctx
319 {
320   WOComponent *childComponent;
321   WOComponent *parentComponent;
322
323   BEGIN_PROFILE;
324   
325   childComponent = [self _childComponentForNode:_node inContext:_ctx];
326   if (childComponent == nil)
327     return;
328   
329   parentComponent = [_ctx component];
330
331   PROFILE_CHECKPOINT("sync down ..");
332   
333   [self _syncComponent:childComponent
334         parent:parentComponent
335         node:_node
336         syncUp:NO
337         inContext:_ctx];
338
339   PROFILE_CHECKPOINT("enter stack ..");
340   
341   [_ctx enterComponent:childComponent
342         content:[self _childContentForNode:_node inContext:_ctx]];
343
344   PROFILE_CHECKPOINT("append child ..");
345   
346   [childComponent appendToResponse:_response inContext:_ctx];
347   
348   PROFILE_CHECKPOINT("leave stack ..");
349   
350   [_ctx leaveComponent:childComponent];
351
352   PROFILE_CHECKPOINT("sync up ..");
353   
354   [self _syncComponent:childComponent
355         parent:parentComponent
356         node:_node
357         syncUp:YES
358         inContext:_ctx];
359
360   END_PROFILE;
361 }
362
363 @end /* ODR_bind_embed */
364
365 @implementation _ODRBindFormTemplateWrapper
366
367 - (id)_nodeInContext:(WOContext *)_ctx {
368   return nil;
369 }
370
371 - (ODNodeRenderer *)rendererForNode:(id)_domNode inContext:(WOContext *)_ctx {
372   id<ODNodeRendererFactory> factory;
373   ODNodeRenderer *renderer = nil;
374
375   if ((factory = [_ctx objectForKey:@"domRenderFactory"]))
376     renderer = [factory rendererForNode:_domNode inContext:_ctx];
377
378   return renderer;
379 }
380
381 - (void)takeValuesFromRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
382   ODNodeRenderer *lrenderer = nil;
383   id dom;
384   
385   if ((dom = [self _nodeInContext:_ctx]) == nil)
386     return;
387
388   [lrenderer takeValuesForNode:dom
389              fromRequest:_request
390              inContext:_ctx];
391 }
392
393 - (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
394   ODNodeRenderer *lrenderer = nil;
395   id dom;
396   
397   if ((dom = [self _nodeInContext:_ctx]) == nil)
398     return nil;
399   
400   return [lrenderer invokeActionForNode:dom
401                     fromRequest:_request
402                     inContext:_ctx];
403 }
404
405 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
406   ODNodeRenderer *lrenderer;
407   id dom;
408   
409   if ((dom = [self _nodeInContext:_ctx]) == nil)
410     return;
411
412   if ((lrenderer = [self rendererForNode:dom inContext:_ctx]) == nil) {
413 #if DEBUG_DOM
414     [cmp logWithFormat:@"did not find renderer for node %@", dom];
415     [_response appendContentString:@"<!-- missing dom renderer -->"];
416 #endif
417     return;
418   }
419
420 #if DEBUG_DOM
421   NSAssert(lrenderer, @"lost renderer ..");
422 #endif
423
424   [lrenderer appendNode:dom
425              toResponse:_response
426              inContext:_ctx];
427
428 #if DEBUG_DOM
429   NSAssert(_response, @"lost response ..");
430   [_response appendContentString:@"<!-- renderdom-end -->"];
431 #endif
432 }
433
434 @end /* _ODRBindFormTemplateWrapper */