Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From d88444e265f3f78f To 67060c509079a8b7
2020-09-17
| ||
23:44 | pikchr command doc updates. (check-in: 82a0b517 user: stephan tags: trunk) | |
23:25 | Removed some console.debug() output and fixed extraneous breaks which caused markdown_to_html() to stop afer processing a single tag. (check-in: 67060c50 user: stephan tags: trunk) | |
23:11 | Renovated the pikchr click handling as discussed off-list with drh. (check-in: 938bb6c7 user: stephan tags: trunk) | |
21:09 | Toggle Pikchr between SVG and source code using ctrl-click. Or if the Pikchr was created using the "toggle" tag, an plain old single-click will suffice. (check-in: d88444e2 user: drh tags: trunk) | |
19:31 | Misuse of a potentially unsigned value, caught by clang. Only affected platforms where char is unsigned by default. (check-in: 5c92bbfc user: stephan tags: trunk) | |
Changes to src/default.css.
︙ | ︙ | |||
1386 1387 1388 1389 1390 1391 1392 | noscript > .error { /* Part of the style_emit_noscript_for_js_page() interface. */ padding: 1em; font-size: 150%; } .pikchr-src { /* source code view for a pikchr (see fossil.pikchr.js) */ box-sizing: border-box/*reduces UI shift*/; | < < | 1386 1387 1388 1389 1390 1391 1392 1393 1394 | noscript > .error { /* Part of the style_emit_noscript_for_js_page() interface. */ padding: 1em; font-size: 150%; } .pikchr-src { /* source code view for a pikchr (see fossil.pikchr.js) */ box-sizing: border-box/*reduces UI shift*/; overflow: auto; } |
Changes to src/fossil.dom.js.
︙ | ︙ | |||
711 712 713 714 715 716 717 | }; /** Parses a string as HTML. Usages: | | | | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | }; /** Parses a string as HTML. Usages: Array (htmlString) DOMElement (DOMElement target, htmlString) The first form parses the string as HTML and returns an Array of all elements parsed from it. If string is falsy then it returns an empty array. The second form parses the HTML string and appends all elements to the given target element using dom.append(), then returns the |
︙ | ︙ |
Changes to src/fossil.page.pikchrshow.js.
︙ | ︙ | |||
320 321 322 323 324 325 326 | D.enable(this.e.previewModeToggle, this.e.markupAlignRadios); let label, svg; switch(this.previewMode){ case 0: label = "SVG"; f.showMarkupAlignment(false); D.parseHtml(D.clearElement(preTgt), P.response.raw); | | > | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | D.enable(this.e.previewModeToggle, this.e.markupAlignRadios); let label, svg; switch(this.previewMode){ case 0: label = "SVG"; f.showMarkupAlignment(false); D.parseHtml(D.clearElement(preTgt), P.response.raw); svg = preTgt.querySelector('svg.pikchr'); if(svg){ /*for copy button*/ this.e.taPreviewText.value = svg.outerHTML; F.pikchr.addSrcView(svg); } break; case 1: label = "Markdown"; f.showMarkupAlignment(true); this.e.taPreviewText.value = [ '```pikchr'+f.getMarkupAlignmentClass(), |
︙ | ︙ |
Changes to src/fossil.pikchr.js.
1 2 | (function(F/*window.fossil object*/){ "use strict"; | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | < | < < < | < | < < > < < < < > > > > > | | | > > > > > > | > > > > < | | < < | < | | < > | < < < < < | < < < < < < | < | | < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | (function(F/*window.fossil object*/){ "use strict"; const D = F.dom, P = F.pikchr = {}; /** Initializes pikchr-rendered elements with the ability to toggle between their SVG and source code. The first argument may be any of: - A single SVG.pikchr element. - A collection (with a forEach method) of such elements. - A CSS selector string for one or more such elements. - An array of such strings. Passing no value is equivalent to passing 'svg.pikchr'. For each SVG in the resulting set, this function sets up event handlers which allow the user to toggle the SVG between image and source code modes. The image will switch modes in response to cltr-click and, if its *parent* element has the "toggle" CSS class, it will also switch modes in response to single-click. If the parent element has the "source" CSS class, the image starts off with its source code visible and the image hidden, instead of the default of the other way around. Returns this object. Each element will only be processed once by this routine, even if it is passed to this function multiple times. Each processed element gets a "data" attribute set to it to indicate that it was already dealt with. This code expects the following structure around the SVGs, and will not process any which don't match this: <DIV><SVG.pikchr></SVG><PRE.pikchr-src></PRE></DIV> */ P.addSrcView = function f(svg){ if(!f.hasOwnProperty('parentClick')){ f.parentClick = function(ev){ if(ev.ctrlKey || this.classList.contains('toggle')){ this._childs.forEach((e)=>e.classList.toggle('hidden')); } /* For the sake of small pics, we have to eliminate the parent element's max-width... */ const src = this._childs[1]; if(src.classList.contains('hidden')){ this.style.maxWidth = this.dataset.origMaxWidth; }else{ this.style.maxWidth = "unset"; } }; }; if(!svg) svg = 'svg.pikchr'; if('string' === typeof svg){ document.querySelectorAll(svg).forEach((e)=>f.call(this, e)); return this; }else if(svg.forEach){ svg.forEach((e)=>f.call(this, e)); return this; } if(svg.dataset.pikchrProcessed){ return this; } svg.dataset.pikchrProcessed = 1; const parent = svg.parentNode; const srcView = svg.nextElementSibling; if(!srcView || !srcView.classList.contains('pikchr-src')){ /* Without this element, there's nothing for us to do here. */ return this; } parent.dataset.origMaxWidth = parent.style.maxWidth; parent._childs = [svg, srcView]; D.addClass(srcView, 'hidden'); D.removeClass(svg, 'hidden'); parent.addEventListener('click', f.parentClick, false); if(parent.classList.contains('source')){ /* Start off in source-view mode via a very fake click event */ f.parentClick.call(parent, {ctrlKey:true}); } }; })(window.fossil); |
Changes to src/markdown_html.c.
︙ | ︙ | |||
340 341 342 343 344 345 346 | ** text and insert the result in place of the original. */ void pikchr_to_html( Blob *ob, /* Write the generated SVG here */ const char *zSrc, int nSrc, /* The Pikchr source text */ const char *zArg, int nArg /* Addition arguments */ ){ | | | | < < < < < | | | | | | < > | < > | < > | < > | < > > > | | | | | < < < < < < < < | < < < < < < < < > | < < < < < < | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | ** text and insert the result in place of the original. */ void pikchr_to_html( Blob *ob, /* Write the generated SVG here */ const char *zSrc, int nSrc, /* The Pikchr source text */ const char *zArg, int nArg /* Addition arguments */ ){ int pikFlags = PIKCHR_PROCESS_NONCE | PIKCHR_PROCESS_DIV | PIKCHR_PROCESS_SRC_HIDDEN; Blob bSrc = empty_blob; while( nArg>0 ){ int i; for(i=0; i<nArg && !fossil_isspace(zArg[i]); i++){} if( i==6 && strncmp(zArg, "center", 6)==0 ){ pikFlags |= PIKCHR_PROCESS_DIV_CENTER; }else if( i==6 && strncmp(zArg, "indent", 6)==0 ){ pikFlags |= PIKCHR_PROCESS_DIV_INDENT; }else if( i==10 && strncmp(zArg, "float-left", 10)==0 ){ pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_LEFT; }else if( i==11 && strncmp(zArg, "float-right", 11)==0 ){ pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_RIGHT; }else if( i==6 && strncmp(zArg, "toggle", 6)==0 ){ pikFlags |= PIKCHR_PROCESS_DIV_TOGGLE; }else if( i==6 && strncmp(zArg, "source", 6)==0 ){ pikFlags |= PIKCHR_PROCESS_DIV_SOURCE; } while( i<nArg && fossil_isspace(zArg[i]) ){ i++; } zArg += i; nArg -= i; } blob_append(&bSrc, zSrc, nSrc) /*have to dup input to ensure a NUL-terminated source string */; pikchr_process(blob_str(&bSrc), pikFlags, 0, ob); blob_reset(&bSrc); } /* Invoked for `...` blocks where there are nSep grave accents in a ** row that serve as the delimiter. According to CommonMark: ** ** * https://spec.commonmark.org/0.29/#fenced-code-blocks ** * https://spec.commonmark.org/0.29/#code-spans ** |
︙ | ︙ |
Changes to src/pikchrshow.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 38 39 40 | #define PIKCHR_PROCESS_SRC 0x10 #define PIKCHR_PROCESS_SRC_HIDDEN 0x20 #define PIKCHR_PROCESS_DIV 0x40 #define PIKCHR_PROCESS_DIV_INDENT 0x0100 #define PIKCHR_PROCESS_DIV_CENTER 0x0200 #define PIKCHR_PROCESS_DIV_FLOAT_LEFT 0x0400 #define PIKCHR_PROCESS_DIV_FLOAT_RIGHT 0x0800 #endif /* | > > | > | | | | | | | | > > > > > > > > > > > > | > > | | | | > > | | > > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #define PIKCHR_PROCESS_SRC 0x10 #define PIKCHR_PROCESS_SRC_HIDDEN 0x20 #define PIKCHR_PROCESS_DIV 0x40 #define PIKCHR_PROCESS_DIV_INDENT 0x0100 #define PIKCHR_PROCESS_DIV_CENTER 0x0200 #define PIKCHR_PROCESS_DIV_FLOAT_LEFT 0x0400 #define PIKCHR_PROCESS_DIV_FLOAT_RIGHT 0x0800 #define PIKCHR_PROCESS_DIV_TOGGLE 0x1000 #define PIKCHR_PROCESS_DIV_SOURCE 0x2000 #endif /* ** Processes a pikchr script, optionally with embedded TH1, and ** produces HTML code for it. zIn is the NUL-terminated input ** script. pikFlags may be a bitmask of any of the PIKCHR_PROCESS_xxx ** flags documented below. thFlags may be a bitmask of any of the ** TH_INIT_xxx and/or TH_R2B_xxx flags. Output is sent to pOut, ** appending to it without modifying any prior contents. ** ** Returns 0 on success, 1 if TH1 processing failed, or 2 if pikchr ** processing failed. In either case, the error message (if any) from ** TH1 or pikchr will be appended to pOut. ** ** pikFlags flag descriptions: ** ** - PIKCHR_PROCESS_TH1 means to run zIn through TH1, using the TH1 ** init flags specified in the 3rd argument. If thFlags is non-0 then ** this flag is assumed even if it is not specified. ** ** - PIKCHR_PROCESS_TH1_NOSVG means that processing stops after the ** TH1 eval step, thus the output will be (presumably) a ** TH1-generated/processed pikchr script (or whatever else the TH1 ** outputs). If this flag is set, PIKCHR_PROCESS_TH1 is assumed even ** if it is not specified. ** ** All of the remaining flags listed below are ignored if ** PIKCHR_PROCESS_TH1_NOSVG is specified! ** ** - PIKCHR_PROCESS_DIV: if set, the SVG result is wrapped in a DIV ** element which specifies a max-width style value based on the SVG's ** calculated size. This flag has multiple mutually exclusive forms: ** ** - PIKCHR_PROCESS_DIV uses default element alignment. ** - PIKCHR_PROCESS_DIV_INDENT indents the div. ** - PIKCHR_PROCESS_DIV_CENTER centers the div. ** - PIKCHR_PROCESS_DIV_FLOAT_LEFT floats the div left. ** - PIKCHR_PROCESS_DIV_FLOAT_RIGHT floats the div right. ** ** If more than one is specified, which one is used is undefined. Those ** flags may be OR'd with one or both of the following: ** ** - PIKCHR_PROCESS_DIV_TOGGLE: adds the 'toggle' CSS class to the ** outer DIV so that event-handler code can install different ** toggling behaviour than the default. Default is ctrl-click, but ** this flag enables single-click toggling for the element. ** ** - PIKCHR_PROCESS_DIV_SOURCE: adds the 'source' CSS class to the ** outer DIV, which is a hint to the client-side renderer (see ** fossil.pikchr.js) that the pikchr should initially be rendered ** in source code form mode (the default is to hide the source and ** show the SVG). ** ** - PIKCHR_PROCESS_NONCE: if set, the resulting SVG/DIV are wrapped ** in "safe nonce" comments, which are a fossil-internal mechanism ** which prevents the wiki/markdown processors from re-processing this ** output. This is necessary when calling this routine in the context ** of wiki/embedded doc processing, but not (e.g.) when fetching ** an image for /pikchrpage. ** ** - PIKCHR_PROCESS_SRC: if set, a new PRE.pikchr-src element is ** injected adjacent to the SVG element which contains the ** HTML-escaped content of the input script. ** ** - PIKCHR_PROCESS_SRC_HIDDEN: exactly like PIKCHR_PROCESS_SRC but ** the .pikchr-src tag also gets the CSS class 'hidden' (which, in ** fossil's default CSS, will hide that element). This is almost ** always what client code will want to do if it includes the source ** at all. ** ** - PIKCHR_PROCESS_ERR_PRE: if set and pikchr() fails, the resulting ** error report is wrapped in a PRE element, else it is retained ** as-is (intended only for console output). */ int pikchr_process(const char * zIn, int pikFlags, int thFlags, Blob * pOut){ Blob bIn = empty_blob; int isErr = 0; if(!(PIKCHR_PROCESS_DIV & pikFlags) /* If any DIV_xxx flags are set, set DIV */ && (PIKCHR_PROCESS_DIV_INDENT | PIKCHR_PROCESS_DIV_CENTER | PIKCHR_PROCESS_DIV_FLOAT_RIGHT | PIKCHR_PROCESS_DIV_FLOAT_LEFT | PIKCHR_PROCESS_DIV_SOURCE | PIKCHR_PROCESS_DIV_TOGGLE ) & pikFlags){ pikFlags |= PIKCHR_PROCESS_DIV; } if(!(PIKCHR_PROCESS_TH1 & pikFlags) /* If any TH1_xxx flags are set, set TH1 */ && (PIKCHR_PROCESS_TH1_NOSVG & pikFlags || thFlags!=0)){ pikFlags |= PIKCHR_PROCESS_TH1; |
︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | }else{ int w = 0, h = 0; const char * zContent = blob_str(&bIn); char *zOut; zOut = pikchr(zContent, "pikchr", 0, &w, &h); if( w>0 && h>0 ){ const char *zNonce = (PIKCHR_PROCESS_NONCE & pikFlags) ? safe_html_nonce(1) : 0; if(zNonce){ blob_append(pOut, zNonce, -1); } if(PIKCHR_PROCESS_DIV & pikFlags){ Blob css = empty_blob; blob_appendf(&css, "max-width:%dpx;", w); if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){ blob_append(&css, "display:block;margin-auto;", -1); }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){ blob_append(&css, "margin-left:4em", -1); }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){ blob_append(&css, "float:left;padding=4em;", -1); }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){ blob_append(&css, "float:right;padding=4em;", -1); } | > > > > > > > > | > > > < | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | }else{ int w = 0, h = 0; const char * zContent = blob_str(&bIn); char *zOut; zOut = pikchr(zContent, "pikchr", 0, &w, &h); if( w>0 && h>0 ){ const char * zClassToggle = ""; const char * zClassSource = ""; const char *zNonce = (PIKCHR_PROCESS_NONCE & pikFlags) ? safe_html_nonce(1) : 0; if(zNonce){ blob_append(pOut, zNonce, -1); } if(PIKCHR_PROCESS_DIV & pikFlags){ Blob css = empty_blob; blob_appendf(&css, "max-width:%dpx;", w); if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){ blob_append(&css, "display:block;margin-auto;", -1); }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){ blob_append(&css, "margin-left:4em", -1); }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){ blob_append(&css, "float:left;padding=4em;", -1); }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){ blob_append(&css, "float:right;padding=4em;", -1); } if(PIKCHR_PROCESS_DIV_TOGGLE & pikFlags){ zClassToggle = " toggle"; } if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ zClassSource = " source"; } blob_appendf(pOut,"<div class=\"pikchr-svg%s%s\" " "style=\"%b\">\n", zClassToggle/*safe-for-%s*/, zClassSource/*safe-for-%s*/, &css); blob_reset(&css); } blob_append(pOut, zOut, -1); if((PIKCHR_PROCESS_SRC & pikFlags) || (PIKCHR_PROCESS_SRC_HIDDEN & pikFlags)){ blob_appendf(pOut, "<pre class='pikchr-src%s'>" "%h</pre>\n", (PIKCHR_PROCESS_SRC_HIDDEN & pikFlags) ? " hidden" : "", blob_str(&bIn)); } if(PIKCHR_PROCESS_DIV & pikFlags){ blob_append(pOut, "</div>\n", 7); } |
︙ | ︙ | |||
355 356 357 358 359 360 361 | ** ** -div-center Like -div but centers the div. ** ** -div-left Like -div but floats the div left. ** ** -div-right Like -div but floats the div right. ** | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | ** ** -div-center Like -div but centers the div. ** ** -div-left Like -div but floats the div left. ** ** -div-right Like -div but floats the div right. ** ** -src Stores the input pikchr's source code in the output as ** a separate element adjacent to the SVG one. The ** source element initially has the "hidden" CSS class. ** ** -th Process the input using TH1 before passing it to pikchr. ** ** -th-novar Disable $var and $<var> TH1 processing. Use this if the ** pikchr script uses '$' for its own purposes and that |
︙ | ︙ | |||
397 398 399 400 401 402 403 | Blob bIn = empty_blob; Blob bOut = empty_blob; const char * zInfile = "-"; const char * zOutfile = "-"; const int fTh1 = find_option("th",0,0)!=0; const int fNosvg = find_option("th-nosvg",0,0)!=0; int isErr = 0; | | > > > > > > | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | Blob bIn = empty_blob; Blob bOut = empty_blob; const char * zInfile = "-"; const char * zOutfile = "-"; const int fTh1 = find_option("th",0,0)!=0; const int fNosvg = find_option("th-nosvg",0,0)!=0; int isErr = 0; int pikFlags = find_option("src",0,0)!=0 ? PIKCHR_PROCESS_SRC_HIDDEN : 0; u32 fThFlags = TH_INIT_NO_ENCODE | (find_option("th-novar",0,0)!=0 ? TH_R2B_NO_VARS : 0); Th_InitTraceLog()/*processes -th-trace flag*/; if(find_option("div",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV; }else if(find_option("div-indent",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV_INDENT; }else if(find_option("div-center",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV_CENTER; }else if(find_option("div-float-left",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_LEFT; }else if(find_option("div-float-right",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV_FLOAT_RIGHT; } if(find_option("div-toggle",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV_TOGGLE; } if(find_option("div-source",0,0)!=0){ pikFlags |= PIKCHR_PROCESS_DIV_SOURCE; } verify_all_options(); if(g.argc>4){ usage("?INFILE? ?OUTFILE?"); } if(g.argc>2){ zInfile = g.argv[2]; |
︙ | ︙ |