settings

Main package containing all neccesarry functions

Modules

aliases
module settings.aliases

Members

Enums

colorSetting
enum colorSetting

Adds type="color" to string types

dateSetting
enum dateSetting

Adds type="date" to string types

datetimeLocalSetting
enum datetimeLocalSetting

Adds type="datetime-local" to string types

disabledSetting
enum disabledSetting

Adds disabled to any input

emailSetting
enum emailSetting

Adds type="email" to string types

monthSetting
enum monthSetting

Adds type="month" to string types

multilineSetting
enum multilineSetting

Makes string types textareas

nonAutomaticSetting
enum nonAutomaticSetting

Disables automatic JS saving when changing the input

optionsSetting
enum optionsSetting

Changes a dropdown to a radio button list

rangeSetting
enum rangeSetting

Adds type="range" to numeric types

requiredSetting
enum requiredSetting

Adds required to any input

timeSetting
enum timeSetting

Adds type="time" to string types

urlSetting
enum urlSetting

Adds type="url" to string types

weekSetting
enum weekSetting

Adds type="week" to string types

Functions

makeHumanName
string makeHumanName(string identifier)

Converts correctBookISBN_number to "Correct Book ISBN Number"

processSetting
bool processSetting(HTTPServerRequest req, ref Config config, bool strict = false, bool post = true)

Function processing user input and validating for correctness.

The following validations are done:
If the setting is a disabledSetting, it will always skip this field.
If the setting has a settingPattern, 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 a BitFlags!T every passed argument will be checked if it is contained inside the enum T or 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 a rangeSetting, 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:
emailSetting is validated using std.net.isemail.isEmail(CheckDns.no, EmailStatusCode.any)
urlSetting is validated using vibe.inet.url.URL
timeSetting is checked against pattern 00:00 + checking if 0 <= hour < 24 && 0 <= minute < 60
weekSetting is checked against pattern 0{4,6}-W00 + checking if 1 <= year <= 200000 && 1 <= week <= 52
monthSetting is checked against pattern 0{4,6}-00 + checking if 1 <= year <= 200000 && 1 <= month <= 12
datetimeLocalSetting is checked against pattern 0000-00-00T00:00 + passing into std.datetime.SysTime.fromISOExtString`
dateSetting is checked against pattern 0000-00-00 + checking the date using std.datetime.Date
colorSetting is checked against pattern #FFFFFF
Values using these attributes can be used without the need to validate the input.

processSettings
ulong processSettings(scope HTTPServerRequest req, ref T config, bool strict = false, bool post = true)

Function processing user input and validating for correctness.

The following validations are done:
If the setting is a disabledSetting, it will always skip this field.
If the setting has a settingPattern, 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 a BitFlags!T every passed argument will be checked if it is contained inside the enum T or 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 a rangeSetting, 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:
emailSetting is validated using std.net.isemail.isEmail(CheckDns.no, EmailStatusCode.any)
urlSetting is validated using vibe.inet.url.URL
timeSetting is checked against pattern 00:00 + checking if 0 <= hour < 24 && 0 <= minute < 60
weekSetting is checked against pattern 0{4,6}-W00 + checking if 1 <= year <= 200000 && 1 <= week <= 52
monthSetting is checked against pattern 0{4,6}-00 + checking if 1 <= year <= 200000 && 1 <= month <= 12
datetimeLocalSetting is checked against pattern 0000-00-00T00:00 + passing into std.datetime.SysTime.fromISOExtString`
dateSetting is checked against pattern 0000-00-00 + checking the date using std.datetime.Date
colorSetting is checked against pattern #FFFFFF
Values using these attributes can be used without the need to validate the input.

renderSetting
string renderSetting(ref Config config, bool success = true)

Generates a single input

renderSettings
string renderSettings(T value, string formAttributes = "", string action = "/settings", string method = "POST", string jsAction = "/api/setting")
string renderSettings(T value, ulong set, string formAttributes = "", string action = "/settings", string method = "POST", string jsAction = "/api/setting")

Generates a HTML form for a configuration struct T with 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)

validateColorString
bool validateColorString(string s)

Validates s == pattern "#xxxxxx"

validateDateString
bool validateDateString(string s)

Validates s == pattern "0000-00-00"

validateDatetimeLocalString
bool validateDatetimeLocalString(string s)

Validates s == pattern "0000-00-00T00:00"

validateMonthString
bool validateMonthString(string s)

Validates s == pattern "0{4,6}-00"

validateTimeString
bool validateTimeString(string s)

Validates s == pattern "00:00"

validateWeekString
bool validateWeekString(string s)

Validates s == pattern "0{4,6}-W00"

Manifest constants

DefaultJavascriptCode
enum DefaultJavascriptCode;

Contains a updateSetting(input) function which automatically sends changes to the server.

Structs

DefaultInputGenerator
struct DefaultInputGenerator

Controls how the input HTML is generated

enumTranslation
struct enumTranslation

Relables all enum member names for a language. Give null as first argument to change the default language

settingLabel
struct settingLabel

Overrides the label of the input

settingLength
struct settingLength

Changes the minlength="" and maxlength="" attribute for string values

settingMax
struct settingMax

Changes the max="" attribute for numerical values

settingMin
struct settingMin

Changes the min="" attribute for numerical values

settingPattern
struct settingPattern

Changes the pattern="regex" attribute

settingRange
struct settingRange

Changes the min="" and max="" attribute for numerical values

settingStep
struct settingStep

Changes the step="" attribute for numerical values

settingTitle
struct settingTitle

