more template functions

This commit is contained in:
Adam D. Ruppe 2012-11-18 23:30:18 -05:00
parent 86062de07b
commit c1af333c6b
1 changed files with 94 additions and 17 deletions

111
web.d
View File

@ -2298,7 +2298,7 @@ WrapperFunction generateWrapper(alias ObjectType, string funName, alias f, R)(Re
// find it in reflection // find it in reflection
ofInterest ~= reflection.functions[callingName]. ofInterest ~= reflection.functions[callingName].
dispatcher(cgi, null, decodeVariables(callingArguments), "string", null).value.str; dispatcher(cgi, object, decodeVariables(callingArguments), "string", null).value.str;
} }
} }
@ -2379,6 +2379,9 @@ string formatAs(T, R)(T ret, string format, R api = null, JSONValue* returnValue
returnValue.str = retstr; returnValue.str = retstr;
break; break;
case "string": // FIXME: this is the most expensive part of the compile! Two seconds in one of my apps. case "string": // FIXME: this is the most expensive part of the compile! Two seconds in one of my apps.
static if(is(typeof(ret) == string))
returnValue.str = ret;
else
/+ /+
static if(__traits(compiles, to!string(ret))) { static if(__traits(compiles, to!string(ret))) {
retstr = to!string(ret); retstr = to!string(ret);
@ -2990,6 +2993,10 @@ immutable(string[]) weekdayNames = [
// this might be temporary // this might be temporary
struct TemplateFilters { struct TemplateFilters {
// arguments:
// args (space separated on pipe), context element, attribute name (if we're in an attribute)
// string (string replacement, string[], in Element, string)
string date(string replacement, string[], in Element, string) { string date(string replacement, string[], in Element, string) {
auto dateTicks = to!time_t(replacement); auto dateTicks = to!time_t(replacement);
auto date = SysTime( unixTimeToStdTime(dateTicks/1_000) ); auto date = SysTime( unixTimeToStdTime(dateTicks/1_000) );
@ -3010,16 +3017,61 @@ struct TemplateFilters {
return toJson(replacement); return toJson(replacement);
} }
string article(string replacement, string[], in Element, string) {
if(replacement.length && replacement[0].isVowel())
return "an " ~ replacement;
else if(replacement.length)
return "a " ~ replacement;
return replacement;
}
string capitalize(string replacement, string[], in Element, string) {
return std.string.capitalize(replacement);
}
string possessive(string replacement, string[], in Element, string) {
if(replacement.length && replacement[$ - 1] == 's')
return replacement ~ "'";
else if(replacement.length)
return replacement ~ "'s";
else
return replacement;
}
string plural(string replacement, string[] args, in Element, string) {
if(replacement.length == 0)
return replacement;
int count = 0;
if(args.length && std.string.isNumeric(args[0]))
count = to!int(args[0]);
if(count == 1)
return replacement; // it isn't actually plural
switch(replacement[$ - 1]) {
case 's':
case 'a', 'e', 'i', 'o', 'u':
return replacement ~ "es";
case 'f':
return replacement[0 .. $-1] ~ "ves";
default:
return replacement ~ "s";
}
}
static auto defaultThings() { static auto defaultThings() {
string delegate(string, string[], in Element, string)[string] pipeFunctions; string delegate(string, string[], in Element, string)[string] pipeFunctions;
TemplateFilters filters; TemplateFilters filters;
if("date" !in pipeFunctions) string delegate(string, string[], in Element, string) tmp;
pipeFunctions["date"] = &filters.date; foreach(member; __traits(allMembers, TemplateFilters)) {
if("uri" !in pipeFunctions) static if(__traits(compiles, tmp = &__traits(getMember, filters, member))) {
pipeFunctions["uri"] = &filters.uri; if(member !in pipeFunctions)
if("js" !in pipeFunctions) pipeFunctions[member] = &__traits(getMember, filters, member);
pipeFunctions["js"] = &filters.js; }
}
return pipeFunctions; return pipeFunctions;
} }
} }
@ -3035,14 +3087,14 @@ void applyTemplateToElement(
auto tc = cast(TextNode) ele; auto tc = cast(TextNode) ele;
if(tc !is null) { if(tc !is null) {
// text nodes have no attributes, but they do have text we might replace. // text nodes have no attributes, but they do have text we might replace.
tc.contents = htmlTemplateWithData(tc.contents, vars, pipeFunctions, false); tc.contents = htmlTemplateWithData(tc.contents, vars, pipeFunctions, false, tc, null);
} else { } else {
auto rs = cast(RawSource) ele; auto rs = cast(RawSource) ele;
if(rs !is null) { if(rs !is null) {
bool isSpecial; bool isSpecial;
if(ele.parentNode) if(ele.parentNode)
isSpecial = ele.parentNode.tagName == "script" || ele.parentNode.tagName == "style"; isSpecial = ele.parentNode.tagName == "script" || ele.parentNode.tagName == "style";
rs.source = htmlTemplateWithData(rs.source, vars, pipeFunctions, !isSpecial); /* FIXME: might be wrong... */ rs.source = htmlTemplateWithData(rs.source, vars, pipeFunctions, !isSpecial, rs, null); /* FIXME: might be wrong... */
} }
// if it is not a text node, it has no text where templating is valid, except the attributes // if it is not a text node, it has no text where templating is valid, except the attributes
// note: text nodes have no attributes, which is why this is in the separate branch. // note: text nodes have no attributes, which is why this is in the separate branch.
@ -3052,7 +3104,7 @@ void applyTemplateToElement(
v = v.replace("%7B%24", "{$"); v = v.replace("%7B%24", "{$");
v = v.replace("%7D", "}"); v = v.replace("%7D", "}");
} }
ele.attributes[k] = htmlTemplateWithData(v, vars, pipeFunctions, false); ele.attributes[k] = htmlTemplateWithData(v, vars, pipeFunctions, false, ele, k);
} }
} }
} }
@ -3062,7 +3114,7 @@ void applyTemplateToElement(
// set useHtml to false if you're working on internal data (such as TextNode.contents, or attribute); // set useHtml to false if you're working on internal data (such as TextNode.contents, or attribute);
// it should only be set to true if you're doing input that has already been ran through toString or something. // it should only be set to true if you're doing input that has already been ran through toString or something.
// NOTE: I'm probably going to change the pipe function thing a bit more, but I'm basically happy with it now. // NOTE: I'm probably going to change the pipe function thing a bit more, but I'm basically happy with it now.
string htmlTemplateWithData(in string text, in string[string] vars, in string delegate(string, string[], in Element, string)[string] pipeFunctions, bool useHtml) { string htmlTemplateWithData(in string text, in string[string] vars, in string delegate(string, string[], in Element, string)[string] pipeFunctions, bool useHtml, Element contextElement = null, string contextAttribute = null) {
if(text is null) if(text is null)
return null; return null;
@ -3088,10 +3140,12 @@ string htmlTemplateWithData(in string text, in string[string] vars, in string de
nameStart = i + 1; nameStart = i + 1;
auto it = name in vars; if(!replacementPresent) {
if(it !is null) { auto it = name in vars;
replacement = *it; if(it !is null) {
replacementPresent = true; replacement = *it;
replacementPresent = true;
}
} }
} }
@ -3099,8 +3153,21 @@ string htmlTemplateWithData(in string text, in string[string] vars, in string de
if(currentPipe is null || replacement is null) if(currentPipe is null || replacement is null)
return; return;
if(currentPipe in pipeFunctions) { auto pieces = currentPipe.split(" ");
replacement = pipeFunctions[currentPipe](replacement, null, null, null); // FIXME context assert(pieces.length);
auto pipeName = pieces[0];
auto pipeArgs = pieces[1 ..$];
foreach(ref arg; pipeArgs) {
if(arg.length && arg[0] == '$') {
string n = arg[1 .. $];
if(n in vars)
arg = vars[n];
}
}
if(pipeName in pipeFunctions) {
replacement = pipeFunctions[pipeName](replacement, pipeArgs, contextElement, contextAttribute);
// string, string[], in Element, string // string, string[], in Element, string
} }
@ -3552,6 +3619,16 @@ string makeJavascriptApi(const ReflectionInfo* mod, string base, bool isNested =
return script; return script;
} }
bool isVowel(char c) {
return (
c == 'a' || c == 'A' ||
c == 'e' || c == 'E' ||
c == 'i' || c == 'I' ||
c == 'o' || c == 'O' ||
c == 'u' || c == 'U'
);
}
debug string javascriptBase = ` debug string javascriptBase = `
// change this in your script to get fewer error popups // change this in your script to get fewer error popups