webconfig
Main package containing all neccesarry functions
See Also
settings.aliases for shorter UDAs
Examples
enum FavoriteFood
{
// enum UDAs require at least dmd 2.082.0
//dfmt off
@settingTranslation(null, "Fish") @settingTranslation("de", "Fisch") @settingTranslation("ja", "魚")
fish,
@settingTranslation(null, "Meat") @settingTranslation("de", "Fleisch") @settingTranslation("ja", "肉")
meat,
@settingTranslation(null, "Vegetables") @settingTranslation("de", "Gemüse") @settingTranslation("ja", "野菜")
vegetables,
@settingTranslation(null, "Fruits") @settingTranslation("de", "Obst") @settingTranslation("ja", "フルーツ")
fruit
//dfmt on
}
//dfmt off
enum Country
{
none, AF, AX, AL, DZ, AS, AD, AO, AI, AQ, AG, AR, AM, AW, AC, AU, AT, AZ, BS, BH, BD, BB, BY, BE, BZ, BJ, BM,
BT, BO, BA, BW, BR, IO, VG, BN, BG, BF, BI, KH, CM, CA, IC, CV, BQ, KY, CF, EA, TD, CL, CN, CX, CC, CO, KM,
CG, CD, CK, CR, CI, HR, CU, CW, CY, CZ, DK, DG, DJ, DM, DO, EC, EG, SV, GQ, ER, EE, ET, FK, FO, FJ, FI, FR,
GF, PF, TF, GA, GM, GE, DE, GH, GI, GR, GL, GD, GP, GU, GT, GG, GN, GW, GY, HT, HN, HK, HU, IS, IN, ID, IR,
IQ, IE, IM, IL, IT, JM, JP, JE, JO, KZ, KE, KI, XK, KW, KG, LA, LV, LB, LS, LR, LY, LI, LT, LU, MO, MK, MG,
MW, MY, MV, ML, MT, MH, MQ, MR, MU, YT, MX, FM, MD, MC, MN, ME, MS, MA, MZ, MM, NA, NR, NP, NL, NC, NZ, NI,
NE, NG, NU, NF, KP, MP, NO, OM, PK, PW, PS, PA, PG, PY, PE, PH, PN, PL, PT, PR, QA, RE, RO, RU, RW, WS, SM,
ST, SA, SN, RS, SC, SL, SG, SX, SK, SI, SB, SO, ZA, GS, KR, SS, ES, LK, BL, SH, KN, LC, MF, PM, VC, SD, SR,
SJ, SZ, SE, CH, SY, TW, TJ, TZ, TH, TL, TG, TK, TO, TT, TA, TN, TR, TM, TC, TV, UM, VI, UG, UA, AE, GB, US,
UY, UZ, VU, VA, VE, VN, WF, EH, YE, ZM, ZW
}
//dfmt on
enum SocialMedia
{
twitter = 1 << 0,
facebook = 1 << 1,
myspace = 1 << 2,
}
struct Config
{
@requiredSetting // Must be filled out
@nonAutomaticSetting // Don't auto sync when typing
@emailSetting @settingPlaceholder("you@example.com") string userEmail;
bool married;
@urlSetting @settingLength(64) string resourceURI;
// OR
@settingLength(64) URL myWebsite;
@multilineSetting @settingLength(1000) string aboutMe;
@rangeSetting @settingRange(0, 10) int rating;
@timeSetting string favoriteTimeOfDay;
// OR
TimeOfDay leastFavoriteTimeOfDay;
@weekSetting string bestWeekYouHad;
@monthSetting string firstMonthOfWork;
// Timezone-less
@datetimeLocalSetting string birthdayTimeAndDate;
// OR
DateTime myChildsBirthdayTimeAndDate;
@dateSetting string myMothersBirthday;
// OR
Date myFathersBirthday;
// inserts some html before some element
@settingHTML("<hr/><p>Some cooler information now follows.</p>")
@colorSetting @settingClass("wide") string favoriteColor;
@disabledSetting string someInformation = "Just a hint, nothing changable";
Country favoriteCountry;
@settingTranslation("de", "Lieblingsessen") // Translation of labels (only in translation contexts inside web interfaces)
@settingTranslation("ja", "好きな食べ物") // translations require at least vibe.d 0.8.1-alpha.3 to work
@optionsSetting FavoriteFood favoriteFood;
BitFlags!SocialMedia usedSocialMedia;
@settingTitle("If you don't have any you can still say 1 because you have yourself.") // Hover & validation text
@settingMin(1) int numberOfFriends;
@settingRange(0, 100) @settingStep(0.1) double englishSkillLevelPercentage;
@settingMax(10) ubyte orderedProductCount;
@settingLabel("Accept terms of service") @requiredSetting bool acceptTOS;
@settingPattern(`(ISBN\s+)?\d{3}-\d-\d{5}-\d{3}-\d`) string favoriteBookISBN;
@settingRows(8) string[] someStrings;
}
import vibe.vibe;
auto router = new URLRouter;
router.get("/style.css", serveStaticFile("styles/material.css"));
router.get("/", staticRedirect("/settings"));
enum html = `<html>
<head>
<title>Settings</title>
<meta charset="utf-8"/>
<link rel="stylesheet" href="/style.css"/>
<style>
body,html{background:#efefef;color:rgba(0,0,0,0.87);font-family:Roboto,"Segoe UI",sans-serif;}
.settings{background:white;border-radius:2px;padding:16px;margin:32px auto;box-shadow:0 2px 5px rgba(0,0,0,0.3);max-width:600px;}
</style>
</head>
<body>
<div class="settings">
<h2>Settings</h2>
%s
</div>
</body>
</html>`;
struct TranslationContext
{
import std.meta;
alias languages = AliasSeq!("en", "de", "ja");
}
Config settingsInstance; // You might fetch & save this per user, web-config only changes the struct
@translationContext!TranslationContext class SettingsInterface
{
@safe void getSettings(scope HTTPServerRequest req, scope HTTPServerResponse res)
{
string settings = renderSettings(settingsInstance);
res.writeBody(html.format(settings), "text/html");
}
@safe void postSettings(scope HTTPServerRequest req, scope HTTPServerResponse res)
{
// no-js & nonautomatic setting route
auto ret = req.processSettings(settingsInstance);
string settings = renderSettings(settingsInstance, ret);
if (ret)
{
// Something changed, you can save here
}
res.writeBody(html.format(settings), "text/html");
}
@path("/api/setting") @safe void postJsSettings(scope HTTPServerRequest req,
scope HTTPServerResponse res)
{
// js route called for each individual setting
if (req.processSettings(settingsInstance))
{
// Save settings
res.writeBody("", 204); // Send 200 or 204
}
else
res.writeBody("", HTTPStatus.badRequest);
}
}
router.registerWebInterface(new SettingsInterface);
auto httpSettings = new HTTPServerSettings;
httpSettings.port = 8080;
listenHTTP(httpSettings, router);
runApplication();
-
Declaration
@safe stringrenderSettings(T, InputGenerator = DefaultInputGenerator, string javascript = DefaultJavascriptCode)(Tvalue, stringformAttributes= "", stringaction= "/settings", stringmethod= "POST", stringjsAction= "/api/setting");
@safe stringrenderSettings(T, InputGenerator = DefaultInputGenerator, string javascript = DefaultJavascriptCode)(Tvalue, ulongset, stringformAttributes= "", stringaction= "/settings", stringmethod= "POST", stringjsAction= "/api/setting");Generates a HTML form for a configuration struct
Twith automatic instant updates using AJAX. The fields can be annotated with the various UDAs found in this module. (setting enums + structs)
Supported types:enum(drop down lists or radio box lists),std.typecons.BitFlags(checkbox lists),bool(checkbox), string types (text, email, url, etc.), numeric types (number),std.datetime.DateTime(datetime-local),std.datetime.Date(date),std.datetime.TimeOfDay(time),vibe.inet.URL(url),string[](textarea taking each line)Parameters
Tthe config struct type.
InputGeneratorthe input generator to use.
javascriptthe javascript code to embed including script tag.
Tvaluean existing config
valueto prefill the inputs.ulongseta bitflag field which settings have been
setproperly. Any bitsetto 0 will show an error string for the given field. Defaults to all success.stringformAttributesextra HTML to put into the form.
stringactionPath to the form submit HTTP endpoint.
stringmethodMethod to use for the submit HTTP endpoint. Also replaces {
method} inside the javascript template.stringjsActionPath to the javascript form submit HTTP endpoint. Replaces {
action} inside the javascript template. If empty then no js will be emitted. -
Declaration
@safe stringrenderSetting(InputGenerator = DefaultInputGenerator, string name, Config)(ref Configconfig, boolsuccess= true);Generates a single input
-
Declaration
@safe ulongprocessSettings(T)(scope HTTPServerRequestreq, ref Tconfig, boolstrict= false, boolpost= true);
@safe boolprocessSetting(string name, Config)(HTTPServerRequestreq, ref Configconfig, boolstrict= false, boolpost= true);Function processing user input and validating for correctness.
The following validations are done:
If the setting is adisabledSetting, it will always skip this field.
If the setting has asettingPattern, it will validate the raw value (no matter what type) against this regex.
If the setting is a number, std.conv.to will be used to try to convert it to a double and then it will be cast to the type after checking min/max/step.
If the setting is aBitFlags!Tevery passed argument will be checked if it is contained inside the enumTor when submitted via JS only the one specified argument will get validated and inverted if starting with!
If the setting is an enum the value will be checked if it is contained inside the enum.
Additionally if the setting is a floating point number and there hasn't been a min/max setup but it is arangeSetting, the number will be finite.
Integral numbers will always be checked if finite & if no range is given they will be clamped.
Attributes for strings:
emailSettingis validated usingstd.net.isemail.isEmail(CheckDns.no, EmailStatusCode.any)
urlSettingis validated usingvibe.inet.url.URL
timeSettingis checked against pattern00:00+ checking if 0 <= hour < 24 && 0 <= minute < 60
weekSettingis checked against pattern0{4,6}-W00+ checking if 1 <= year <= 200000 && 1 <= week <= 52
monthSettingis checked against pattern0{4,6}-00+ checking if 1 <= year <= 200000 && 1 <= month <= 12
datetimeLocalSettingis checked against pattern0000-00-00T00:00+ passing intostd.datetime.SysTime.fromISOExtString`
dateSettingis checked against pattern0000-00-00+ checking the date usingstd.datetime.Date
colorSettingis checked against pattern#FFFFFF
Values using these attributes can be used without the need to validate the input.Parameters
boolstrictif
false, values will be fixed to conform to the input instead of discarding them. Currently only fixing numbers and string lengths and new lines in single line strings is implemented.Return Value
a bit array where each bit represents an input and is set to 1 if valid
-
Declaration
@safe boolvalidateTimeString(strings);Validates
s== pattern "00:00" -
Declaration
@safe boolvalidateWeekString(strings);Validates
s== pattern "0{4,6}-W00" -
Declaration
@safe boolvalidateMonthString(strings);Validates
s== pattern "0{4,6}-00" -
Declaration
@safe boolvalidateDatetimeLocalString(strings);Validates
s== pattern "0000-00-00T00:00" -
Declaration
@safe boolvalidateDateString(strings);Validates
s== pattern "0000-00-00" -
Declaration
@safe boolvalidateColorString(strings);Validates
s== pattern "#xxxxxx" -
Declaration
@safe stringmakeHumanName(stringidentifier);Converts correctBookISBN_number to "Correct Book ISBN Number"
-
Declaration
structDefaultInputGenerator;Controls how the input HTML is generated
-
Declaration
static @safe stringtextfield(stringname, stringtype, stringvalue, stringraw, boolsuccess, string[]classes);Called for single line input types
-
Declaration
static @safe stringtextarea(stringname, stringvalue, stringraw, boolsuccess, string[]classes);Called for textareas
-
Declaration
static @safe stringcheckbox(stringname, boolchecked, stringraw, boolsuccess, string[]classes);Called for boolean values
-
Declaration
stringdropdownList(Enum, translations...)(stringname, Enumvalue, stringraw, boolsuccess, string[]classes);Called for enums disabled as select (you need to iterate over the enum members)
-
Declaration
stringoptionList(Enum, translations...)(stringname, Enumvalue, stringraw, boolsuccess, string[]classes);Called for enums displayed as list of radio boxes (you need to iterate over the enum members)
-
Declaration
stringcheckboxList(Enum, translations...)(stringname, BitFlags!Enumvalue, stringraw, boolsuccess, string[]classes);Called for BitFlags displayed as list of checkboxes.
-
-
Declaration
enumemailSetting;Adds type="email" to string types
-
Declaration
enumurlSetting;Adds type="url" to string types
-
Declaration
enumpasswordSetting;Adds type="password" to string types
-
Declaration
enummultilineSetting;Makes string types textareas
-
Declaration
enumrangeSetting;Adds type="range" to numeric types
-
Declaration
enumtimeSetting;Adds type="time" to string types
-
Declaration
enumweekSetting;Adds type="week" to string types
-
Declaration
enummonthSetting;Adds type="month" to string types
-
Declaration
enumdatetimeLocalSetting;Adds type="datetime-local" to string types
-
Declaration
enumdateSetting;Adds type="date" to string types
-
Declaration
enumcolorSetting;Adds type="color" to string types
-
Declaration
enumdisabledSetting;Adds disabled to any input
-
Declaration
enumrequiredSetting;Adds required to any input
-
Declaration
enumnonAutomaticSetting;Disables automatic JS saving when changing the input
-
Declaration
enumoptionsSetting;Changes a dropdown to a radio button list
-
Declaration
structsettingMin;Changes the min="" attribute for numerical values
-
Declaration
doublemin;
-
-
Declaration
structsettingMax;Changes the max="" attribute for numerical values
-
Declaration
doublemax;
-
-
Declaration
structsettingStep;Changes the step="" attribute for numerical values
-
Declaration
doublestep;
-
-
Declaration
structsettingRange; -
Declaration
structsettingLength; -
Declaration
structsettingPattern;Changes the pattern="regex" attribute
-
Declaration
stringregex;
-
-
Declaration
structsettingTitle;Changes the title="" attribute for custom error messages & tooltips
-
Declaration
stringtitle;
-
-
Declaration
structsettingLabel;Overrides the label of the input
-
Declaration
stringlabel;
-
-
Declaration
structsettingRows;Sets the number of rows of a textarea
-
Declaration
intcount;
-
-
Declaration
structsettingTranslation; -
Declaration
structenumTranslation;Relables all enum member names for a language. Give
nullas first argument to change the default language-
Declaration
stringlanguage; -
Declaration
string[]translations;
-
-
Declaration
structsettingHTML;Inserts raw HTML code before an element.
-
Declaration
stringraw;
-
-
Declaration
structsettingClass;Inserts raw CSS class name for an element.
-
Declaration
stringclassName;
-
-
Declaration
structformTemplate;Changes how the form HTML template looks
-
Declaration
stringcode;Contains the std.format formattable template
code.
Arguments in order are: string action, string method, string formArguments, string html
html is last so you can embed it using %4$s without throwing an orphan arguments exception.
-
-
Declaration
structsettingPlaceholder;Sets the placeholder attribute for elements that support it
-
Declaration
stringplaceholder;
-
-
Declaration
enum stringDefaultJavascriptCode;Contains a updateSetting(input) function which automatically sends changes to the server.