Browse Source

various js and python improvements

Thomas B 3 weeks ago
parent
commit
39cedacba2
5 changed files with 293 additions and 33 deletions
  1. 73
    18
      macros.py
  2. 30
    2
      page.html
  3. 72
    0
      static/css/auto_toc.css
  4. 68
    13
      static/css/style.css
  5. 50
    0
      static/js/auto_toc.js

+ 73
- 18
macros.py View File

@@ -10,6 +10,20 @@ import os.path
10 10
 import time
11 11
 import codecs
12 12
 from datetime import datetime
13
+import json
14
+
15
+def print_cnsl_error(s, url = None):
16
+    sys.stderr.write("\n")
17
+    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
18
+    sys.stderr.write("warning: !!!!!!!                  WARNING                 !!!!!\n")
19
+    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
20
+    sys.stderr.write("warning: " + s + "\n")
21
+    if url != None:
22
+        sys.stderr.write("warning: URL: \"" + url + "\"\n")
23
+    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
24
+    sys.stderr.write("warning: !!!!!!!                  WARNING                 !!!!!\n")
25
+    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
26
+    sys.stderr.write("\n")
13 27
 
14 28
 # -----------------------------------------------------------------------------
15 29
 # Python 2/3 hacks
@@ -109,10 +123,16 @@ def tableHelper(style, header, content):
109 123
             print("<th>" + h + "</th>")
110 124
         print("</tr>")
111 125
     for ci in range(0, len(content)):
112
-        if len(content[ci]) != len(style):
126
+        if len(content[ci]) < len(style):
113 127
             # invalid call of table helper!
128
+            print_cnsl_error("invalid table: {}[{}] != {}", len(content[ci]), ci, len(style))
114 129
             continue
115
-        print("<tr>")
130
+
131
+        if len(content[ci]) > len(style):
132
+            print("<tr " + content[ci][len(style)] + ">")
133
+        else:
134
+            print("<tr>")
135
+
116 136
         for i in range(0, len(style)):
117 137
             s = style[i]
118 138
             td_style = ""
@@ -144,6 +164,7 @@ def tableHelper(style, header, content):
144 164
                 text = content[ci][i]
145 165
                 print(text)
146 166
             print("</td>")
167
+
147 168
         print("</tr>")
148 169
     print("</table>")
149 170
 
@@ -482,9 +503,12 @@ def lightgallery(links):
482 503
                     #img += "/default.jpg" # default thumbnail
483 504
                     style = ' style="width:300px;"'
484 505
                     img2 = '<img src="lg/video-play.png" class="picthumb">'
485
-                else:
506
+                elif link.startswith('img/'):
486 507
                     x = link.rfind('.')
487 508
                     img = link[:x] + '_small' + link[x:]
509
+                else:
510
+                    img = link
511
+                    style = ' style="max-width:300px;max-height:300px;"'
488 512
             lightgallery_check_thumbnail(link, img)
489 513
             print('<div class="border" style="position:relative;" data-src="' + link + '"><a href="' + link + '"><img class="pic" src="' + img + '" alt="' + alt + '"' + style + '>' + img2 + '</a></div>')
490 514
         elif len(l) == 5:
@@ -506,20 +530,6 @@ def lightgallery(links):
506 530
 # github helper macros
507 531
 # -----------------------------------------------------------------------------
508 532
 
