Profiles / Programming
SU

Screen & UI developer (sajax)

Build the screens of MentDB web apps in MQL: Bootstrap grids, forms and every control, ajax buttons, alerts, refreshes and charts.

10 recipes on this page · open in the interactive view

Recipes
  1. Bootstrap page skeleton with an onload call
  2. A remote script behind a page button
  3. Inline contact form with text, mail, tel, textarea and hidden fields
  4. Modal booking form with date, datetime, time and number pickers
  5. Preferences form with color, range, password and file upload
  6. Article editor with CKEditor and a category select
  7. Filter panel with checkboxes, radios and a multiple select
  8. Approve button: refresh, alert and JavaScript from one action
  9. Clickable table rows and a Reload button
  10. Sales dashboard: KPI cards, bar chart, gauge and sparkline
executed on MentDB

Bootstrap page skeleton with an onload call

Lay out a sales dashboard page: a container, two rows, a title column with custom HTML and two empty columns that a script fills after the load. The script checks the generated grid and decodes the onload call.

Pipeline
Script
admin
#1. The page HTML is built in [page] by the skeleton helpers;
-> "[page]" "";
-> "[on_load_functions]" "";
include "app.100.obj.sajax.skeleton.container.exe" "[id]" "sales" "[name]" "" "[class]" "" "[style]" "";
	include "app.100.obj.sajax.skeleton.row.exe" "[id]" "" "[name]" "" "[class]" "" "[style]" "";
		include "app.100.obj.sajax.skeleton.col.exe" "[id]" "sales_title" "[name]" "" "[class]" "col-12" "[style]" "";
			#Custom HTML inside a column;
			concat_var "[page]" "<h3>Sales <small>" (date curdate) "</small></h3>";
		include "app.100.obj.sajax.skeleton.div.end.exe";
	include "app.100.obj.sajax.skeleton.div.end.exe";
	include "app.100.obj.sajax.skeleton.row.exe" "[id]" "" "[name]" "" "[class]" "" "[style]" "margin-top:8px";
		include "app.100.obj.sajax.skeleton.col.exe" "[id]" "sales_kpi" "[name]" "" "[class]" "col-12 col-lg-8" "[style]" ""; include "app.100.obj.sajax.skeleton.div.end.exe";
		include "app.100.obj.sajax.skeleton.col.exe" "[id]" "sales_gauge" "[name]" "" "[class]" "col-12 col-lg-4" "[style]" ""; include "app.100.obj.sajax.skeleton.div.end.exe";
	include "app.100.obj.sajax.skeleton.div.end.exe";
include "app.100.obj.sajax.skeleton.div.end.exe";
#2. After the load, the browser runs the script that fills the empty columns, client_data is a JS expression;
include "app.100.obj.sajax.skeleton.onload.exe"
	"[scriptname]" "tuto.p4k.sales.onload.exe"
	"[client_data]" "({\"region\": \"North\"})"
;
#3. Check the HTML: balanced divs, the ids of the empty targets, the decoded onload call;
-> "[open]" (string regexp_count [page] "<div");
-> "[close]" (string regexp_count [page] "</div>");
-> "[call_script]" (string decode_b64 (string regexp_extract [on_load_functions] "execute_script\('([^']+)'" 1));
-> "[call_data]" (string decode_b64 (string regexp_extract [on_load_functions] ", '([^']+)'\);" 1));
concat [page] [_n_] "divs: " [open] " open / " [close] " closed" [_n_] "onload: " [on_load_functions] [_n_] "runs " [call_script] " with " [call_data];
Result
mentdb
<div id='sales' class='container-fluid'><div class='row'><div id='sales_title' class='col-12'><h3>Sales <small>2026-11-01</small></h3></div></div><div class='row' style='margin-top:8px'><div id='sales_kpi' class='col-12 col-lg-8'></div><div id='sales_gauge' class='col-12 col-lg-4'></div></div></div>
divs: 6 open / 6 closed
onload: execute_script('dHV0by5wNGsuc2FsZXMub25sb2FkLmV4ZQ==', 'KHsicmVnaW9uIjogIk5vcnRoIn0p');
runs tuto.p4k.sales.onload.exe with ({"region": "North"})
Go further
  • The onload script then fills sales_kpi and sales_gauge with REFRESH commands, see the chart recipe.
  • Use responsive classes such as col-12 col-sm-6 col-lg to put 5 cards on one line on large screens only.
executed on MentDB

A remote script behind a page button

Create the server action a page calls in ajax (one OBJ_OVERWRITE_B64 parameter), put a button on the page that sends a product code and the value of a quantity box, then simulate two clicks and read the alerts.

Pipeline
Script
admin
#1. A remote script: one parameter OBJ_OVERWRITE_B64, it answers with ajax commands;
script create exe "tuto.p4k.stock.check" false 1
  (param
  	(var "[OBJ_OVERWRITE_B64]" {true} "Parameters in base 64" is_null:false is_empty:false "{}")
  )
  "Check the stock of a product"
{
	json load "tuto_p4k_param" (string decode_b64 [OBJ_OVERWRITE_B64]);
	-> "[sku]" (json select "tuto_p4k_param" "/sku");
	-> "[qty]" (json select "tuto_p4k_param" "/qty");
	json unload "tuto_p4k_param";
	-> "[left]" (- 40 [qty]);
	if (>= [left] 0) {
		include "app.100.obj.sajax.alert.exe" "[type]" "ALERT_SUCCESS" "[strong]" "In stock"
			"[msg]" (concat [qty] " x " [sku] " reserved, " [left] " left.");
	} {
		include "app.100.obj.sajax.alert.exe" "[type]" "ALERT_WARNING" "[strong]" "Short"
			"[msg]" (concat "Only 40 " [sku] " available.");
	};
} "Ajax commands";
#2. The page: a button whose onclick sends the sku and the value of the box qty_box;
-> "[page]" "<input id='qty_box' type='number' value='3'>";
concat_var "[page]" "<button class='btn btn-primary' onclick=" (include "app.100.obj.sajax.client.exe"
	"[scriptname]" "tuto.p4k.stock.check.exe"
	"[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"sku\": \"BOLT-M8\"}")
	"[getElementById]" "qty=qty_box"
	"[data]" ""
) ">Check stock</button>";
#3. Simulate the clicks: the browser adds qty to the object, then includes the script;
json load "result" "[]";
include "tuto.p4k.stock.check.exe" "[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"sku\": \"BOLT-M8\", \"qty\": 3}");
include "tuto.p4k.stock.check.exe" "[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"sku\": \"BOLT-M8\", \"qty\": 55}");
-> "[answers]" (string regexp_replace (json doc "result") "\n *" "");
json unload "result"; json unload "o";
script delete "tuto.p4k.stock.check.exe";
concat [page] [_n_] "Answers: " [answers] [_n_] "Script left: " (script exist "tuto.p4k.stock.check.exe");
Result
mentdb
<input id='qty_box' type='number' value='3'><button class='btn btn-primary' onclick="execute_script('dHV0by5wNGsuc3RvY2suY2hlY2suZXhl', 'eyJza3UiOiAiQk9MVC1NOCJ9', 'qty=qty_box', '');return false;">Check stock</button>
Answers: [{"msg": "3 x BOLT-M8 reserved, 37 left.","strong": "In stock","type": "ALERT_SUCCESS"},{"msg": "Only 40 BOLT-M8 available.","strong": "Short","type": "ALERT_WARNING"}]
Script left: 0
Go further
  • [getElementById] takes key=elementId pairs separated by commas: the browser copies each element value into the object before the call.
  • Grant the action to the group of the app users with group grant script.
