]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WODynamicElement.m
fixed OGo bug #888
[sope] / sope-appserver / NGObjWeb / WODynamicElement.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
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: WODynamicElement.m 1 2004-08-20 10:08:27Z znek $
22
23 #include <NGObjWeb/WODynamicElement.h>
24 #include "WOElement+private.h"
25 #include "WOCompoundElement.h"
26 #include <NGObjWeb/WOApplication.h>
27 #include "common.h"
28
29 typedef struct _WOExtraAttrItem  {
30   NSString      *key;
31   WOAssociation *value;
32   NSString      *(*valQuery)(id,SEL,WOComponent *c);
33 } WOExtraAttrItem;
34
35 typedef struct _WOExtraAttrStruct  {
36   WOExtraAttrItem *items;
37   NSString        *extraString;
38   unsigned char   count;
39 } WOExtraAttrs;
40
41 @implementation WODynamicElement
42
43 + (int)version {
44   return [super version] + 0 /* v2 */;
45 }
46
47 static Class FormClass        = Nil;
48 static Class FormElementClass = Nil;
49
50 + (void)initialize {
51   static BOOL isInitialized = NO;
52   
53   NSAssert2([super version] == 2,
54             @"invalid superclass (%@) version %i !",
55             NSStringFromClass([self superclass]), [super version]);
56   
57   if (!isInitialized) {
58     isInitialized = YES;
59
60     FormClass        = NSClassFromString(@"WOForm");
61     FormElementClass = NSClassFromString(@"WOInput");
62   }
63 }
64
65 //static int i = 0;
66
67 - (id)initWithName:(NSString *)_name
68   associations:(NSDictionary *)_associations
69   template:(WOElement *)_rootChild
70 {
71   if ((self = [super init])) {
72     WOAssociation *t;
73     
74     self->otherTagString = OWGetProperty(_associations, @"otherTagString");
75     
76     t = OWGetProperty(_associations, @"debug");
77     self->debug = [t boolValueInComponent:nil];
78     [t release]; t = nil;
79   }
80   return self;
81 }
82 - (id)initWithName:(NSString *)_name
83   associations:(NSDictionary *)_associations
84   contentElements:(NSArray *)_contents
85 {
86   /* this method was discovered in SSLContainer.h and may not be public */
87   WOCompoundElement *template;
88   int count;
89   
90   count = [_contents count];
91   
92   if (count == 0) {
93     template = nil;
94   }
95   else if (count == 1) {
96     template = [_contents objectAtIndex:0];
97   }
98   else {
99     template = [[WOCompoundElement allocForCount:[_contents count]
100                                    zone:[self zone]]
101                                    initWithContentElements:_contents];
102   }
103   
104   return [self initWithName:_name
105                associations:_associations
106                template:template];
107 }
108
109 - (id)init {
110   return [self initWithName:[NSString stringWithFormat:@"0x%08X", self]
111                associations:nil
112                template:nil];
113 }
114
115 - (void)dealloc {
116   register WOExtraAttrs *ea;
117   
118   [self->otherTagString release];
119
120   if ((ea = self->extraAttributes) != NULL) { // GC
121     register unsigned short i;
122     
123     [ea->extraString release];
124     for (i = 0; i < ea->count; i++) {
125       [ea->items[i].key   release];
126       [ea->items[i].value release];
127     }
128     if (ea->items)
129       free(ea->items);
130     
131     free(self->extraAttributes);
132     self->extraAttributes = ea = NULL;
133   }
134   [super dealloc];
135 }
136
137 /* accessors */
138
139 - (NSString *)elementID {
140   return [[[WOApplication application] context] elementID];
141 }
142
143 - (void)setExtraAttributes:(NSDictionary *)_extras {
144   register WOExtraAttrs *ea;
145   NSEnumerator    *ke;
146   NSString        *key;
147   NSMutableString *es;
148
149   if ([_extras count] == 0)
150     /* no extra attributes ... */
151     return;
152   
153   if (self->extraAttributes) {
154     NSLog(@"ERROR(%s): tried to reset extra attributes (access denied) !!!",
155           __PRETTY_FUNCTION__);
156     return;
157   }
158   
159   /* setup structure */
160
161   ea = calloc(1, sizeof(WOExtraAttrs));
162   ea->count = 0;
163   ea->items = calloc([_extras count], sizeof(WOExtraAttrItem));
164   
165   /* fill structure */
166   
167   es = nil;
168   ke = [_extras keyEnumerator];
169   while ((key = [ke nextObject])) {
170     WOAssociation *value;
171
172     //key   = [key lowercaseString];
173     value = [_extras objectForKey:key];
174     
175     if ([value isValueConstant]) {
176       /* static value (calculated *now*) */
177       NSString *s;
178       
179       if (es == nil)
180         es = [[NSMutableString alloc] initWithCapacity:128];
181       
182       /* query value */
183       s = [value stringValueInComponent:nil];
184       
185       /* HTML escape value ... */
186       s = [s stringByEscapingHTMLAttributeValue];
187       
188       /* add to static string */
189       [es appendString:@" "];
190       [es appendString:key];
191       [es appendString:@"=\""];
192       [es appendString:s];
193       [es appendString:@"\""];
194     }
195     else {
196       /* dynamic value (calculated at runtime) */
197       register WOExtraAttrItem *item;
198       
199       item = &(ea->items[ea->count]);
200       item->key   = [key copy];
201       item->value = RETAIN(value);
202       item->valQuery = /* cache method IMP */
203         (void*)[value methodForSelector:@selector(stringValueInComponent:)];
204       ea->count++;
205     }
206   }
207   
208   /* check results for static vs dynamic ... */
209   
210   if (ea->count == 0) {
211     /* no dynamic attributes, free items structure ... */
212     free(ea->items);
213     ea->items = NULL;
214   }
215   if ([es length] > 0) ea->extraString = [es copy];
216   [es release]; es = nil;
217   
218   /* finish */
219   self->extraAttributes = ea;
220 }
221
222 - (WOElement *)template {
223   return nil;
224 }
225
226 + (BOOL)isDynamicElement {
227   return YES;
228 }
229
230 /* description */
231
232 - (void)appendExtraAttributesToResponse:(WOResponse *)_response
233   inContext:(WOContext *)_ctx
234 {
235   if (self->extraAttributes) {
236     register WOExtraAttrs *ea;
237     
238     ea = self->extraAttributes;
239     
240     if (ea->count > 0) {
241       /* has dynamic attributes */
242       WOComponent *sComponent;
243       register unsigned short i;
244       
245       sComponent = [_ctx component];
246       
247       for (i = 0; i < ea->count; i++) {
248         register WOExtraAttrItem *item;
249         NSString *value;
250         
251         item = &(ea->items[i]);
252         
253         if (item->valQuery) {
254           /* use cached selector implementation */
255           value = item->valQuery(item->value,@selector(stringValueInComponent:),
256                                  sComponent);
257         }
258         else {
259           value = [item->value stringValueInComponent:sComponent];
260         }
261         
262         WOResponse_AddChar(_response, ' ');
263         WOResponse_AddString(_response, item->key);
264         WOResponse_AddCString(_response, "=\"");
265         [_response appendContentHTMLAttributeValue:value];
266         WOResponse_AddChar(_response, '"');
267       }
268     }
269     
270     /* add static string */
271     if (ea->extraString)
272       WOResponse_AddString(_response, ea->extraString);
273   }
274 }
275
276 - (NSString *)associationDescription {
277 #if 1
278   return nil;
279 #else
280   if (self->extraAttributes) {
281     NSMutableString *ad;
282     NSEnumerator *keys;
283     NSString     *key;
284
285     ad = [NSMutableString stringWithCapacity:32];
286     keys = [self->extraAttributes keyEnumerator];
287     while ((key = [keys nextObject])) {
288       WOAssociation *value;
289       
290       value = [self->extraAttributes objectForKey:key];
291       
292       [ad appendString:@" "];
293       [ad appendString:key];
294       [ad appendString:@"="];
295       [ad appendString:[value description]];
296     }
297     return ad;
298   }
299   else
300     return nil;
301 #endif
302 }
303
304 - (NSString *)description {
305   NSMutableString *desc      = [NSMutableString stringWithCapacity:100];
306   NSString        *assocDesc = [self associationDescription];
307
308   [desc appendFormat:@"<%@[0x%08X]:", NSStringFromClass([self class]), self];
309   if (assocDesc) [desc appendString:assocDesc];
310   [desc appendString:@">"];
311
312   return desc;
313 }
314
315 @end /* WODynamicElement */
316
317 #include <DOM/EDOM.h>
318 #include <NGObjWeb/NGObjWeb.h>
319 #include <NGObjWeb/WOxElemBuilder.h>
320 #include <SaxObjC/XMLNamespaces.h>
321 #include "common.h"
322
323 /*
324   The new DOM element init function for elements constructed from DOM element
325   nodes.
326
327   The default method is defined on NSObject instead of WOElement, since some
328   dynamic elements are class clusters, which use temporary non-WOElement 
329   classes during construction.
330
331   The default construction process requires no support from existing NGObjWeb
332   elements.
333   It maps all tag attributes to element associations and all child nodes to 
334   subelements.
335   The tagname is used as the dynamic element name.
336 */
337
338 @implementation NSObject(InitElement)
339
340 - (id)initWithElement:(id<DOMElement>)_element
341   templateBuilder:(WOxElemBuilder *)_builder
342 {
343   NSString            *name;
344   NSMutableDictionary *assocs;
345   NSArray             *children;
346   id<NSObject,DOMNamedNodeMap> attrs;
347   unsigned count;
348   
349   name = [_element tagName];
350   
351   /* construct associations */
352   
353   assocs = nil;
354   attrs = [_element attributes];
355   if ((count = [attrs length]) > 0)
356     assocs = [_builder associationsForAttributes:attrs];
357   
358   /* construct child elements */
359   
360   if ([_element hasChildNodes]) {
361     /* look for var:binding tags ... */
362     
363     children = [_builder buildNodes:[_element childNodes]
364                          templateBuilder:_builder];
365   }
366   else
367     children = nil;
368   
369   /* construct self ... */
370   
371   self = [(WODynamicElement *)self initWithName:name 
372                                    associations:assocs 
373                                    contentElements:children];
374   [(id)self setExtraAttributes:assocs];
375   return self;
376 }
377
378 @end /* NSObject(InitElement) */