509
-import json, sys
510
-
511
-def print_cnsl_error(s, url):
512
-    sys.stderr.write("\n")
513
-    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
514
-    sys.stderr.write("warning: !!!!!!!                  WARNING                 !!!!!\n")
515
-    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
516
-    sys.stderr.write("warning: " + s + "\n")
517
-    sys.stderr.write("warning: URL: \"" + url + "\"\n")
518
-    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
519
-    sys.stderr.write("warning: !!!!!!!                  WARNING                 !!!!!\n")
520
-    sys.stderr.write("warning: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
521
-    sys.stderr.write("\n")
522
-
523 533
 def http_request(url, timeout = 5):
524 534
     if PY3:
525 535
         response = urllib.request.urlopen(url, timeout = timeout)
@@ -532,7 +542,7 @@ def http_request(url, timeout = 5):
532 542
     data = response.read().decode("utf-8")
533 543
     return data
534 544
 
535
-def include_url(url, fallback = None, timeout = 2):
545
+def include_url(url, fallback = None, data_slice = None, timeout = 2):
536 546
     sys.stderr.write('sub    : fetching page "%s"\n' % url)
537 547
 
538 548
     if fallback == None:
@@ -553,6 +563,33 @@ def include_url(url, fallback = None, timeout = 2):
553 563
             print_cnsl_error(str(e), url)
554 564
             return
555 565
 
566
+    if isinstance(data_slice, tuple):
567
+        start, end = data_slice
568
+        if end < start:
569
+            print_cnsl_error("invalid slice: end={} < start={}", end, start)
570
+        else:
571
+            lines = data.split("\n")
572
+            slc = lines[max(0, start - 1) : end]
573
+            data = "\n".join(slc)
574
+            #sys.stderr.write("\n")
575
+            #sys.stderr.write("Selected Slice:\n")
576
+            #sys.stderr.write(str(len(slc)))
577
+            #sys.stderr.write("\n")
578
+            #for l in slc:
579
+            #    sys.stderr.write(l + "\n")
580
+            #sys.stderr.write("\n\n")
581
+    elif isinstance(data_slice, list):
582
+        lines = data.split("\n")
583
+        data = []
584
+        for ds in data_slice:
585
+            start, end = ds
586
+            if end < start:
587
+                print_cnsl_error("invalid slice: end={} < start={}", end, start)
588
+            else:
589
+                slc = lines[max(0, start - 1) : end]
590
+                data.append("\n".join(slc))
591
+        data = "\n\n// ...\n\n".join(data)
592
+
556 593
     if PY3:
557 594
         encoded = html.escape(data)
558 595
     else:
@@ -560,6 +597,24 @@ def include_url(url, fallback = None, timeout = 2):
560 597
 
561 598
     print(encoded, end="")
562 599
 
600
+def include_sourcecode_slice(sh_type, data_slice, filename, url_pre, fallback_pre = None, timeout = 2):
601
+    url = url_pre + filename
602
+    fallback = (fallback_pre + filename) if fallback_pre != None else None
603
+    off = data_slice[0] if data_slice != None else 1
604
+
605
+    print('<pre class="sh_' + sh_type + '" offset="' + str(off))
606
+    if isinstance(data_slice, list):
607
+        print(' skip_line_no')
608
+    print('">')
609
+
610
+    include_url(url, fallback, data_slice, timeout)
611
+
612
+    print('</pre>')
613
+    print('<p class="sh_link_upstream">Link to the complete file "<a href="' + url + '">' + url.split("/")[-1] + '</a>"')
614
+    if fallback != None:
615
+        print(' (<a href="' + fallback + '">alternative</a>)')
616
+    print('</p>')
617
+
563 618
 def restRequest(url):
564 619
     sys.stderr.write('sub    : fetching REST "%s"\n' % url)
565 620
     data = json.loads(http_request(url))

+ 30
- 2
page.html View File

@@ -11,12 +11,16 @@ else:
11 11
     <meta name="description" content="{{ htmlspecialchars(page.get("description", "Electronics & Software Projects")) }}" />
12 12
     <meta name="keywords" content="{{ htmlspecialchars(page.get("keywords", "xythobuz")) }}" />
13 13
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
14
-    <link rel="shortcut icon" href="img/favicon.ico" />
14
+    <link rel="shortcut icon" href="{{ page.get("favicon", "img/favicon.ico") }}" />
15 15
     <link rel="alternate" type="application/rss+xml" title="xythobuz.de" href="rss.xml" />
16 16
     <link type="text/css" rel="stylesheet" href="css/style.css" />
17 17
     <link type="text/css" rel="stylesheet" href="css/print.css" media="print" />
18 18
     <link type="text/css" rel="stylesheet" href="css/gh-fork-ribbon.css" />
19 19
     <link type="text/css" rel="stylesheet" href="css/lightgallery.min.css" />
20
+    <!--%
21
+        if page.get("auto_toc", "false") == "true":
22
+            print('<link type="text/css" rel="stylesheet" href="css/auto_toc.css" />')
23
+    %-->
20 24
 </head>
21 25
 <body onload="loadPage()">
22 26
     <!--%
@@ -64,6 +68,10 @@ else:
64 68
             %-->
65 69
         </ul>
66 70
     </div></div>
71
+    <!--%
72
+        if page.get("auto_toc", "false") == "true":
73
+            print('<div id="toc_wrap"></div>')
74
+    %-->
67 75
     <div id="content">
68 76
         <!--%
69 77
             from datetime import datetime
@@ -146,6 +154,9 @@ else:
146 154
         <br><span style="font-size: xx-small">
147 155
             Static HTML generated at <!--% print(datetime.now().strftime("%Y-%m-%d %H:%M:%S %z")) %-->
148 156
         </span>
157
+        <br><span style="font-size: xx-small">
158
+            <a href="<!--% print(page.get('fname').replace('./input/', '').replace('.de.md', '.md')) %-->">View Source '<!--% print(page.get("fname").replace('./input/', '').replace('.de.md', '.md')) %-->'</a>
159
+        </span>
149 160
     </div>
150 161
     <script type="text/javascript">
151 162
         function loadPage() {
@@ -155,15 +166,28 @@ else:
155 166
                 $('<div class="_sh"><div class="_sh_lines"></div></div>').insertBefore($(this));
156 167
                 $(this).appendTo($(this).prev('._sh'));
157 168
 
169
+                // allow skipping line numbers
170
+                if ($(this).attr("skip_line_no") != undefined) {
171
+                    return;
172
+                }
173
+
158 174
                 // split content of pre with linebreaks so we can get total line number
159 175
                 var content = $.trim($(this).html());
160 176
                 var lines = content.split('\n');
161 177
 
178
+                // configurable line number offset
179
+                var line_cnt_off = "1";
180
+                if ($(this).attr("offset") != undefined) {
181
+                    line_cnt_off = $(this).attr("offset");
182
+                }
183
+                var max = lines.length + parseInt(line_cnt_off);
184
+
162 185
                 // append line number to span._sh_lines
163
-                for(var line = 1; line < lines.length + 1; line++) {
186
+                for (var line = line_cnt_off; line < max; line++) {
164 187
                     $(this).prev('._sh_lines').append('<span data-line="' + line + '">' + line + '</span>');
165 188
                 }
166 189
             });
190
+
167 191
             $("pre:not([class^='sh_']):not([class='ascii'])").each(function() {
168 192
                 // wrap pre with div._sh
169 193
                 $('<div class="_sh"></div>').insertBefore($(this));
@@ -179,6 +203,10 @@ else:
179 203
         if page.get("comments", "false") == "true":
180 204
             print('<script defer src="https://comments.xythobuz.de/js/commento.js"></script>')
181 205
     %-->
206
+    <!--%
207
+        if page.get("auto_toc", "false") == "true":
208
+            print('<script defer src="js/auto_toc.js"></script>')
209
+    %-->
182 210
     <script type="text/javascript">
183 211
         $(document).ready(function() {
184 212
             jQuery(window).resize(function() {

+ 72
- 0
static/css/auto_toc.css View File

@@ -0,0 +1,72 @@
1
+#content {
2
+    counter-reset: heading;
3
+}
4
+
5
+#content h2:not(.toc):before {
6
+    content: counter(heading)") ";
7
+    counter-increment: heading;
8
+}
9
+
10
+#content h2:not(.toc) {
11
+    counter-reset: subheading;
12
+}
13
+
14
+#content h3:not(.toc):before {
15
+    content: counter(heading)"." counter(subheading)") ";
16
+    counter-increment: subheading;
17
+}
18
+
19
+#content h3:not(.toc) {
20
+    counter-reset: subsubheading;
21
+}
22
+
23
+#content h4:not(.toc):before {
24
+    content: counter(heading)"." counter(subheading)"." counter(subsubheading)") ";
25
+    counter-increment: subsubheading;
26
+}
27
+
28
+#toc {
29
+    float: right;
30
+    width: fit-content;
31
+    font-size: smaller;
32
+    padding: 0 0.5em;
33
+    border-width: 2px;
34
+    border-style: solid;
35
+    border-radius: 10px;
36
+    max-height: 50vh;
37
+    overflow: auto;
38
+}
39
+
40
+#toc_wrap {
41
+    display: none;
42
+}
43
+
44
+@media (min-width: 1000px) {
45
+    #toc_wrap {
46
+        display: block;
47
+        float: right;
48
+        position: sticky;
49
+        max-width: 12%;
50
+        top: 1em;
51
+    }
52
+}
53
+
54
+@media (min-height: 750px) {
55
+    #toc_wrap {
56
+        top: 8em;
57
+    }
58
+}
59
+
60
+@media (min-width: 1500px) {
61
+    #toc_wrap {
62
+        right: 100px;
63
+    }
64
+}
65
+
66
+#toc ul, .toc {
67
+    margin: 0.25em 0;
68
+}
69
+
70
+#toc ul {
71
+    padding-left: 1em;
72
+}