executed on MentDB

Inline contact form with text, mail, tel, textarea and hidden fields

Generate a contact form shown inside a page container, with a hidden source field, required name, e-mail and message, and an optional phone with a pattern. The script parses the generated HTML to list the fields and the Send button call.

Pipeline
Script
admin
#1. A contact form shown inline in the container contact_box;
-> "[app_lang]" "en";
-> "[object]" "";
json load "result" "[]";
include "app.100.obj.form.begin.exe" "[form_id]" "form_contact" "[modal]" false
	"[action]" "index.jsp" "[enctype]" false "[title]" "Contact us" "[subTitle]" "answer within 24 h"
	"[method]" "post" "[widthIfModal]" "modal-lg" "[html]" "";
include "app.100.obj.form.control.hidden.exe" "[control_id]" "source_page" "[value]" "pricing";
include "app.100.obj.form.control.textbox.text.exe" "[control_id]" "full_name" "[class]" "col-12 col-md-6"
	"[label]" "Full name" "[description]" "" "[maxlength]" "80" "[placeholder]" "Jane O'Neil"
	"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" "";
include "app.100.obj.form.control.textbox.mail.exe" "[control_id]" "email" "[class]" "col-12 col-md-6"
	"[label]" "E-mail" "[description]" "We never share it" "[maxlength]" "120" "[placeholder]" "name@company.com"
	"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" "";
include "app.100.obj.form.control.textbox.tel.exe" "[control_id]" "phone" "[class]" "col-12 col-md-6"
	"[label]" "Phone" "[description]" "" "[maxlength]" "20" "[placeholder]" "+262 692 00 00 00"
	"[readonly]" false "[required]" false "[disabled]" false "[html]" "pattern='[+0-9 ]+'" "[value]" "";
include "app.100.obj.form.control.textarea.exe" "[control_id]" "message" "[class]" "col-12"
	"[label]" "Message" "[description]" "2000 characters max" "[maxlength]" "2000" "[placeholder]" ""
	"[readonly]" false "[required]" true "[disabled]" false "[html]" "rows='5'" "[value]" "";
include "app.100.obj.form.end.exe" "[form_id]" "form_contact" "[modal]" false
	"[OBJ_OVERWRITE_B64]" (string encode_b64 "{}") "[container_id]" "contact_box"
	"[mql_script]" "tuto.p4k.contact.send.exe" "[data_eval]" "$('#form_contact').serializeObject()"
	"[closeTitle]" "Close" "[submitTitle]" "Send" "[submitType]" "success";
#2. The answer is one REFRESH: parse its HTML and list the fields;
-> "[html]" (json select "result" "/[0]/innerHtml");
html load_from_str "tuto_p4k_dom" [html];
-> "[fields]" "";
html parse "tuto_p4k_dom" "tuto_p4k_el" "SELECT" "input,textarea" "" {
	concat_var "[fields]" [_n_] "  " (json select "tuto_p4k_el" "/attributes/name") " <" (json select "tuto_p4k_el" "/tagName") " " (json select "tuto_p4k_el" "/attributes/type") ">" (if (> (string regexp_count (json select "tuto_p4k_el" "/outerHtml") " required") 0) {" required"} {""});
};
-> "[button]" "";
html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "button" "" {
	-> "[button]" (concat (json select "tuto_p4k_el" "/text") " -> " (json select "tuto_p4k_el" "/attributes/onclick"));
};
html close "tuto_p4k_dom";
json unload "tuto_p4k_el";
-> "[out]" (concat (json select "result" "/[0]/type") " of #" (json select "result" "/[0]/target") ", " (string length [html]) " chars" [_n_] "Fields:" [fields] [_n_] "Button: " [button]);
json unload "result"; json unload "o";
[out];
Result
mentdb
REFRESH of #contact_box, 2348 chars
Fields:
  source_page <input hidden>
  full_name <input text> required
  email <input email> required
  phone <input tel>
  message <textarea text> required
Button: Send -> if (check_form_values('form_contact')) {execute_script('dHV0by5wNGsuY29udGFjdC5zZW5kLmV4ZQ==', 'e30=', '', 'JCgnI2Zvcm1fY29udGFjdCcpLnNlcmlhbGl6ZU9iamVjdCgp');$('#modal_form_contact').modal('hide');};return false;
Go further
executed on MentDB

Modal booking form with date, datetime, time and number pickers

Book a meeting room in a modal form whose date pickers follow the language of the user: dd/MM/yyyy in French, yyyy-MM-dd in English. The default slot is prefilled with date functions, and the summary shows the ajax commands, the picker formats and the values.

