#load "../config/settings.uce" #load "user.class.h" String app_fs_root(Request& context) { String root = context.var["app"]["fs_root"].to_string(); if(root == "") root = cwd_get(); return(root); } String app_script_url(Request& context) { String url = context.var["app"]["script_url"].to_string(); if(url == "") url = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]); return(url); } String app_base_url(Request& context) { String base = context.var["app"]["base_url"].to_string(); if(base == "") { base = dirname(app_script_url(context)); if(base == "") base = "/"; if(base[base.length() - 1] != '/') base.append(1, '/'); } return(base); } String app_fs_path(String relative, Request& context) { return(path_join(app_fs_root(context), relative)); } String app_link(String path, Request& context); String app_link(String path, StringMap params, Request& context); void app_init(Request& context); String app_first_route_segment(Request& context) { String query = context.params["QUERY_STRING"]; for(auto part : split(query, "&")) { if(part == "") continue; if(part.find("=") == String::npos) return(uri_decode(part)); } return(""); } DTree app_make_route(Request& context) { DTree route; String path = app_first_route_segment(context); path = trim(path); while(path.length() > 0 && path[0] == '/') path = path.substr(1); while(path.length() > 0 && path[path.length() - 1] == '/') path = path.substr(0, path.length() - 1); if(path == "") path = "index"; route["l_path"] = path; route["page"] = nibble(path, "/"); if(route["page"].to_string() == "") route["page"] = "index"; return(route); } DTree app_resolve_view(Request& context, String base_dir = "views") { DTree result; DTree route = context.var["app"]["route"]; String lpath = first(route["l_path"].to_string(), "index"); String base = trim(base_dir); if(base != "" && base[base.length() - 1] == '/') base = base.substr(0, base.length() - 1); String exact = base + "/" + lpath + ".uce"; if(file_exists(exact)) { result["file"] = exact; return(result); } String dir_index = base + "/" + lpath + "/index.uce"; if(file_exists(dir_index)) { result["file"] = dir_index; return(result); } auto parts = split(lpath, "/"); if(parts.size() > 1) { String param = parts.back(); parts.pop_back(); String parent = join(parts, "/"); String parent_index = base + "/" + parent + "/index.uce"; if(file_exists(parent_index)) { result["file"] = parent_index; result["param"] = param; return(result); } } return(result); } void app_register_css(String path, Request& context) { context.var["app"]["assets"]["css"][path] = path; } void app_register_js(String path, Request& context) { context.var["app"]["assets"]["js"][path] = path; } String app_asset_url(String path, Request& context) { String url = app_base_url(context) + path; String fs_path = app_fs_path(path, context); if(file_exists(fs_path)) url += "?v=" + std::to_string((u64)file_mtime(fs_path)); return(url); } void app_render_registered_css(Request& context) { context.var["app"]["assets"]["css"].each([&](DTree item, String key) { String path = item.to_string(); if(path != "") { <> } }); } void app_render_registered_js(Request& context) { context.var["app"]["assets"]["js"].each([&](DTree item, String key) { String path = item.to_string(); if(path != "") { <> } }); } String app_link(String path, Request& context) { StringMap params; return(app_link(path, params, context)); } String app_link(String path, StringMap params, Request& context) { String query = ""; path = trim(path); if(path != "") query = uri_encode(path); String extra = encode_query(params); if(query != "" && extra != "") query += "&" + extra; else if(query == "") query = extra; String url = app_script_url(context); if(query != "") url += "?" + query; return(url); } void app_redirect(String path, Request& context) { context.set_status(302, "Found"); context.header["Location"] = app_link(path, context); } void app_not_found(String message, Request& context) { context.set_status(404, "Not Found"); context.var["app"]["error"] = message; context.var["app"]["page_title"] = "404 Not Found"; } String app_menu_href(String menu_key, DTree menu_item, Request& context) { if(menu_item["external"].to_string() != "") return("/" + menu_key); return(app_link(menu_key, context)); } String app_html_class(Request& context) { String classes = "no-js"; if(context.cfg.get_by_path("theme/mode").to_string() == "dark") classes += " dark-theme"; return(classes); } String app_page_main_html(Request& context) { String main_html = context.call["main_html"].to_string(); if(main_html == "") main_html = context.var["app"]["fragments"]["main"].to_string(); return(main_html); } bool app_bool_value(DTree value, bool fallback = false) { String raw = trim(value.to_string()); if(raw == "") return(fallback); return( raw != "0" && raw != "false" && raw != "FALSE" && raw != "False" && raw != "(false)" && raw != "no" && raw != "NO" && raw != "No" ); } bool app_request_embed_mode(Request& context) { return(app_bool_value(context.var["app"]["embed_mode"])); } bool app_page_embed_mode(Request& context) { String embed_value = context.call["embed_mode"].to_string(); if(embed_value != "") return(app_bool_value(context.call["embed_mode"])); return(app_request_embed_mode(context)); } String app_theme_page_component(Request& context) { String page_type = first(context.var["app"]["page_type"].to_string(), "html"); if(page_type == "blank") return("themes/common/page.blank.uce"); if(page_type == "json") return("themes/common/page.json.uce"); String theme_path = context.cfg.get_by_path("theme/path").to_string(); if(theme_path == "") return(""); if(theme_path[theme_path.length() - 1] != '/') theme_path.append(1, '/'); return(theme_path + "page.html.uce"); } void app_render_page(Request& context) { if(context.flags.status >= 300 && context.flags.status < 400) return; DTree page_props; page_props["main_html"] = context.var["app"]["fragments"]["main"]; if(context.var["app"]["json"].get_type_name() == "array") page_props["json"] = context.var["app"]["json"]; String page_component = app_theme_page_component(context); if(page_component != "" && file_exists(page_component)) { print(component(page_component, page_props, context)); return; } context.set_status(500, "Internal Server Error"); context.header["Content-Type"] = "text/plain; charset=utf-8"; print("UCE app is missing the page template component: " + page_component); } // Backward-compatible aliases for older starter example units. using StarterUser = AppUser; void starter_boot(Request& context) { app_init(context); } String starter_link(String path, Request& context) { return(app_link(path, context)); } String starter_link(String path, StringMap params, Request& context) { return(app_link(path, params, context)); } void starter_register_css(String path, Request& context) { app_register_css(path, context); } void starter_register_js(String path, Request& context) { app_register_js(path, context); } String starter_asset_url(String path, Request& context) { return(app_asset_url(path, context)); } void starter_render_registered_css(Request& context) { app_render_registered_css(context); } void starter_render_registered_js(Request& context) { app_render_registered_js(context); } bool starter_page_embed_mode(Request& context) { return(app_page_embed_mode(context)); } String starter_page_main_html(Request& context) { return(app_page_main_html(context)); } String starter_html_class(Request& context) { return(app_html_class(context)); } String starter_menu_href(String menu_key, DTree menu_item, Request& context) { return(app_menu_href(menu_key, menu_item, context)); } void starter_render_page(Request& context) { app_render_page(context); } void starter_redirect(String path, Request& context) { app_redirect(path, context); } void starter_not_found(String message, Request& context) { app_not_found(message, context); } DTree starter_make_route(Request& context) { return(app_make_route(context)); } DTree starter_resolve_view(Request& context, String base_dir = "views") { return(app_resolve_view(context, base_dir)); } void app_init(Request& context) { if(context.var["app"]["booted"].to_string() == "1") return; context.var["app"]["booted"] = "1"; context.var["app"]["fs_root"] = cwd_get(); context.var["app"]["script_url"] = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]); String base_url = dirname(context.var["app"]["script_url"].to_string()); if(base_url == "") base_url = "/"; if(base_url[base_url.length() - 1] != '/') base_url.append(1, '/'); context.var["app"]["base_url"] = base_url; DTree config = get_config(); String requested_theme = first(context.get["theme"], context.cookies["app_theme"], config["theme"]["key"].to_string()); if(config["theme"]["options"][requested_theme].to_string() == "" && config["theme"]["options"][requested_theme].get_type_name() != "array") requested_theme = config["theme"]["key"].to_string(); config["theme"]["options"][requested_theme].each([&](DTree item, String key) { config["theme"][key] = item; }); config["theme"]["key"] = requested_theme; context.cfg = config; context.var["cfg"].set_reference(&context.cfg); context.var["app"]["config"].set_reference(&context.cfg); context.var["app"]["route"] = app_make_route(context); context.var["app"]["page_type"] = "html"; context.var["app"]["page_title"] = first(config["menu"][context.var["app"]["route"]["l_path"].to_string()]["title"].to_string(), config["site"]["default_page_title"].to_string(), "Home"); context.var["app"]["embed_mode"].set_bool(context.get["embed"] != ""); if(context.get["theme"] != "" && context.get["theme"] == requested_theme) { set_cookie("app_theme", requested_theme, time() + (86400 * 180)); context.cookies["app_theme"] = requested_theme; } session_start(); AppUser(context).is_signed_in(); app_register_css(context.cfg.get_by_path("theme/path").to_string() + "css/style.css", context); app_register_css("themes/common/fontawesome/css/all.min.css", context); app_register_js("js/u-query.js", context); app_register_js("js/morphdom.js", context); app_register_js("js/site.js", context); }