+ 68
- 13
static/css/style.css View File

@@ -90,6 +90,12 @@ a.anchor {
90 90
     }
91 91
 }
92 92
 
93
+.sh_link_upstream {
94
+    font-size: small;
95
+    padding-left: 2em;
96
+    margin-top: -0.75em
97
+}
98
+
93 99
 ._sh {
94 100
     max-height: 300px;
95 101
     overflow: auto;
@@ -337,8 +343,43 @@ blockquote p {
337 343
     margin: 0 0 0 2em;
338 344
 }
339 345
 
346
+:not(pre) > code {
347
+    padding: 0.25em 0.5em;
348
+    border-radius: 0.5em;
349
+}
350
+
351
+#nav::after {
352
+    content: "";
353
+    height: 0.25em;
354
+    width: 100%;
355
+    display: block;
356
+    border-width: 1px;
357
+    border-style: solid;
358
+    border-radius: 0.125em;
359
+}
360
+
361
+hr {
362
+    border: none;
363
+    height: 0.25em;
364
+    border-width: 1px;
365
+    border-style: solid;
366
+    border-radius: 0.125em;
367
+}
368
+
369
+#footbar {
370
+    border: none;
371
+    height: 0.25em;
372
+    border-width: 1px;
373
+    border-style: solid;
374
+    border-radius: 0.125em;
375
+}
376
+
340 377
 /* colors */