Pipeline
Script
admin
#1. Default slot proposed to the user;
-> "[start]" "2026-11-16 09:30:00";
-> "[out]" "";
json load "tuto_p4k_langs" "[\"fr\", \"en\"]";
json parse_array "tuto_p4k_langs" "/" "[app_lang]" {
	#2. A modal booking form, date pickers in the format of the language;
	-> "[object]" "";
	-> "[app_object_id]" 0;
	json load "result" "[]";
	include "app.100.obj.form.begin.exe" "[form_id]" "form_room" "[modal]" true
		"[action]" "index.jsp" "[enctype]" false "[title]" "Book a meeting room" "[subTitle]" "Room B12"
		"[method]" "post" "[widthIfModal]" "modal-lg" "[html]" "";
	if (equal [app_lang] "fr") {
		include "app.100.obj.form.control.textbox.date_fr.exe" "[control_id]" "day" "[class]" "col-6"
			"[label]" "Day" "[description]" "" "[placeholder]" ""
			"[readonly]" false "[required]" true "[disabled]" false "[html]" ""
			"[value]" (date format [start] "yyyy-MM-dd HH:mm:ss" "dd/MM/yyyy");
		include "app.100.obj.form.control.textbox.datetime_fr.exe" "[control_id]" "reminder" "[class]" "col-6"
			"[label]" "Reminder" "[description]" "" "[placeholder]" ""
			"[readonly]" false "[required]" false "[disabled]" false "[html]" ""
			"[value]" (date format (date addt [start] "HOUR" -1) "yyyy-MM-dd HH:mm:ss" "dd/MM/yyyy HH:mm:ss");
	} {
		include "app.100.obj.form.control.textbox.date_en.exe" "[control_id]" "day" "[class]" "col-6"
			"[label]" "Day" "[description]" "" "[placeholder]" ""
			"[readonly]" false "[required]" true "[disabled]" false "[html]" ""
			"[value]" (string left [start] 10);
		include "app.100.obj.form.control.textbox.datetime_en.exe" "[control_id]" "reminder" "[class]" "col-6"
			"[label]" "Reminder" "[description]" "" "[placeholder]" ""
			"[readonly]" false "[required]" false "[disabled]" false "[html]" ""
			"[value]" (date addt [start] "HOUR" -1);
	};
	include "app.100.obj.form.control.textbox.time.exe" "[control_id]" "start_time" "[class]" "col-6"
		"[label]" "Start" "[description]" "" "[placeholder]" ""
		"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" (string right [start] 8);
	include "app.100.obj.form.control.textbox.number.exe" "[control_id]" "hours" "[class]" "col-6"
		"[label]" "Duration in hours" "[description]" "" "[maxlength]" ""
		"[min]" 0.5 "[max]" 8 "[step]" 0.5 "[placeholder]" ""
		"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" 1.5;
	include "app.100.obj.form.end.exe" "[form_id]" "form_room" "[modal]" true
		"[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"room\": \"B12\"}") "[container_id]" ""
		"[mql_script]" "tuto.p4k.room.book.exe" "[data_eval]" "$('#form_room').serializeObject()"
		"[closeTitle]" "Cancel" "[submitTitle]" "Book" "[submitType]" "primary";
	#3. Summary: the commands, the picker formats, the prefilled values;
	-> "[html]" (json select "result" "/[0]/innerHtml");
	-> "[formats]" (string regexp_replace (string regexp_replace [html] "(?s).*?format : '([^']+)'" "$1 | ") "(?s)\| [^|]*$" "");
	html load_from_str "tuto_p4k_dom" [html];
	-> "[values]" "";
	html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "input" "" {
		concat_var "[values]" (json select "tuto_p4k_el" "/attributes/name") "=" (json select "tuto_p4k_el" "/attributes/value") (if (is null or empty (json select "tuto_p4k_el" "/attributes/id")) {" -no id-"} {""}) "  ";
	};
	html close "tuto_p4k_dom";
	concat_var "[out]" "[" [app_lang] "] " (json select "result" "/[0]/type") " target='" (json select "result" "/[0]/target") "' then " (json select "result" "/[1]/type") " " (json select "result" "/[1]/javascript") [_n_]
		"  pickers: " [formats] [_n_] "  values: " (string trim [values]) [_n_];
};
json unload "tuto_p4k_langs"; json unload "tuto_p4k_el"; json unload "result"; json unload "o";
[out];
Result
mentdb
[fr] REFRESH target='' then JAVASCRIPT object_onload1();
  pickers: DD/MM/YYYY | DD/MM/YYYY HH:mm:ss | HH:mm:ss
  values: day=16/11/2026 reminder=16/11/2026 08:30:00 -no id-  start_time=09:30:00 hours=1.5
[en] REFRESH target='' then JAVASCRIPT object_onload1();
  pickers: YYYY-MM-DD | YYYY-MM-DD HH:mm:ss | HH:mm:ss
  values: day=2026-11-16 reminder=2026-11-16 08:30:00 start_time=09:30:00 hours=1.5
Go further
  • The datetime_fr control writes no id on its input: read it by its name, or through the form serialization, not with [getElementById].
  • A modal form needs [app_object_id] set before: each modal gets its own object_onloadN function.
executed on MentDB

Preferences form with color, range, password and file upload

Build a user preferences form with a theme color, a font size slider, a new password and an avatar upload (multipart form), then check on the server side the values the browser posts without ever echoing the password.

Pipeline
Script
admin
#1. A preferences form with an upload, so enctype is multipart;
-> "[app_lang]" "en";
-> "[object]" "";
json load "result" "[]";
include "app.100.obj.form.begin.exe" "[form_id]" "form_prefs" "[modal]" false
	"[action]" "upload.jsp" "[enctype]" true "[title]" "My preferences" "[subTitle]" ""
	"[method]" "post" "[widthIfModal]" "modal-lg" "[html]" "";
include "app.100.obj.form.control.textbox.color.exe" "[control_id]" "theme_color" "[class]" "col-4"
	"[label]" "Theme color" "[description]" "" "[maxlength]" "7" "[placeholder]" ""
	"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" "#FFB547";
include "app.100.obj.form.control.textbox.range.exe" "[control_id]" "font_size" "[class]" "col-8"
	"[label]" "Font size" "[description]" "12 to 20 px" "[min]" 12 "[max]" 20 "[step]" 1 "[placeholder]" ""
	"[readonly]" false "[required]" false "[disabled]" false "[html]" "oninput='font_px.value=this.value'" "[value]" 14;
include "app.100.obj.form.control.textbox.password.exe" "[control_id]" "new_pwd" "[class]" "col-6"
	"[label]" "New password" "[description]" "10 characters, one digit" "[maxlength]" "64" "[placeholder]" ""
	"[readonly]" false "[required]" false "[disabled]" false "[html]" "autocomplete='new-password'" "[value]" "";
