"},{raw, Bin},"{raw,"}],
73 | % better use like {raw,["",Bin,""]}. 74 | % Child(s) of raw is an iolist, but can als contain ehtml, again 75 | % using {ehtml, ...} 76 | % It will not be encoded in any way. 77 | % 78 | % {stream, Acc0, fun(Acc) -> {E, Acc} end}. 79 | % Similary, but fun will be evaluated just on sending data to the browser, 80 | % thus keeping memory requirment smaller. 81 | % Good for tables and lists of any kinds. 82 | % Remember that this is probably only usefull if backend data 83 | % is also retrivied in similar fashion (like cursor in qlc, 84 | % or iterators in mnesia, dets, or cursor in SQL). 85 | % 86 | % ehtml - is silently ignored, but its child must be valid ehtml, 87 | % and is valideted. If there are attributes, they are inspected, 88 | % for example to change encoding, or perform scheme translations. 89 | % 90 | % ehtml, [valid] - if it is ehtml chunk, but it is already valid. 91 | % html_raw, [valid] - similary but for validated html_raw chunks. 92 | % 93 | % raw, [dirty] - if it is already compiled and verified. 94 | % Or you are sure it is valid for other reason. 95 | % Or want to cheat, and send invalid xml. 96 | % Or you tested that performance of validator is a bottlneck. 97 | % 98 | % string, int, float - will type check content, and convert data 99 | % to the proper form. String can be iolist, 100 | % HTML safe encoding will be performed. 101 | % (coding using entities and few others characters 102 | % which can dangerous normally) 103 | % 104 | % {include, File} - will include file with ehtml term, it can 105 | % contain many terms, each terminated with dot. 106 | % {include, [valid], File} - marks that content of File have been 107 | % already in some way valideted (i.e. in cache), or for performance reasons. 108 | % {include, [raw], File} - will include file just like raw, must be valid HTML/XML part. 109 | % {include, [raw,dirty], File} - will include file just 110 | % like raw, but will not be validated. 111 | % {include, [raw, {rewrite, "%", [{"A", "Godzilla"}]}], File} - also 112 | % available as {ssi, "filename.txt", "%", [{"a", "Godzilla"}]} - 113 | % includes file, but all occurence of "%a%" are changed into "Godzilla" 114 | % variable names should be have first letter upper case (just like Erlang variables) 115 | % and MUST not contain "%", or whitespaces. It should only use letters, numbers, underline. 116 | % Optionally it can contain: minus, plus, star, dot, double collon, collon, braces, 117 | % curly-braces, squre brackets, angle brackets, dollar, pipe, slash, semicolon, 118 | % exclamation mark, at-sign, hash-mark. 119 | % {include, [{rewrite, [{"A", "Godzilla"}]}], File} - works similary to {include, File} 120 | % but allows using variables. It is forbiden to use Erlang expressions other than term construction, 121 | % in included file. 122 | % {include, [dtl], {template_module, something, File}} - include File as DTL (Django template). 123 | % One can add 'dirty' option, if want to assume validity. 124 | % If one will use atom to reference module, then File will be compiled 125 | % once into template_module:something/1 function. If no such module exists 126 | % it will be created from given template and compiled properly on first usage. 127 | % Dynamic recompilation of new files (for example after change, but without restarting server and removing beam files), 128 | % can be done based on atime, or manually (globally or per-file or per-module) 129 | % using erljs_html:dtl_options([Opts]) where Opts is 130 | % clear_all - will clear all files and recompile them, on next usaxe. 131 | % mtime - will set automatic recompilation based on modification time of file 132 | % every - will recompile template on every access (can be usefull when developing application, 133 | % or when there are very big number of templates, as they will normally be loaded 134 | % into VM as modules, thus consuming RAM). 135 | % recompile_known - will recompile all loaded currently templates. 136 | % 137 | % DTL templates will use current request dictionaries as variables. 138 | % You can also provide own values using, {rewrite,[...]} just like in ehtml templates, 139 | % but you keys need to be valid Python identifiers (still they also should begin 140 | % from upper case, to/from make porting to ehtml templates and javascript easier). 141 | % 142 | % DTL template can be compiled to raw text, or to ehtml templates, thus making, 143 | % validation and dynamic insertion into DOM easier (without innerHTML). 144 | % 145 | % For compiled ehtml templates it is possible, to update live DOM tree, in such manner, 146 | % that if on new rendering in the same place some part of HTML will no change 147 | % they will not be removed from DOM tree, if some was removed/added (due to the {% if %}), 148 | % they will be removed/added. In case of loops, the old childrens will be removed, and new 149 | % childrens will be added (this can be changed by {loops,append}, which will append new childs 150 | % after existing ones if they exist). This only applies to the outer-most loops. 151 | % 152 | % For more on DTL go to: 153 | % http://www.djangoproject.com/documentation/templates/ 154 | % http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/dtl/ 155 | % 156 | % In case of files, file will not be readed to the memory, but will be streamed to the client when nacassary. 157 | % 158 | % In case of error (no such regular file, bad permissions) response will immiedietly stop, 159 | % and connection will be terminated unclearly. Be sure no error will occur. 160 | % 161 | % When rewriting values, one can use string, binary-string, or {ehtml, ...} struct (it will be 162 | % serialized to html binary-string). 163 | % 164 | % Attributes needs to be valid attributes for corresponsing 165 | % tag elements. Their values also need to be correct. 166 | % 167 | % One can also create own tags: 168 | % 169 | % new_element_type(page, fun (Attributes, Childs) when is_list(Childs) -> 170 | % {ehtml, {html, { 171 | % header, 172 | % {body, Childs} 173 | % }}}. 174 | % end, [parse_childs]). 175 | % 176 | % new_element_type(header, fun (Attributes, Childs) when is_list(Childs) -> 177 | % {raw, "Hello"} 178 | % end, [parse_childs, cache]). 179 | % 180 | % new_element_type(my_table, fun (Attributes, [{stream, SubAcc0, Fun}]) -> 181 | % {ehtml, {table, 182 | % {stream, {SubAcc0, 1}, fun({SubAcc, N) -> 183 | % Style = if 184 | % N rem 2 == 1 -> [{class, 'odd'}]; 185 | % true -> [{class, 'even'}] 186 | % end, 187 | % {SubE, NewSubAcc} = Fun(SubAcc), 188 | % E = {tr, [Style], SubE}, 189 | % NewAcc = {NewSubAcc, N+1}, 190 | % {E, NewAcc} 191 | % end} 192 | % }} 193 | % end, [parse_childs, cache]). 194 | 195 | % 196 | % If there was no Attributes or Childs, they will be an empty list. 197 | % In all cases it will be an list (also in case only one element 198 | % was given originally, or raw data, pcdata, or string, or binary). 199 | % 200 | % parse_childs - means that ehtml engine will first parse 201 | % all childrens before giving them to the fun. 202 | % no_parse_childs - means that fun must parse them alone. 203 | % 204 | % cache - means that result of fun will be cached (as far as Attributes and Childs) match 205 | % generation and validation will be performed only once. 206 | % 207 | % 208 | % Fun should return ehtml (which could possibly trigger again some 209 | % funs to be called) or raw data. 210 | 211 | 212 | % One can also use parse transform (similar to qlc:q([...]) ...) in the form: 213 | 214 | 215 | % erljs_html:pf({ehtml, {html, {body, 216 | % [header, 217 | % ... 218 | % ] 219 | % }}}) 220 | % 221 | % such ehtml, will be parsed and compiled in advance to most compressed 222 | % form with minimal space, network and cpu usage (for example 223 | % glueing together consecutive opening tags into single binary, 224 | % it will be flat narrow list, not deep and wide list). 225 | % in case it is literal constant term, it is simple 226 | % in case it refferes to some variables or functions or expressions, 227 | % it will try to compile as much as possible from it, and make original 228 | % call a call to the specialized fun). 229 | % 230 | % Care must be taken when generating huge amount data, as 231 | % all data is keeped in memory. For huge amount of data, 232 | % streaming techniques can be used. 233 | % 234 | % 235 | % Hyperlinks should be encoded using 236 | % erljs_html:a(LogicalKey, [{param,Value}}, [OtherAttributes]) 237 | % where OtherAttributes can also contain {target,"xxx"}, which will translate into "#xxx" appened to href. 238 | % Direct usage of 'a' can be disabled, or checked, 239 | % by changing scheme (allow_custom_a_href). 240 | % 241 | % 242 | % erljs_html:register_a(LogicalKey, RealPath, 243 | % [{param1,int,required}, 244 | % {param2,float,optional}, 245 | % {"param3",any,optional}, 246 | % {{"^params_.*$"},int,optional} 247 | % ) 248 | % 249 | % This have many advantages. 250 | % - you can track usage of all links 251 | % - you can add additional parameters (like security tokens, session ids) 252 | % - you can easly move site or part of it to other directory, or location 253 | % - you can enforce absolute or relative URLS 254 | % - you can enforce https encryption 255 | % - you can create proxy/redir page, which will hide user's Refferer 256 | % 257 | % 258 | % 259 | 260 | % 261 | % syntactic sugar for 'style' attribute 262 | % 263 | 264 | 265 | % TODO: registering parameters. 266 | % 267 | % 268 | % ?get_required(int, Page). 269 | % ?get_required(postive_int, Page). 270 | % ?get_required(float, Temp). 271 | % ?get_optional(identifier, Temp). 272 | % ?get_optional(id, Id). 273 | % ?get_optional(atom, Elem). % it will must be 'atom' like, but not actually converted 274 | % ?get_optional({"....-....-\\d\\d"}, Key). % for regular expressions 275 | % ?get_optional(fun(X) -> is_valid_token(X) end, Token). % for general tests 276 | % listing(Req) -> 277 | % {page, 278 | % ["something -", Page] 279 | % }. 280 | % 281 | % in case of int, positive_int, float - arguments are parsed as int or float. 282 | % 283 | 284 | % ?pre_require(secure). % https over ssl/tls. todo: warn/clear cookies, log referrer, etc 285 | % ?pre_require(auth). 286 | % ?pre(log). 287 | % ?post(trace). 288 | % ?cookie(present). 289 | % ?header(present, "Refferer"). 290 | 291 | 292 | % 293 | % Other important parts in ehtml 294 | % {status, 404} % yaws 295 | % {status, 404, "WTF"} 296 | % {redirect, URL} % yaws % URL must be absolute URL 297 | % {redirect_local, Path} % yaws % URL 298 | % {headers, [ 299 | % clear, 300 | % [{set, Header}] 301 | % [{replace, Header}] 302 | % [{append, Header}] 303 | % [{remove, Header}] 304 | % ]}. 305 | % where Header is binary or string "XXX: YYY", or {'XXX', "YYY"} 306 | % no new lines allowed. 307 | % ok % yaws % do nothing 308 | % {'EXIT', normal} % yaws 309 | % {content, MimeType, Data} % yaws 310 | % {sendfile, FileName, Start, End} % End can be eof. 311 | % 312 | % %{allheaders, [Headers]} % yaws 313 | % %{header, Header} % yaws 314 | % 315 | % {streamcontent, MimeType, FirstChunk} % yaws 316 | % 317 | % in other process. 318 | % % YawsPid is original process which was serving, so S=self(),spawn(fun()->loop(S) end) 319 | % yaws_api:stream_chunk_deliver(YawsPid, BinData), 320 | % yaws_api:stream_chunk_deliver(YawsPid, BinData), 321 | % yaws_api:stream_chunk_deliver_blocking(YawsPid, Data), % with sending flow-control 322 | % yaws_api:stream_chunk_end(YawsPid), 323 | % exit(normal). 324 | % 325 | % NewPid = spawn(fun() -> loop(A#arg.clisock) end), 326 | % [{header, {content_length, Sz}}, % without content_length, chunked mode (b) is used 327 | % {streamcontent_from_pid, MimeType, NewPid}] % yaws 328 | % 329 | % in loop 330 | % % {discard, YawsPid} -> 331 | % % yaws_api:stream_process_end(Sock, YawsPid); 332 | % % {ok, YawsPid} -> 333 | % % a) yaws_api:stream_process_deliver(Socket, BinData), 334 | % % a) yaws_api:stream_process_deliver(Socket, BinData), 335 | % % b) yaws_api:stream_process_deliver_chunk(Socket, IoList), 336 | % % b) yaws_api:stream_process_deliver_chunk(Socket, IoList), 337 | % % b) yaws_api:stream_process_final_deliver_chunk(Socket, IoList), 338 | % % yaws_api:stream_process_end(Socket, YawsPid) 339 | % for delive 340 | % 341 | % {ssi, FileName, Separator, [{"var","Rewriting it to something"}. % yaws. similar to include. 342 | % % included for compatibility. 343 | % {yssi, FileName}. % yaws, only top level element from out/1. 344 | 345 | 346 | % TODO: 347 | % SVG: esvg % http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd 348 | % svg 349 | % a, altGlyph, altGlyphDef, altGlyphItem, animate, animateColor, animateMotion, animateTransofrm 350 | % circle, clipPath, color_profile, cursor 351 | % definition_src, defs, desc 352 | % ellipse 353 | % feBlend, feColorMatrix, feComponentTransfer, feComposite, feConvolveMatrix, feDiffuseLighting, feDisplacementMap, feFlood, feFuncA, feFuncB, feFuncG, feFuncR, feGaussianBlur, feImage, feMerge, feMergeNode, feMorphology, feOffset, fePointLight, feSpecularLighting, feSpotLight, feTile, feTurbulence 354 | % filter, font, font_face, font_face_format, font_face_name, font_face_src, font_face_uri, foreignObject 355 | % g, glyph, glyphRef 356 | % hkern, vkern 357 | % image 358 | % line, linearGradient 359 | % marker, mask, metadata, missing_glyph 360 | % mpath, path, pattern, polygon, polyline 361 | % radialGradient, rect 362 | % script, set, stop, style, switch, symbol 363 | % text, textPath, title, tref, tspan 364 | % use, view 365 | % 366 | % esvg_valid - marks that esvg fragment should not be validated, as it was already validated 367 | % svg_raw - to put iolist() directly in given place. it still need to be valid svg fragment, and validate 368 | % 369 | % Example: 370 | % {esvg, [{width,"100%"},{height,"100%"}], [ 371 | % {circle, [{cx,100},{cy,50},{r,40},{stroke,'black'},{stroke_width,2},{fill,'red'}], []}, 372 | % {rect, [{x,20},{y,20},{rx,20},{ry,20},{width,250},{height,250},{style,"fill:blue;stroke:ping;fill-opacity:0.1;stroke-opacity:0.9"}], []}, 373 | % {ellipse, [{cx,300},{cy,150},{rx,200},{ry,80},{style,"fill:rgb(200,100,50)"}], []}, 374 | % {line,[{x1,0},{y1,0},{x2,300},{y2,300},{style,"stroke:rgb(99,99,99);stroke-width:2"}], []}, 375 | % {polygon,[{points,"220,100 300,210 170,250"},{style,"fill:#cccccc;stroke:#000000;stroke-width:1"}], []}, 376 | % {polyline,[{points,"0,0 0,20 20,20 20,40 40,40 40,60"},{style,"fill:green;stroke:red;stroke-width:2"}], []}, 377 | % {path, [{d,"M250 150 L150 350 L350 350 Z"}], []} 378 | % {path, [{d,"M153 334" ++ 379 | % "C153 334 151 334 151 334" ++ 380 | % "C151 339 153 344 156 344" ++ 381 | % "C164 344 171 339 171 334" ++ 382 | % "C171 322 164 314 156 314" ++ 383 | % "C142 314 131 322 131 334" ++ 384 | % "C131 350 142 364 156 364" ++ 385 | % "C175 364 191 350 191 334" ++ 386 | % "C191 311 175 294 156 294" ++ 387 | % "C131 294 111 311 111 334" ++ 388 | % "C111 361 131 384 156 384" ++ 389 | % "C186 384 211 361 211 334" ++ 390 | % "C211 300 186 274 156 274"}, {style,"fill:white;stroke:red;stroke-width:2"}], []}, 391 | % {defs, [ 392 | % {filter,[{id,myFilter1}],[ 393 | % {feGaussianBlur,[{in,"SourceGraphic"},{stdDeviation,3}],[]} 394 | % ]} 395 | % ]}, 396 | % {ellipse,[{cx,300},{cy,150},{rx,170},{ry,40},{style,"fill:#ff0000;stroke:#000000;stroke-width:2;filter:url(#myFilter1)"}],[]} 397 | % ]}. 398 | % 399 | % see syntactic sugar for shorter notation for circle, rect, line, ellipse, polygon, polyline, path and style (as in HTML) 400 | % 401 | % % Mostly all browsers, allows scripting 402 | % {ehtml, {embed, [{src,"plik.svg"}, 403 | % {width,300},{height,100}, 404 | % {type,"image/svg+xml"}, 405 | % {pluginpage,"http://www.adobe.com/svg/viewer/install/"} % for IE 406 | % ] 407 | % }}. 408 | % 409 | % % HTML4, but do not allows scripting 410 | % {ehtml, {object, [{data,"plik.svg"}, 411 | % {width,300},{height,100}, 412 | % {type,"image/svg+xml"}, 413 | % {codebase,"http://www.adobe.com/svg/viewer/install/"} % for IE 414 | % ] 415 | % }}. 416 | % 417 | % % Mostly all browser. 418 | % {ehtml, {iframe, [{src,"plik.svg"}, 419 | % {width,300},{height,100}]}}. 420 | % 421 | % % HTML5 (just inserts svg directly into HTML5) 422 | % {ehtml, SVG}. 423 | % 424 | % % HTML + SVG (translates svg into own namespace, for example: xmlns:svg=) 425 | % {ehtml, [{'xmlns:svg',"http://www.w3.org/2000/svg"}], {'svg:svg', SVG}}. 426 | % 427 | % 428 | % MathML: emathml % 429 | % 430 | % mi, mo, mn, mtext, ms, mspace, mglyph 431 | % mfenced, mfrac, mrow, msqrt, mroot, mstyle, merror, mpadded, mphantom, menclose 432 | % msup, msub, msubsup 433 | % munder, mover, munderover 434 | % mmultiscripts, mprescripts 435 | % mtable, mtr, mtd, maligngroup, malignmark, mlabeldtr 436 | % maction 437 | % apply, power, plus, divide, minus, times, ci, cn, compose, cos, sin, intersect, transpose, and 438 | % reln, eq, geq, leq, lt, subset 439 | % interval, vector, matrix, matrixrow 440 | % set, bvar, condition 441 | % sum, int, prod, lowlimit, uplimit 442 | % diff, partialdiff, degree 443 | % lambda, log, limit 444 | % semantics 445 | % annotation 446 | 447 | 448 | 449 | % Other templates: 450 | % 451 | % http://forum.trapexit.org/viewtopic.php?t=9342 452 | % Written By: Vladimir Sekissov, 453 | % STL as `Simple Template Language' is a clone of 454 | % Bruce R. Lewis's BRL (http://brl.sourceforge.net) 455 | % implemented in Erlang. It deals with template 456 | % processing and has most capabilities which user 457 | % expects from web template engines. 458 | % 459 | 460 | 461 | 462 | % other things too look: 463 | % glade for GTK+ 464 | % rapicorn 465 | % xrc for wxWidgets 466 | % Microsoft WFC and .NET classes 467 | 468 | --------------------------------------------------------------------------------