From 53f21017f9ddd83b9133fdcb14d4b1b6f02f57d1 Mon Sep 17 00:00:00 2001 From: helge Date: Tue, 19 Jul 2005 15:15:14 +0000 Subject: [PATCH] added JSStringTable dynamic element git-svn-id: http://svn.opengroupware.org/SOPE/trunk@920 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-appserver/WEExtensions/ChangeLog | 9 + sope-appserver/WEExtensions/GNUmakefile | 2 + sope-appserver/WEExtensions/JSMenu.h | 12 +- sope-appserver/WEExtensions/JSStringTable.api | 9 + sope-appserver/WEExtensions/JSStringTable.m | 277 ++++++++++++++++++ sope-appserver/WEExtensions/Version | 3 +- sope-appserver/WEExtensions/WEDateField.m | 15 +- .../WEExtensions/WExExtElemBuilder.m | 12 +- sope-appserver/WEExtensions/bundle-info.plist | 3 +- 9 files changed, 320 insertions(+), 22 deletions(-) create mode 100644 sope-appserver/WEExtensions/JSStringTable.api create mode 100644 sope-appserver/WEExtensions/JSStringTable.m diff --git a/sope-appserver/WEExtensions/ChangeLog b/sope-appserver/WEExtensions/ChangeLog index db16c355..3d20e05d 100644 --- a/sope-appserver/WEExtensions/ChangeLog +++ b/sope-appserver/WEExtensions/ChangeLog @@ -1,5 +1,14 @@ 2005-07-19 Helge Hess + * v4.5.76 + + * WExExtElemBuilder.m: expose JSStringTable as var:js-stringtable + + * added JSStringTable dynamic element to expose localization string + tables as JavaScript arrays on the client side + + * WEDateField.m, JSMenu.h: minor code cleanups + * v4.5.75 * WEStringTableManager.m: reworked table manager diff --git a/sope-appserver/WEExtensions/GNUmakefile b/sope-appserver/WEExtensions/GNUmakefile index 82ababbc..a441d891 100644 --- a/sope-appserver/WEExtensions/GNUmakefile +++ b/sope-appserver/WEExtensions/GNUmakefile @@ -60,6 +60,8 @@ libWEExtensions_OBJC_FILES = \ WEResourceKey.m \ WEStringTable.m \ WEStringTableManager.m \ + \ + JSStringTable.m \ libWEExtensions_SUBPROJECTS += \ WETableView diff --git a/sope-appserver/WEExtensions/JSMenu.h b/sope-appserver/WEExtensions/JSMenu.h index 19ae0213..2aab75a3 100644 --- a/sope-appserver/WEExtensions/JSMenu.h +++ b/sope-appserver/WEExtensions/JSMenu.h @@ -23,13 +23,15 @@ #define __WEExtensions_JSMenu_H__ #include -#ifdef __APPLE__ -# include -#else -# include -#endif +#include #include "JSMenuItem.h" +/* + JSMenu + + TODO: document what this does! +*/ + @class WOAssociation, WOElement; @interface JSMenu : WODynamicElement diff --git a/sope-appserver/WEExtensions/JSStringTable.api b/sope-appserver/WEExtensions/JSStringTable.api new file mode 100644 index 00000000..c9023b29 --- /dev/null +++ b/sope-appserver/WEExtensions/JSStringTable.api @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/sope-appserver/WEExtensions/JSStringTable.m b/sope-appserver/WEExtensions/JSStringTable.m new file mode 100644 index 00000000..082e299b --- /dev/null +++ b/sope-appserver/WEExtensions/JSStringTable.m @@ -0,0 +1,277 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include + +/* + JSStringTable + + Export a string table (usually a .strings file) to JavaScript. + + Note: this includes a direct action which makes all languages files + publically accessible! As far as we could see this has no security + implications. + + Note: be aware of WOResourceManager handling when using the link instead of + inplace. The element has some special support for product resource + managers, but always uses the application resource manager otherwise. +*/ + +@interface JSStringTable : WODynamicElement +{ + WOAssociation *name; + WOAssociation *identifier; + WOAssociation *framework; + WOAssociation *languages; + WOAssociation *inplace; +} + +@end + +#include +#include +#include +#include "common.h" + +@implementation JSStringTable + +- (id)initWithName:(NSString *)_name + associations:(NSDictionary *)_config + template:(WOElement *)_t +{ + if ((self = [super initWithName:_name associations:_config template:_t])) { + self->name = OWGetProperty(_config, @"name"); + self->identifier = OWGetProperty(_config, @"identifier"); + self->framework = OWGetProperty(_config, @"framework"); + self->languages = OWGetProperty(_config, @"languages"); + self->inplace = OWGetProperty(_config, @"inplace"); + } + return self; +} + +- (void)dealloc { + [self->inplace release]; + [self->identifier release]; + [self->name release]; + [self->framework release]; + [self->languages release]; + [super dealloc]; +} + +/* generate response */ + ++ (void)appendTable:(id)_table withIdentifier:(NSString *)_identifier + toResponse:(WOResponse *)_response +{ + NSEnumerator *keys; + NSString *key; + BOOL isFirst; + + if (_table == nil) { + [_response appendContentString:@""]; + return; + } + if ([_identifier length] == 0) _identifier = @"WELabels"; + + [_response appendContentString:@"var "]; + [_response appendContentString:_identifier]; + [_response appendContentString:@" = {\n"]; + + isFirst = YES; + keys = [_table keyEnumerator]; + while ((key = [keys nextObject]) != nil) { + NSString *value; + + if (isFirst) isFirst = NO; + else [_response appendContentString:@",\n"]; + + value = [_table objectForKey:key]; + + /* escape value */ + value = [value stringByReplacingString:@"\"" withString:@"\\\""]; + + [_response appendContentString:@" \""]; + [_response appendContentString:key]; + [_response appendContentString:@"\": \""]; + [_response appendContentString:value]; + [_response appendContentString:@"\""]; + } + [_response appendContentString:@"\n};\n"]; +} + +- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { + WOResourceManager *rm; + WOComponent *sComponent = [_ctx component]; + NSString *lidentifier, *lname, *lfw; + NSArray *langs; + + lname = [self->name stringValueInComponent:sComponent]; + if (![lname isNotEmpty]) lname = @"Localizable"; + + lfw = [self->framework stringValueInComponent:sComponent]; + + lidentifier = [self->identifier stringValueInComponent:sComponent]; + if (![lname isNotEmpty]) + lidentifier = [@"WELabels" stringByAppendingString:lname]; + + if (self->languages != nil) { + langs = [self->languages valueInComponent:sComponent]; + if ([langs isKindOfClass:[NSString class]]) + langs = [(NSString *)langs componentsSeparatedByString:@","]; + } + else if ([_ctx hasSession]) + langs = [[_ctx session] languages]; + else + langs = [[_ctx request] browserLanguages]; + + if ((rm = [sComponent resourceManager]) == nil) + rm = [[WOApplication application] resourceManager]; + + if ([self->inplace boolValueInComponent:sComponent]) { + /* generate table inline */ + id table; + + table = [rm stringTableWithName:lname inFramework:lfw + languages:langs]; + + if (table != nil) { + [_response appendContentString:@""]; + } + else { + [_response appendContentString: + @""]; + } + } + else { + /* generate link to table file */ + NSMutableDictionary *qd; + NSString *url; + id product = nil; + + if ([rm isKindOfClass:NSClassFromString(@"SoProductResourceManager")]) + product = [[rm valueForKey:@"container"] productName]; + + qd = [[NSDictionary alloc] initWithObjectsAndKeys: + lname ? lname : @"", @"table", + lfw ? lfw : @"", @"framework", + lidentifier ? lidentifier : @"", @"id", + product ? product : @"", @"product", + [langs componentsJoinedByString:@","], + @"languages", + nil]; + + url = [_ctx directActionURLForActionNamed:@"JSStringTableAction/default" + queryDictionary:qd]; + [qd release]; qd = nil; + + /* Note: we MUST use the app-resource manager since we cache info */ + [_response appendContentString:@""]; + } +} + +@end /* JSStringTable */ + +@interface JSStringTableAction : WODirectAction +@end + +@implementation JSStringTableAction + +static NSString *etag = nil; + +- (id)defaultAction { + WOResourceManager *rm = nil; + WORequest *rq; + WOResponse *r; + id table; + NSString *s, *lname, *lfw, *productName; + NSArray *langs; + + if (etag == nil) { + /* + Not a strictly correct etag, but should be ok. We assume that the app + needs to restart for changes to take effect and that changes are global + for all instances. + */ + char buf[32]; + sprintf(buf, "stamp_%d", ((unsigned)time(NULL) - 1121785679)); + etag = [[NSString alloc] initWithCString:buf]; + } + + rq = [[self context] request]; + r = [[self context] response]; + + productName = [rq formValueForKey:@"product"]; + if ([productName length] > 0) { + rm = [[[SoProductRegistry sharedProductRegistry] + productWithName:productName] resourceManager]; + } + if (rm == nil) + rm = [[WOApplication application] resourceManager]; + + lname = [rq formValueForKey:@"table"]; + lfw = [rq formValueForKey:@"framework"]; + langs = [[rq formValueForKey:@"languages"] componentsSeparatedByString:@","]; + + table = [rm stringTableWithName:lname inFramework:lfw languages:langs]; + if (table == nil) { + [r setStatus:404 /* Not Found */]; + [r appendContentString:@"Found no matching table"]; + + [self warnWithFormat:@"RM %@ did not find string table %@ / %@ / %@", + rm, + lname, lfw, [langs componentsJoinedByString:@","]]; + + return r; + } + + [r setHeader:@"application/x-javascript" forKey:@"content-type"]; + [r setHeader:etag forKey:@"etag"]; + + /* check preconditions */ + + s = [[[self context] request] headerForKey:@"if-none-match"]; + if ([s rangeOfString:etag].length > 0) { + /* client already has the proper entity */ + [r setStatus:304 /* Not Modified */]; + return r; + } + + /* send script */ + + [[JSStringTable class] + appendTable:table withIdentifier:[rq formValueForKey:@"id"] + toResponse:r]; + return r; +} + +@end /* JSStringTableAction */ diff --git a/sope-appserver/WEExtensions/Version b/sope-appserver/WEExtensions/Version index 43acebab..2a34764c 100644 --- a/sope-appserver/WEExtensions/Version +++ b/sope-appserver/WEExtensions/Version @@ -1,6 +1,7 @@ # version file -SUBMINOR_VERSION:=75 +SUBMINOR_VERSION:=76 +# v4.5.76 requires libNGObjWeb v4.5.176 # v4.5.75 requires libNGObjWeb v4.5.174 # v4.5.65 requires libNGObjWeb v4.5.106 diff --git a/sope-appserver/WEExtensions/WEDateField.m b/sope-appserver/WEExtensions/WEDateField.m index 6bf117e3..146fcb60 100644 --- a/sope-appserver/WEExtensions/WEDateField.m +++ b/sope-appserver/WEExtensions/WEDateField.m @@ -31,7 +31,6 @@ next.gif last.gif icon_unread.gif - */ @interface WEDateField : WECalendarField @@ -41,20 +40,16 @@ @implementation WEDateField -- (void)takeValuesFromRequest:(WORequest *)_request - inContext:(WOContext *)_ctx -{ - [self _takeValuesFromDateFieldRequest:_request inContext:_ctx]; +- (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx { + [self _takeValuesFromDateFieldRequest:_rq inContext:_ctx]; } -- (id)invokeActionForRequest:(WORequest *)_request - inContext:(WOContext *)_ctx -{ - return [self _invokeActionForDateFieldRequest:_request inContext:_ctx]; +- (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx { + return [self _invokeActionForDateFieldRequest:_rq inContext:_ctx]; } - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx { [self _appendDateFieldToResponse:_response inContext:_ctx]; } -@end +@end /* WEDateField */ diff --git a/sope-appserver/WEExtensions/WExExtElemBuilder.m b/sope-appserver/WEExtensions/WExExtElemBuilder.m index 7971590b..61f41584 100644 --- a/sope-appserver/WEExtensions/WExExtElemBuilder.m +++ b/sope-appserver/WEExtensions/WExExtElemBuilder.m @@ -32,6 +32,7 @@ maps to JSMenu maps to JSMenuItem maps to JSShiftClick + maps to JSStringTable maps to WERichString maps to WEBrowser @@ -156,15 +157,18 @@ if ([tagName hasPrefix:@"js-"]) { if (tl < 6) return Nil; - if ([tagName isEqualToString:@"js-clipboard"]) + if (tl == 12 && [tagName isEqualToString:@"js-clipboard"]) return NSClassFromString(@"JSClipboard"); - if ([tagName isEqualToString:@"js-menu"]) + if (tl == 7 && [tagName isEqualToString:@"js-menu"]) return NSClassFromString(@"JSMenu"); - if ([tagName isEqualToString:@"js-menu-item"]) + if (tl == 12 && [tagName isEqualToString:@"js-menu-item"]) return NSClassFromString(@"JSMenuItem"); - if ([tagName isEqualToString:@"js-shiftclick"]) + if (tl == 12 && [tagName isEqualToString:@"js-shiftclick"]) return NSClassFromString(@"JSShiftClick"); + + if (tl == 14 && [tagName isEqualToString:@"js-stringtable"]) + return NSClassFromString(@"JSStringTable"); } break; diff --git a/sope-appserver/WEExtensions/bundle-info.plist b/sope-appserver/WEExtensions/bundle-info.plist index a149a110..aef9fadb 100644 --- a/sope-appserver/WEExtensions/bundle-info.plist +++ b/sope-appserver/WEExtensions/bundle-info.plist @@ -1,6 +1,4 @@ { - CVSID = "$Id$"; - requires = { bundleManagerVersion = 1; @@ -20,6 +18,7 @@ { name = "JSClipboard"; }, { name = "WEQualifierCondition"; }, { name = "WERedirect"; }, + { name = "JSStringTable"; }, ); classes = ( -- 2.39.5