include "app.100.obj.form.control.textbox.file.exe" "[control_id]" "avatar" "[class]" "col-6"
	"[label]" "Avatar" "[description]" "PNG or JPG" "[maxlength]" "255" "[placeholder]" ""
	"[readonly]" false "[required]" false "[disabled]" false "[html]" "accept='.png,.jpg'" "[value]" "";
include "app.100.obj.form.end.exe" "[form_id]" "form_prefs" "[modal]" false
	"[OBJ_OVERWRITE_B64]" (string encode_b64 "{}") "[container_id]" "prefs_box"
	"[mql_script]" "tuto.p4k.prefs.save.exe" "[data_eval]" "$('#form_prefs').serializeObject()"
	"[closeTitle]" "Close" "[submitTitle]" "Save" "[submitType]" "primary";
#2. Read the form tag and each input as the browser will see it;
html load_from_str "tuto_p4k_dom" (json select "result" "/[0]/innerHtml");
html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "form" "" {
	-> "[form]" (concat (json select "tuto_p4k_el" "/attributes/method") " " (json select "tuto_p4k_el" "/attributes/action") " " (json select "tuto_p4k_el" "/attributes/enctype"));
};
-> "[inputs]" "";
html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "input" "" {
	concat_var "[inputs]" [_n_] "  " (json select "tuto_p4k_el" "/attributes/type") " " (json select "tuto_p4k_el" "/attributes/name") " value='" (json select "tuto_p4k_el" "/attributes/value") "'"
		(if (equal (json select "tuto_p4k_el" "/attributes/type") "range") {concat " " (json select "tuto_p4k_el" "/attributes/min") ".." (json select "tuto_p4k_el" "/attributes/max")} {""});
};
html close "tuto_p4k_dom"; json unload "tuto_p4k_el";
#3. Server side: validate what the browser posts, never echo the password;
json load "tuto_p4k_post" "{\"theme_color\": \"#1E88E5\", \"font_size\": \"16\", \"new_pwd\": \"Lagoon2026x\"}";
-> "[pwd]" (json select "tuto_p4k_post" "/new_pwd");
-> "[checks]" (concat "color ok: " (string regexp_count (json select "tuto_p4k_post" "/theme_color") "^#[0-9A-Fa-f]{6}$")
	", size ok: " (and (>= (json select "tuto_p4k_post" "/font_size") 12) (<= (json select "tuto_p4k_post" "/font_size") 20))
	", password ok: " (and (>= (string length [pwd]) 10) (> (string regexp_count [pwd] "[0-9]") 0))
	", salted hash: " (string left (string sha_256 (concat "jane.doe:" [pwd])) 12) "...");
json unload "tuto_p4k_post"; json unload "result"; json unload "o";
concat "Form: " [form] [_n_] "Inputs:" [inputs] [_n_] [checks];
Result
mentdb
Form: post upload.jsp multipart/form-data
Inputs:
  color theme_color value='#FFB547'
  range font_size value='14' 12..20
  password new_pwd value=''
  file avatar value=''
color ok: 1, size ok: 1, password ok: 1, salted hash: c84f49f69990...
Go further
  • [html] adds any attribute to the input: accept, autocomplete, oninput, pattern...
  • Store a password with string sha_512 and a per-user salt, never in clear text.
executed on MentDB

Article editor with CKEditor and a category select

Open an existing news article in a modal editor: a title box, a single-choice category select with codes and labels, and a CKEditor rich text body. The script shows the selected option, how the body is escaped for the textarea, and cleans the HTML the editor posts back.

Pipeline
Script
admin
#1. Edit an existing news article: its current values;
-> "[title]" "Port closed on Friday";
-> "[body]" "<p>The <b>port</b> of Le Port is closed on Friday.</p>";
-> "[category]" "ops";
#2. Modal editor: title, category select, rich text body;
-> "[app_lang]" "en";
-> "[object]" "";
-> "[app_object_id]" 0;
json load "result" "[]";
include "app.100.obj.form.begin.exe" "[form_id]" "form_news" "[modal]" true
	"[action]" "index.jsp" "[enctype]" false "[title]" "Edit article" "[subTitle]" "#118"
	"[method]" "post" "[widthIfModal]" "modal-xl" "[html]" "";
include "app.100.obj.form.control.textbox.text.exe" "[control_id]" "news_title" "[class]" "col-8"
	"[label]" "Title" "[description]" "" "[maxlength]" "120" "[placeholder]" ""
	"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" [title];
include "app.100.obj.form.control.select_mono.exe" "[control_id]" "news_cat" "[class]" "col-4"
	"[label]" "Category" "[description]" ""
	"[readonly]" false "[required]" true "[disabled]" false "[html]" ""
	"[inValues]" "[\"hr\", \"ops\", \"it\"]"
	"[optionValues]" "[\"Human resources\", \"Operations\", \"IT\"]"
	"[value]" [category];
include "app.100.obj.form.control.textarea_cke.exe" "[control_id]" "news_body" "[class]" "col-12"
	"[label]" "Body" "[description]" "" "[maxlength]" "20000" "[placeholder]" ""
	"[readonly]" false "[required]" true "[disabled]" false "[html]" "" "[value]" [body];
include "app.100.obj.form.end.exe" "[form_id]" "form_news" "[modal]" true
	"[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"news_id\": 118}") "[container_id]" ""
	"[mql_script]" "tuto.p4k.news.save.exe" "[data_eval]" "$('#form_news').serializeObject()"
	"[closeTitle]" "Cancel" "[submitTitle]" "Publish" "[submitType]" "success";