341 378
 
379
+:not(pre) > code {
380
+    background: #DEDEDE;
381
+}
382
+
342 383
 body, #nav, .collapsecontent {
343 384
     background-color: #FFFFFF;
344 385
 }
@@ -360,10 +401,7 @@ body, #nav, #nav a:link, #nav a:visited {
360 401
 }
361 402
 
362 403
 #nav::after {
363
-    content: "";
364
-    height: 0.25em;
365
-    width: 100%;
366
-    display: block;
404
+    /* pride colors https://www.flagcolorcodes.com/pride-rainbow */
367 405
     background: linear-gradient(
368 406
         to right,
369 407
         rgb(228, 3, 3) 0%,
@@ -379,15 +417,11 @@ body, #nav, #nav a:link, #nav a:visited {
379 417
         rgb(115, 41, 130) 83.25%,
380 418
         rgb(115, 41, 130) 100%
381 419
     );
382
-}
383
-
384
-._sh_lines {
385
-    border-right-color: #32CD32;
420
+    border-color: #DDDDDD;
386 421
 }
387 422
 
388 423
 hr {
389
-    border: none;
390
-    height: 0.25em;
424
+    /* bisexual colors https://www.flagcolorcodes.com/bisexual */
391 425
     background: linear-gradient(
392 426
         to right,
393 427
         rgb(214, 2, 112) 0%,
@@ -397,11 +431,11 @@ hr {
397 431
         rgb(0, 56, 168) 60%,
398 432
         rgb(0, 56, 168) 100%
399 433
     );
434
+    border-color: #DDDDDD;
400 435
 }
401 436
 
402 437
 #footbar {
403
-    border: none;
404
-    height: 0.25em;
438
+    /* transgender colors https://www.flagcolorcodes.com/transgender */
405 439
     background: linear-gradient(
406 440
         to right,
407 441
         rgb(91, 206, 250) 0%,
@@ -415,9 +449,14 @@ hr {
415 449
         rgb(91, 206, 250) 80%,
416 450
         rgb(91, 206, 250) 100%
417 451
     );
452
+    border-color: #DDDDDD;
418 453
 }
419 454
 
420
-table, th, td, ._sh, .ascii, .border, .releasecard, #index-avatar, .collapsecontent {
455
+._sh_lines {
456
+    border-right-color: #32CD32;
457
+}
458
+
459
+table, th, td, ._sh, .ascii, .border, .releasecard, #index-avatar, .collapsecontent, #toc {
421 460
     border-color: #32CD32;
422 461
 }
