1 /** 2 * Copyright © Yurai Web Framework 2021 3 * License: MIT (https://github.com/YuraiWeb/yurai/blob/main/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 */ 6 module yurai.views.view; 7 8 import yurai.core; 9 import yurai.views.viewresult; 10 import yurai.external.iserver; 11 12 public abstract class View 13 { 14 private: 15 IHttpRequest _request; 16 IHttpResponse _response; 17 IServer _server; 18 string _content; 19 string[string] _placeholders; 20 string _name; 21 string _contentType; 22 string _section; 23 string[] _routes; 24 25 protected: 26 this(IHttpRequest request, IHttpResponse response, string[] routes = null) 27 { 28 this(null, request, response, null); 29 } 30 31 this(string name, IHttpRequest request, IHttpResponse response, string[] routes = null) 32 { 33 _name = name; 34 35 _request = request; 36 _response = response; 37 38 _server = _request.server; 39 40 _routes = routes; 41 42 _placeholders["doctype"] = "<!doctype html>"; 43 } 44 45 @property 46 { 47 IHttpRequest request() { return _request; } 48 49 IHttpResponse response() { return _response; } 50 51 IServer server() { return _server; } 52 53 string name() { return _name; } 54 55 string[] routes() { return _routes; } 56 } 57 58 void setContentType(string contentType) 59 { 60 _contentType = contentType; 61 } 62 63 ViewResult finalizeContent(string layout = null, bool processLayout = true) 64 { 65 if (layout && layout.length && processLayout) 66 { 67 import yurai.prebuild.viewsmap; 68 69 auto layoutView = getView(layout, _request, _response); 70 71 if (layoutView) 72 { 73 layoutView._name = _name; 74 75 foreach (k,v; _placeholders) 76 { 77 layoutView.setPlaceholder(k, v); 78 } 79 80 layoutView.setPlaceholder("view", _content); 81 return layoutView.generate(true); 82 } 83 } 84 85 return new ViewResult(_content ? _content : "", _contentType); 86 } 87 88 void renderPartial(string name) 89 { 90 import yurai.prebuild.viewsmap; 91 92 auto partialView = getView(name, _request, _response); 93 94 if (partialView) 95 { 96 foreach (k,v; _placeholders) 97 { 98 partialView.setPlaceholder(k, v); 99 } 100 101 auto result = partialView.generateFinal(true); 102 103 if (!result) 104 { 105 throw new Exception("Failed to render partial view."); 106 } 107 108 append(result.content ? result.content : ""); 109 } 110 } 111 112 void renderPartialModel(string name, T)(T model) 113 { 114 mixin("import yurai.prebuild.views : view_" ~ name ~ ";"); 115 import yurai.prebuild.viewsmap; 116 117 mixin("auto partialView = cast(view_" ~ name ~ ")getView(name, _request, _response);"); 118 119 if (partialView) 120 { 121 foreach (k,v; _placeholders) 122 { 123 partialView.setPlaceholder(k, v); 124 } 125 126 auto result = partialView.generateModel(model); 127 128 if (!result) 129 { 130 throw new Exception("Failed to render partial view."); 131 } 132 133 append(result.content ? result.content : ""); 134 } 135 } 136 137 void setPlaceholder(string key, string value) 138 { 139 _placeholders[key] = value; 140 } 141 142 string getPlaceholder(string key, string defaultValue = "") 143 { 144 return _placeholders.get(key, defaultValue ? defaultValue : ""); 145 } 146 147 void appendPlaceholder(string key, string value) 148 { 149 auto content = getPlaceholder(key); 150 151 content ~= value; 152 153 setPlaceholder(key, content); 154 } 155 156 void setSection(string name) 157 { 158 _section = name == "*" ? null : ("section: " ~ name); 159 } 160 161 void escaped(T)(T data) 162 { 163 import std.conv : to; 164 import yurai.security.html; 165 166 auto s = to!string(data); 167 168 s = escapeHtml(s); 169 170 append(s); 171 } 172 173 void append(T)(T data) 174 { 175 import std.conv : to; 176 177 import std.stdio; 178 179 auto s = to!string(data); 180 181 if (_section && _section != "*") 182 { 183 appendPlaceholder(_section, s); 184 } 185 else 186 { 187 _content ~= s; 188 } 189 } 190 191 public: 192 abstract ViewResult generate(bool processLayout); 193 194 abstract ViewResult generateFinal(bool processLayout); 195 }