#3. What the browser gets: the selected option, the escaped body, the CKEditor init;
html load_from_str "tuto_p4k_dom" (json select "result" "/[0]/innerHtml");
-> "[options]" "";
html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "option" "" {
	concat_var "[options]" (json select "tuto_p4k_el" "/attributes/value") "=" (json select "tuto_p4k_el" "/text") (if (> (string regexp_count (json select "tuto_p4k_el" "/outerHtml") "selected") 0) {" *"} {""}) ", ";
};
html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "textarea" "" {
	-> "[raw]" (string regexp_extract (json select "tuto_p4k_el" "/outerHtml") ">(.*)</textarea>" 1);
	-> "[text]" (json select "tuto_p4k_el" "/text");
};
html close "tuto_p4k_dom";
-> "[cke]" (string regexp_extract (json select "result" "/[0]/innerHtml") "CKEDITOR\.replace\( '[a-z_]+'" 0);
#4. Server side on Publish: strip scripts and inline handlers from the posted HTML;
-> "[posted]" "<p>Closed on <b>Friday</b>.</p><script>steal()</script><img src=x onerror='steal()'>";
-> "[clean]" (string regexp_replace (string regexp_replace [posted] "(?is)<script.*?</script>" "") "(?i) on[a-z]+='[^']*'" "");
json unload "tuto_p4k_el"; json unload "inValues"; json unload "optionValues"; json unload "result"; json unload "o";
concat "Options: " (string regexp_replace [options] ", $" "") [_n_] "Textarea HTML: " [raw] [_n_] "Editor sees: " [text] [_n_] "Init: " [cke] " ..." [_n_] "Posted cleaned: " [clean];
Result
mentdb
Options: hr=Human resources, ops=Operations *, it=IT
Textarea HTML: &lt;p&gt;The &lt;b&gt;port&lt;/b&gt; of Le Port is closed on Friday.&lt;/p&gt;
Editor sees: <p>The <b>port</b> of Le Port is closed on Friday.</p>
Init: CKEDITOR.replace( 'news_body' ...
Posted cleaned: <p>Closed on <b>Friday</b>.</p><img src=x>
Go further
  • The helpers load the json keys inValues and optionValues: unload them at the end of the page.
  • For a real sanitizer, keep a whitelist of tags with html parse rather than a blacklist of regular expressions.
executed on MentDB

Filter panel with checkboxes, radios and a multiple select

Build the filter panel of a ticket list with every choice control: status checkboxes inline, priority radios inline, a multiple select of teams, sort radios one per line and column checkboxes one per line, preselected from the saved filter of the user. The summary reads back each fieldset: kind, number of choices and what is on.

Pipeline
Script
admin
#1. Filter panel of a ticket list, the saved filter of the user preselects values;
-> "[app_lang]" "en";
-> "[object]" "";
json load "result" "[]";
include "app.100.obj.form.begin.exe" "[form_id]" "form_filter" "[modal]" false
	"[action]" "index.jsp" "[enctype]" false "[title]" "Filter tickets" "[subTitle]" ""
	"[method]" "post" "[widthIfModal]" "modal-lg" "[html]" "";
include "app.100.obj.form.control.checkbox_inline.exe" "[control_id]" "status" "[class]" "col-12"
	"[label]" "Status" "[description]" "" "[readonly]" false "[required]" false "[disabled]" false "[html]" ""
	"[inValues]" "[\"open\", \"pending\", \"closed\"]" "[optionValues]" "[\"Open\", \"Pending\", \"Closed\"]"
	"[values]" "{\"open\": 1, \"pending\": 1}";
include "app.100.obj.form.control.radio_inline.exe" "[control_id]" "priority" "[class]" "col-12"
	"[label]" "Priority" "[description]" "" "[readonly]" false "[required]" false "[disabled]" false "[html]" ""
	"[inValues]" "[\"any\", \"P1\", \"P2\", \"P3\"]" "[optionValues]" "[\"Any\", \"P1\", \"P2\", \"P3\"]"
	"[value]" "P1";
include "app.100.obj.form.control.select_multiple.exe" "[control_id]" "teams" "[class]" "col-6"
	"[label]" "Teams" "[description]" "Ctrl+click for several" "[readonly]" false "[required]" false "[disabled]" false "[html]" "size='4'"
	"[inValues]" "[\"net\", \"db\", \"web\", \"desk\"]" "[optionValues]" "[\"Network\", \"Database\", \"Web\", \"Service desk\"]"
	"[values]" "{\"db\": 1, \"web\": 1}";
include "app.100.obj.form.control.radio_line.exe" "[control_id]" "sort" "[class]" "col-6"
	"[label]" "Sort by" "[description]" "" "[readonly]" false "[required]" false "[disabled]" false "[html]" ""
	"[inValues]" "[\"created\", \"updated\", \"sla\"]" "[optionValues]" "[\"Creation date\", \"Last update\", \"SLA left\"]"
	"[value]" "sla";
include "app.100.obj.form.control.checkbox_line.exe" "[control_id]" "cols" "[class]" "col-12"
	"[label]" "Columns" "[description]" "" "[readonly]" false "[required]" false "[disabled]" false "[html]" ""
	"[inValues]" "[\"id\", \"subject\", \"owner\", \"sla\"]" "[optionValues]" null
	"[values]" "{\"id\": 1, \"subject\": 1, \"sla\": 1}";
include "app.100.obj.form.end.exe" "[form_id]" "form_filter" "[modal]" false
	"[OBJ_OVERWRITE_B64]" (string encode_b64 "{}") "[container_id]" "filter_box"
	"[mql_script]" "tuto.p4k.tickets.list.exe" "[data_eval]" "$('#form_filter').serializeObject()"
	"[closeTitle]" "Close" "[submitTitle]" "Apply" "[submitType]" "primary";
#2. Summary per control: kind and preselected values;
html load_from_str "tuto_p4k_dom" (json select "result" "/[0]/innerHtml");
-> "[sum]" "Filter panel, one fieldset per control:";
html parse "tuto_p4k_dom" "tuto_p4k_fs" "TAG" "fieldset" "" {
	html load_from_str "tuto_p4k_sub" (json select "tuto_p4k_fs" "/html");
	-> "[on]" "";
	html parse "tuto_p4k_sub" "tuto_p4k_el" "SELECT" "input[checked],option[selected]" "" {
		concat_var "[on]" (json select "tuto_p4k_el" "/attributes/value") " ";
	};
	-> "[h]" (json select "tuto_p4k_fs" "/html");
	-> "[kind]" (concat
		(case (> (string regexp_count [h] "type=\"radio\"") 0) {"radio"} (> (string regexp_count [h] "type=\"checkbox\"") 0) {"checkbox"} {"select multiple"};)
		(if (> (string regexp_count [h] "form-check-inline") 0) {" inline"} {""}));
	-> "[label]" "";
	html parse "tuto_p4k_sub" "tuto_p4k_el" "TAG" "label" "" {
		if (is empty [label]) {-> "[label]" (json select "tuto_p4k_el" "/text");};
	};
	concat_var "[sum]" [_n_] "  " [label] ": " [kind] ", " (string regexp_count [h] "<(input|option) ") " choices, on: " (string trim [on]);
	html close "tuto_p4k_sub";
};
html close "tuto_p4k_dom";
json unload "tuto_p4k_fs"; json unload "tuto_p4k_el"; json unload "inValues"; json unload "optionValues"; json unload "values"; json unload "result"; json unload "o";
[sum];
Result
mentdb
Filter panel, one fieldset per control:
  Status: checkbox inline, 3 choices, on: open pending
  Priority: radio inline, 4 choices, on: P1
  Teams: select multiple, 4 choices, on: db web
  Sort by: radio, 3 choices, on: sla
  Columns: checkbox, 4 choices, on: id subject sla
Go further
  • Single values use [value]; multiple values use [values], a JSON object whose keys are the selected values.
  • [optionValues] null shows the raw values as labels, like the Columns control.
  • The helpers use the loop variable [i]: do not wrap them in a loop on [i] in your page.
executed on MentDB

Approve button: refresh, alert and JavaScript from one action

Put an Approve button into the actions container of an invoice page while it loads, and write its server action: under 1500 EUR or for a manager it refreshes the status badge, shows a success alert and disables the button with JavaScript; otherwise it only warns.

Pipeline
Script
admin
#1. The action of the Approve button: refresh the status, alert, run some JavaScript;
script create exe "tuto.p4k.invoice.approve" false 1
  (param
  	(var "[OBJ_OVERWRITE_B64]" {true} "Parameters in base 64" is_null:false is_empty:false "{}")
  )
  "Approve an invoice"
{
	json load "tuto_p4k_inv" (string decode_b64 [OBJ_OVERWRITE_B64]);
	-> "[inv]" (json select "tuto_p4k_inv" "/invoice");
	-> "[amount]" (json select "tuto_p4k_inv" "/amount");
	-> "[role]" (json select "tuto_p4k_inv" "/role");
	json unload "tuto_p4k_inv";
	if (or (<= [amount] 1500) (equal [role] "manager")) {
		include "app.100.obj.sajax.refresh.exe" "[target]" "inv_status"
			"[innerHtml]" (concat "<span class='badge badge-success'>Approved " (date curdate) "</span>");
		include "app.100.obj.sajax.alert.exe" "[type]" "ALERT_SUCCESS" "[strong]" [inv]
			"[msg]" (concat "approved, " (math round [amount] 2) " EUR sent to payment.");
		include "app.100.obj.sajax.javascript.exe" "[javascript]" "$('#inv_actions button').prop('disabled', true);";
	} {
		include "app.100.obj.sajax.alert.exe" "[type]" "ALERT_WARNING" "[strong]" [inv]
			"[msg]" "over 1500 EUR: a manager must approve it.";
	};
} "Ajax commands";
#2. While the page loads: put the Approve button into the container inv_actions;
json load "result" "[]";
include "app.100.obj.sajax.button.exe"
	"[container_id]" "inv_actions"
	"[submitTitle]" "Approve"
	"[submitType]" "success"
	"[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"invoice\": \"INV-2026-0412\", \"amount\": 1840.5}")
	"[mql_script]" "tuto.p4k.invoice.approve.exe"
	"[data_eval]" ""
	"[html]" "style='min-width:120px'"