423 462
 
@@ -451,6 +490,10 @@ blockquote:before, blockquote:after {
451 490
     color: #444444;
452 491
 }
453 492
 
493
+#toc {
494
+    background-color: #E2E2E2;
495
+}
496
+
454 497
 /* dark mode */
455 498
 @media (prefers-color-scheme: dark) {
456 499
     body, #nav, .collapsecontent {
@@ -517,6 +560,10 @@ blockquote:before, blockquote:after {
517 560
         background-color: #424242;
518 561
     }
519 562
 
563
+    :not(pre) > code {
564
+        background: #252525;
565
+    }
566
+
520 567
     blockquote {
521 568
         background: #252525;
522 569
         border-left-color: #888888;
@@ -525,4 +572,12 @@ blockquote:before, blockquote:after {
525 572
     blockquote:before, blockquote:after {
526 573
         color: #888888;
527 574
     }
575
+
576
+    #nav::after, hr, #footbar {
577
+        border-color: #111111;
578
+    }
579
+
580
+    #toc {
581
+        background-color: #1D1D1D;
582
+    }
528 583
 }

+ 50
- 0
static/js/auto_toc.js View File

@@ -0,0 +1,50 @@
1
+function generate_toc() {
2
+    var output = '<div id="toc">';
3
+    output += '<h3 class="toc">Table of Contents</h3>';
4
+    output += '<ul>';
5
+    var level = 0;
6
+    var counters = [ 1, 1, 1 ];
7
+
8
+    $("#content").children("h2, h3, h4").each(function() {
9
+        var this_level = parseInt($(this).prop("tagName").slice(1));
10
+        if (level <= 0) level = this_level;
11
+        if (this_level > level) {
12
+            output += '<ul>';
13
+        } else if (this_level < level) {
14
+            output += '</ul>';
15
+            counters[level - 2] = 1;
16
+        }
17
+        level = this_level;
18
+
19
+        var title = '';
20
+        var link = '';
21
+        for (var lvl = 2; lvl <= this_level; lvl++) {
22
+            if (lvl > 2) {
23
+                title += ".";
24
+                link += ".";
25
+            }
26
+            title += counters[lvl - 2] - ((lvl < this_level) ? 1 : 0);
27
+            link += counters[lvl - 2] - ((lvl < this_level) ? 1 : 0);
28
+        }
29
+
30
+        title += ') ';
31
+        title += $(this).text();
32
+
33
+        link += '_';
34
+        link += $('<span>').text($(this).text().toLowerCase().split(' ').join('_')).html();
35
+
36
+        output += '<li>';
37
+        output += '<a href="#' + link + '">' + title + '</a>';
38
+        output += '</li>';
39
+
40
+        $(this).after('<a class="anchor" name="' + link + '"></a>')
41
+
42
+        counters[this_level - 2]++;
43
+    });
44
+
45
+    output += '</ul>';
46
+    output += '</div>';
47
+    $("#toc_wrap").html(output);
48
+}
49
+
50
+generate_toc();

Loading…
Cancel
Save