Changes the title="" attribute for custom error messages & tooltips

settingTranslation
struct settingTranslation

Changes the label if the current language (using a WebInterface translation context) matches the given one. You need at least vibe-d v0.8.1-alpha.3 to use this UDA.

Examples

1 enum FavoriteFood
2 {
3 	fish,
4 	meat,
5 	vegetables,
6 	fruit
7 }
8 
9 //dfmt off
10 enum Country
11 {
12 	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,
13 	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,
14 	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,
15 	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,
16 	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,
17 	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,
18 	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,
19 	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,
20 	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,
21 	UY, UZ, VU, VA, VE, VN, WF, EH, YE, ZM, ZW
22 }
23 //dfmt on
24 
25 enum SocialMedia
26 {
27 	twitter = 1 << 0,
28 	facebook = 1 << 1,
29 	myspace = 1 << 2,
30 }
31 
32 struct Config
33 {
34 	@requiredSetting // Must be filled out
35 	@nonAutomaticSetting // Don't auto sync when typing
36 	@emailSetting string userEmail;
37 	bool married;
38 	@urlSetting @settingLength(64) string resourceURI;
39 	// OR
40 	@settingLength(64) URL myWebsite;
41 	@multilineSetting @settingLength(1000) string aboutMe;
42 	@rangeSetting @settingRange(0, 10) int rating;
43 	@timeSetting string favoriteTimeOfDay;
44 	// OR
45 	TimeOfDay leastFavoriteTimeOfDay;
46 	@weekSetting string bestWeekYouHad;
47 	@monthSetting string firstMonthOfWork;
48 	// Timezone-less
49 	@datetimeLocalSetting string birthdayTimeAndDate;
50 	// OR
51 	DateTime myChildsBirthdayTimeAndDate;
52 	@dateSetting string myMothersBirthday;
53 	// OR
54 	Date myFathersBirthday;
55 	@colorSetting string favoriteColor;
56 	@disabledSetting string someInformation = "Just a hint, nothing changable";
57 	Country favoriteCountry;
58 	@settingTranslation("de", "Lieblingsessen")  // Translation of labels (only in translation contexts inside web interfaces)
59 	@settingTranslation("ja", "好きな食べ物")  // translations require at least vibe.d 0.8.1-alpha.3 to work
60 	@enumTranslation(null, ["Fish", "Meat", "Vegetables", "Fruits"])
61 	@enumTranslation("de", ["Fisch", "Fleisch", "Gemüse", "Obst"])
62 	@enumTranslation("ja", ["魚", "肉", "野菜", "フルーツ"])
63 	@optionsSetting FavoriteFood favoriteFood;
64 	BitFlags!SocialMedia usedSocialMedia;
65 	@settingTitle("If you don't have any you can still say 1 because you have yourself.")  // Hover & validation text
66 	@settingMin(1) int numberOfFriends;
67 	@settingRange(0, 100) @settingStep(0.1) double englishSkillLevelPercentage;
68 	@settingMax(10) ubyte orderedProductCount;
69 	@settingLabel("Accept terms of service") @requiredSetting bool acceptTOS;
70 	@settingPattern(`(ISBN\s+)?\d{3}-\d-\d{5}-\d{3}-\d`) string favoriteBookISBN;
71 }
72 
73 import vibe.vibe;
74 
75 auto router = new URLRouter;
76 router.get("/style.css", serveStaticFile("styles/material.css"));
77 router.get("/", staticRedirect("/settings"));
78 
79 enum html = `<html>
80 	<head>
81 		<title>Settings</title>
82 		<meta charset="utf-8"/>
83 		<link rel="stylesheet" href="/style.css"/>
84 		<style>
85 			body,html{background:#efefef;color:rgba(0,0,0,0.87);font-family:Roboto,"Segoe UI",sans-serif;}
86 			.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;}
87 		</style>
88 	</head>
89 	<body>
90 		<div class="settings">
91 			<h2>Settings</h2>
92 			%s
93 		</div>
94 	</body>
95 </html>`;
96 
97 struct TranslationContext
98 {
99 	import std.meta;
100 
101 	alias languages = AliasSeq!("en", "de", "ja");
102 }
103 
104 Config settingsInstance; // You might fetch & save this per user, web-config only changes the struct
105 
106 @translationContext!TranslationContext class SettingsInterface
107 {
108 	@safe void getSettings(scope HTTPServerRequest req, scope HTTPServerResponse res)
109 	{
110 		string settings = renderSettings(settingsInstance);
111 		res.writeBody(html.format(settings), "text/html");
112 	}
113 
114 	@safe void postSettings(scope HTTPServerRequest req, scope HTTPServerResponse res)
115 	{
116 		// no-js & nonautomatic setting route
117 		auto ret = req.processSettings(settingsInstance);
118 		string settings = renderSettings(settingsInstance, ret);
119 		if (ret)
120 		{
121 			// Something changed, you can save here
122 		}
123 		res.writeBody(html.format(settings), "text/html");
124 	}
125 
126 	@path("/api/settings") @safe void postJsSettings(scope HTTPServerRequest req,
127 			scope HTTPServerResponse res)
128 	{
129 		// js route called for each individual setting
130 		if (req.processSettings(settingsInstance))
131 		{
132 			// Save settings
133 			res.writeBody("", 204); // Send 200 or 204
134 		}
135 		else
136 			res.writeBody("", HTTPStatus.badRequest);
137 	}

See Also

<a href="aliases.html">settings.aliases</a> for shorter UDAs

Meta