;
-> "[load]" (concat (json select "result" "/[0]/type") " #" (json select "result" "/[0]/target") ": " (json select "result" "/[0]/innerHtml"));
#3. A clerk clicks, then a manager clicks;
json load "result" "[]";
include "tuto.p4k.invoice.approve.exe" "[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"invoice\": \"INV-2026-0412\", \"amount\": 1840.5, \"role\": \"clerk\"}");
-> "[clerk]" (concat (json count "result" "/") " command: " (json select "result" "/[0]/type") " " (json select "result" "/[0]/msg"));
json load "result" "[]";
include "tuto.p4k.invoice.approve.exe" "[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"invoice\": \"INV-2026-0412\", \"amount\": 1840.5, \"role\": \"manager\"}");
-> "[manager]" "";
for (-> "[k]" 0) (< [k] (json count "result" "/")) (++ "[k]") {
	-> "[c]" (concat "/[" [k] "]/");
	concat_var "[manager]" [_n_] "  " (json select "result" (concat [c] "type")) " " (case
		(equal (json select "result" (concat [c] "type")) "REFRESH") {concat "#" (json select "result" (concat [c] "target")) " <- " (json select "result" (concat [c] "innerHtml"))}
		(equal (json select "result" (concat [c] "type")) "JAVASCRIPT") {json select "result" (concat [c] "javascript")}
		{concat (json select "result" (concat [c] "strong")) " " (json select "result" (concat [c] "msg"))};);
};
json unload "result"; json unload "o";
script delete "tuto.p4k.invoice.approve.exe";
concat "On load: " [load] [_n_] "Clerk click: " [clerk] [_n_] "Manager click:" [manager];
Result
mentdb
On load: REFRESH #inv_actions: <button type='submit' style='min-width:120px' class='btn btn-success' onClick="execute_script('dHV0by5wNGsuaW52b2ljZS5hcHByb3ZlLmV4ZQ==', 'eyJpbnZvaWNlIjogIklOVi0yMDI2LTA0MTIiLCAiYW1vdW50IjogMTg0MC41fQ==', '', '');return false;">Approve</button>
Clerk click: 1 command: ALERT_WARNING over 1500 EUR: a manager must approve it.
Manager click:
  REFRESH #inv_status <- <span class='badge badge-success'>Approved 2026-11-01</span>
  ALERT_SUCCESS INV-2026-0412 approved, 1840.5 EUR sent to payment.
  JAVASCRIPT $('#inv_actions button').prop('disabled', true);
Go further
  • In production, read the role from the session with app is_granted_a instead of trusting a value sent by the browser.
  • The browser runs the commands in the order of the result array: refresh first, then the JavaScript that needs the new HTML.
executed on MentDB

Clickable table rows and a Reload button

While a page loads, refresh a container with an orders table whose rows call a detail action on click, and a toolbar with a Reload button that also sends the value of a status filter. The script then reads the onclick of the second row and replays the call exactly as the browser sends it.

Pipeline
Script
admin
#1. The detail action: shows one order in the panel order_detail;
script create exe "tuto.p4k.order.detail" false 1
  (param
  	(var "[OBJ_OVERWRITE_B64]" {true} "Parameters in base 64" is_null:false is_empty:false "{}")
  )
  "Detail of an order"
{
	json load "tuto_p4k_od" (string decode_b64 [OBJ_OVERWRITE_B64]);
	include "app.100.obj.sajax.refresh.exe" "[target]" "order_detail"
		"[innerHtml]" (concat "<h5>Order " (json select "tuto_p4k_od" "/id") "</h5>" (string html_escape (json select "tuto_p4k_od" "/customer")) " - " (json select "tuto_p4k_od" "/total") " EUR");
	json unload "tuto_p4k_od";
} "Ajax commands";
#2. While loading: a table, each row has an onclick event that calls the action;
json load "tuto_p4k_orders" "[{\"id\": 5101, \"customer\": \"Hoarau SARL\", \"total\": 320}, {\"id\": 5102, \"customer\": \"Payet & fils\", \"total\": 1290.4}]";
-> "[rows]" "";
json parse_array "tuto_p4k_orders" "/" "[o]" {
	json load "tuto_p4k_row" [o];
	concat_var "[rows]" "<tr style='cursor:pointer' onclick=" (include "app.100.obj.sajax.client.exe"
		"[scriptname]" "tuto.p4k.order.detail.exe"
		"[OBJ_OVERWRITE_B64]" (string encode_b64 [o])
		"[getElementById]" ""
		"[data]" ""
	) "><td>" (json select "tuto_p4k_row" "/id") "</td><td>" (string html_escape (json select "tuto_p4k_row" "/customer")) "</td></tr>";
};
json load "result" "[]";
include "app.100.obj.sajax.refresh.exe" "[target]" "orders_list" "[innerHtml]" (concat "<table class='table table-hover'>" [rows] "</table>");
#3. And a Reload button refreshed into the toolbar;
include "app.100.obj.sajax.refresh.exe"
	"[target]" "orders_toolbar"
	"[innerHtml]" (concat "<button class='btn btn-light' onclick=" (include "app.100.obj.sajax.client.exe"
		"[scriptname]" "tuto.p4k.orders.list.exe"
		"[OBJ_OVERWRITE_B64]" (string encode_b64 "{\"page\": 1}")
		"[getElementById]" "status=status_filter"
		"[data]" ""
	) ">Reload</button>")
;
-> "[loading]" (concat (json count "result" "/") " commands: " (json select "result" "/[0]/type") " #" (json select "result" "/[0]/target") ", " (json select "result" "/[1]/type") " #" (json select "result" "/[1]/target"));
#4. Replay the click on the second row exactly as the browser sends it;
html load_from_str "tuto_p4k_dom" (json select "result" "/[0]/innerHtml");
-> "[onclick]" "";
html parse "tuto_p4k_dom" "tuto_p4k_el" "TAG" "tr" "" {
	-> "[onclick]" (json select "tuto_p4k_el" "/attributes/onclick");
};
html close "tuto_p4k_dom";
-> "[script]" (string decode_b64 (string regexp_extract [onclick] "execute_script\('([^']*)'" 1));
-> "[b64]" (string regexp_extract [onclick] "execute_script\('[^']*', '([^']*)'" 1);
json load "result" "[]";
include [script] "[OBJ_OVERWRITE_B64]" [b64];
-> "[click]" (concat (json select "result" "/[0]/type") " #" (json select "result" "/[0]/target") " <- " (json select "result" "/[0]/innerHtml"));
json unload "result"; json unload "o"; json unload "tuto_p4k_orders"; json unload "tuto_p4k_row"; json unload "tuto_p4k_el";
script delete "tuto.p4k.order.detail.exe";
concat "While loading: " [loading] [_n_] "Row 2 onclick: " [onclick] [_n_] "Browser sends: include \"" [script] "\" with " (string decode_b64 [b64]) [_n_] "Answer: " [click];
Result
mentdb
While loading: 2 commands: REFRESH #orders_list, REFRESH #orders_toolbar
Row 2 onclick: execute_script('dHV0by5wNGsub3JkZXIuZGV0YWlsLmV4ZQ==', 'eyJ0b3RhbCI6MTI5MC40LCJpZCI6NTEwMiwiY3VzdG9tZXIiOiJQYXlldCAmIGZpbHMifQ==', '', '');return false;
Browser sends: include "tuto.p4k.order.detail.exe" with {"total":1290.4,"id":5102,"customer":"Payet & fils"}
Answer: REFRESH #order_detail <- <h5>Order 5102</h5>Payet &amp; fils - 1290.4 EUR
Go further
  • The payload of each row is visible in the page (base 64 is not encryption): send only ids and check the rights again in the action.
  • Add [getElementById] pairs such as status=status_filter to send the current value of a field with the click.
executed on MentDB

Sales dashboard: KPI cards, bar chart, gauge and sparkline

Fill the columns of a sales dashboard while it loads: two KPI cards, a Chart.js bar chart of the monthly sales, a gauge of the yearly target reached and a trend sparkline, all from data computed in MQL. The summary lists the ajax commands and the library each one uses.

Pipeline
Script
admin
#1. Monthly sales of the year and the yearly target;
json load "tuto_p4k_sales" "[42100, 39800, 45250, 47900]";
-> "[goal_eur]" 230000;
-> "[done]" (+ 42100 39800 45250 47900);
-> "[pct]" (math round (* (/ [done] [goal_eur]) 100) 1);
#2. Onload of the dashboard, each object sends a REFRESH of its column - they set the variable target, so do not use that name for your own data;
-> "[app_object_id]" 0;
-> "[app_object_id_no_load]" 0;
json load "result" "[]";
-> "[kpi_data]" (concat "[{\"class\": \"col-6\", \"title\": \"Sales to date\", \"titleColor\": \"#857B77\", \"value\": \"" [done] " EUR\", \"valueColor\": \"#C9731F\", \"faIcon\": \"fa-euro\"}, {\"class\": \"col-6\", \"title\": \"Best month\", \"titleColor\": \"#857B77\", \"value\": \"April\", \"valueColor\": \"#8C2F28\", \"faIcon\": \"fa-trophy\"}]");
include "app.100.obj.kpi.exe" "[container_id]" "sales_kpi";
-> "[chart_labels]" "[\"Jan\", \"Feb\", \"Mar\", \"Apr\"]";
-> "[chart_title]" "Sales by month";
-> "[chart_data]" (concat "[{\"label\": \"2026\", \"backgroundColor\": \"#FBE3B8\", \"borderColor\": \"#C9731F\", \"borderWidth\": 1, \"data\": " (string regexp_replace (json doc "tuto_p4k_sales") "\s+" "") "}]");
include "app.100.obj.chartjs.bar_vertical.exe" "[container_id]" "sales_bar";
-> "[gauge_value]" [pct];
-> "[gauge_title]" "Yearly target";
-> "[gauge_unit]" "%";
include "app.100.obj.gauge_meter.exe" "[container_id]" "sales_gauge";
include "app.100.obj.sparkline.exe" "[container_id]" "sales_trend" "[type]" "line";
#3. Summary of the answer: one line per command, with the chart library it uses;
-> "[sum]" "";
for (-> "[k]" 0) (< [k] (json count "result" "/")) (++ "[k]") {
	-> "[c]" (concat "/[" [k] "]/");
	-> "[t]" (json select "result" (concat [c] "type"));
	-> "[h]" (if (equal [t] "REFRESH") {json select "result" (concat [c] "innerHtml")} {json select "result" (concat [c] "javascript")});
	concat_var "[sum]" [_n_] "  " [t] " " (if (equal [t] "REFRESH") {concat "#" (json select "result" (concat [c] "target")) ", " (string length [h]) " chars, "
		(case (> (string regexp_count [h] "new Chart") 0) {"Chart.js"} (> (string regexp_count [h] "JustGage") 0) {"JustGage"} (> (string regexp_count [h] "sparkline") 0) {"Sparkline"} {"HTML"};)} {[h]});
};
-> "[bar]" (string regexp_extract (json select "result" "/[1]/innerHtml") "datasets: (.*)" 1);
-> "[gauge]" (string regexp_extract (json select "result" "/[3]/innerHtml") "value: ([0-9.]+)" 1);
-> "[left]" (env exist var "[chart_data]");
json unload "tuto_p4k_sales"; json unload "result"; json unload "o"; json unload "data";
concat "Sales " [done] " EUR = " [pct] "% of " [goal_eur] [_n_] "Commands:" [sum] [_n_] "Bar datasets: " [bar] [_n_] "Gauge value: " [gauge] ", chart_data still set: " [left];
Result
mentdb
Sales 175050 EUR = 76.1% of 230000
Commands:
  REFRESH #sales_kpi, 766 chars, HTML
  REFRESH #sales_bar, 1252 chars, Chart.js
  JAVASCRIPT object_onload1();
  REFRESH #sales_gauge, 693 chars, JustGage
  REFRESH #sales_trend, 1087 chars, Sparkline
Bar datasets: [{"label": "2026", "backgroundColor": "#FBE3B8", "borderColor": "#C9731F", "borderWidth": 1, "data": [42100,39800,45250,47900]}]
Gauge value: 76.1, chart_data still set: 0
Go further

Also in Programming

MB
MQL beginner
Variables, operators, if, loops and your first try/exception: learn MQL step by step.
10 recipes
MD
MQL developer
Atom lists, data types, constants, translations, session variables and error patterns.
10 recipes
BW
Backend & web service developer
Typed scripts, execute / call / include, generated calls and URLs, parameters and logs.
10 recipes
DT
Date & time developer
Calendars, business days, time zones, ISO and epoch, durations, quarters and week numbers.
10 recipes
SE
String & encoding developer
Cleaning, case styles, regex, URL/HTML/Base64 encodings, number bases and encryption.
10 recipes
DV
Data validation developer
IBAN, BIC, SIRET, Luhn, email, IP, UUID, JSON and date checks gathered in a validation report.
10 recipes
JD
JSON & document store developer
In-memory JSON documents, persistent nodes and sequences: build, walk, sort, clean up.
10 recipes
SD
Script developer
Full script lifecycle in the MQL editor: typed parameters, read back, generate, patch, deploy, copy, grant, delete.
10 recipes
EM
Execution modes
execute, call, include, sub_include, parallel, stack: which environment, which checks, which logs.
11 recipes
WS
Web service developer
A small REST resource with get, post, put and delete scripts: validation, JSON answers, codes, grants, URLs and API docs.
10 recipes
AD
Async developer
Asynchronous processing with the stack: push runs now or later, priorities and parallel limits, errors and replays, flows and cleanup.
10 recipes
SD
Scheduler developer
Cron jobs and delayed runs: add, resume, pause, update and remove jobs, prove they ran, and postpone stack runs with a delay condition.
10 recipes
ED
Event developer
Event-driven scripts: file watchers that push each file event to the stack, validation, archiving, errors and safe restarts.
10 recipes
CC
Configuration & connections
Parameters (private, described, locked, deployed), environment variables, sessions and connections used by your scripts.
12 recipes
VD
Versioning & deployment
Group your scripts, commit, compare, roll back, export, import and package a release.
10 recipes
DE
Debugging & error handling
Coded errors with try/exception, logs with correlation ids, timing, metrics and defensive checks.
10 recipes
SD
SQL developer in MQL
Connections, DDL and DML with sql encode, transactions, cursors, parse, and exports to JSON, CSV, Excel and PDF on a real local database. Run the recipes in order: the first one creates the tuto_db_h2 database.
10 recipes
CD
CRUD & data API developer
Generate SCRUD scripts from a table, patch and install them, write typed read and write APIs, check data quality and manage connections per environment. Uses the tuto_db_h2 database of the SQL developer recipes; the last recipe removes it.
10 recipes
WA
Web application developer
Create a web app, its host name, pages, ajax forms, menu and grants, then remove it all.
10 recipes
AI
Algorithms in MQL
Sorting, searching, recursion, data structures and number algorithms: MQL is a real programming language.
10 recipes
CF
Control flow
if, if force, case, switch, mode, for, while, repeat, break, continue, parallel and synchronized on real cases.
10 recipes
TM
The MQL language in depth
Data types and null, booleans, comments, variables and scope, eval and mql blocks, coded errors and try.
10 recipes