PageSourceSearch

https://cs-uob.github.io/options/manual-racket.js

js cs-uob.github.io collected 2026-10-03 08:50:24 UTC 9,651 bytes, 268 lines download raw bytes

1/* For the Racket manual style */
2
3AddOnLoad(function() {
4    /* Look for header elements that have x-source-module and x-part tag.
5       For those elements, add a hidden element that explains how to
6       link to the section, and set the element's onclick() to display
7       the explanation. */
8    var tag_names = ["h1", "h2", "h3", "h4", "h5"];
9    for (var j = 0; j < tag_names.length; j++) {
10        elems = document.getElementsByTagName(tag_names[j]);
11        for (var i = 0; i < elems.length; i++) {
12            var elem = elems.item(i);
13            AddPartTitleOnClick(elem);
14        }
15    }
16})
17
18// for copies that start in Racket code, strip out extra newlines
19AddOnLoad(function() {
20  const codeBlocks = document.getElementsByClassName("SCodeFlow");
21  for (var i = 0; i < codeBlocks.length; i++) {
22    var codeBlock = codeBlocks[i];
23    console.log("add");
24    codeBlock.addEventListener('copy', function(e) {
25      var selection = window.getSelection();
26      var text = selection.toString();
27      var codeText = text.replace(/\n\n/g, '\n');
28      if (text != codeText) {
29        e.preventDefault();
30        e.clipboardData.setData('text/plain', codeText);
31      }
32    })
33  }
34})
35
36// cache of source urls
37var cache = {};
38
39function ParseSource(source, mod_path, single_collection) {
40
41    var source_url = new URL(source);
42
43    if (source_url.protocol == "github:") {
44        // browser URL parser only works with http(s) URLs
45        source_url = new URL("https" + source.substring(6));
46        var host = source_url.host;
47        var url_path = source_url.pathname.substring(1).split("/");
48        if (!(url_path.length >= 2)) return null;
49        var user = url_path.shift();
50        var repo = url_path.shift();
51        var branch = url_path.shift();
52        var source_path = url_path.join("/");
53    }
54    else if (("https:" == source_url.protocol) || ("git:" == source_url.protocol)) {
55        // browser URL parser only works with http(s) URLs
56        if ("git:" == source_url.protocol)
57            source_url = new URL("https" + source.substring(3));
58
59        var host = source_url.host;
60        var source_path = source_url.searchParams.get("path");
61        var branch = (source_url.hash || "#master").substring(1);
62        var url_path = source_url.pathname.substring(1).split("/");
63        if (url_path.length < 2) throw [source_url.pathname, url_path];
64        var user = url_path.shift();
65        var repo = url_path.shift();
66        var mtch = repo.match(/(.*)\.git$/);
67        if (mtch) repo = mtch[1];
68
69    }
70    else return null;
71
72    var mod_path_re = /^\(lib "(.+)"\)$/;
73
74    var mod_path_elems = mod_path && mod_path.match(mod_path_re)[1].split("/");
75
76    if (!user || !repo || !mod_path_elems)
77        return null;
78    if (single_collection)
79        mod_path_elems.shift();
80
81    var file_path = mod_path_elems.join("/");
82
83
84    if (source_path) {
85        file_path = source_path + "/" + file_path;
86    }
87
88    return { user: user,
89             repo: repo,
90             file_path: file_path,
91             branch: branch,
92             host: host };
93}
94
95function AddSourceElement(pkg_url, info) {
96    info.appendChild(document.createTextNode("Document source "));
97    var url_line = document.createElement("div");
98    var a = document.createElement("a");
99    a.href = pkg_url;
100    a.style.whiteSpace = "nowrap";
101    a.appendChild(document.createTextNode(pkg_url));
102    addSpan(url_line, "\xA0", "RktRdr");
103    url_line.appendChild(a);
104    info.appendChild(url_line);
105}
106
107var prefixes = { "github.com": "tree",
108                 "gitlab.com": "-/blob" };
109
110
111function AddSourceUrl(source, mod_path, collection, info) {
112    // multi is encoded as an array, empty as false
113    single_collection = (typeof collection === "string");
114
115    var parsed = source && mod_path && ParseSource(source, mod_path, single_collection);
116
117    if (!parsed) return;
118
119    prefix = prefixes.hasOwnProperty(parsed.host) && prefixes[parsed.host];
120    if (!prefix) return;
121
122    var correct_url = "https://" + [parsed.host, parsed.user, parsed.repo, prefix, parsed.branch, parsed.file_path].join("/");
123
124    if (info) AddSourceElement(correct_url, info);
125}
126
127function addSpan(dest, str, cn) {
128    var s = document.createElement("span");
129    s.className = cn;
130    s.style.whiteSpace = "nowrap";
131    s.appendChild(document.createTextNode(str));
132    dest.appendChild(s);
133}
134
135
136// test cases
137if (false) {
138    console.log(ParseSource("git://gitlab.com/benn/foo?path=xxx",
139                            '(lib "asn1/scribblings/asn1.scrbl")',
140                            false))
141    console.log(ParseSource("github://github.com/carl-eastlund/mischief/master",
142                            '(lib "asn1/scribblings/asn1.scrbl")',
143                            false))
144    console.log(ParseSource("github://github.com/carl-eastlund/mischief/stable/dir",
145                            '(lib "asn1/scribblings/asn1.scrbl")',
146                            false))
147
148    console.log(ParseSource("git://github.com/racket/racket/?path=pkgs/racket-doc",
149                            '(lib "asn1/scribblings/asn1.scrbl")',
150                            false));
151
152    console.log(ParseSource("git://github.com/rmculpepper/asn1.git?path=asn1-doc",
153                            '(lib "asn1/scribblings/asn1.scrbl")',
154                            true));
155    console.log(ParseSource("git://github.com/rmculpepper/asn1",
156                            '(lib "asn1/scribblings/asn1.scrbl")',
157                            true));
158    console.log(ParseSource("git://github.com/rmculpepper/asn1",
159                            '(lib "asn1/scribblings/asn1.scrbl")',
160                            false));
161}
162
163function AddPartTitleOnClick(elem) {
164    var mod_path = elem.getAttribute("x-source-module");
165    var tag = elem.getAttribute("x-part-tag");
166    var source_pkg = elem.getAttribute("x-source-pkg");
167
168    // create here to share
169    var info = document.createElement("div");
170
171
172    // tag is not needed, but this way we can add the element in only one place
173    // avoid failing on browser that don't have `fetch`
174    if (mod_path && source_pkg && tag && window.fetch) {
175
176        var cached = cache[mod_path]
177        if (cached) {
178            AddSourceElement(cached[0], mod_path, cached[1], info);
179        }
180        else {
181            fetch("https://pkgs.racket-lang.org/pkg/" + source_pkg + ".json")
182                .then(function (response) { return response.json(); })
183                .then(function (data) {
184                    var vers = data["versions"] || {};
185                    var def = vers["default"] || {};
186                    var source = def["source"] || undefined;
187                    var collection = data["collection"];
188                    if (source) {
189                        cache[mod_path] = [source, collection];
190                        AddSourceUrl(source, mod_path, collection, info);
191                    }
192                });
193        }
194    }
195
196    if (mod_path && tag) {
197        // Might not be present:
198        var prefixes = elem.getAttribute("x-part-prefixes");
199
200        info.className = "RPartExplain";
201
202        /* The "top" tag refers to a whole document: */
203        var is_top = (tag == "\"top\"");
204        info.appendChild(document.createTextNode("Link to this "
205                                                 + (is_top ? "document" : "section")
206                                                 + " with "));
207
208        /* Break `secref` into two lines if the module path and tag
209           are long enough: */
210        var is_long = (is_top ? false : ((mod_path.length
211                                          + tag.length
212                                          + (prefixes ? (16 + prefixes.length) : 0))
213                                         > 60));
214
215        var line1 = document.createElement("div");
216        var line1x = ((is_long && prefixes) ? document.createElement("div") : line1);
217        var line2 = (is_long ? document.createElement("div") : line1);
218
219        /* Construct a `secref` call with suitable syntax coloring: */
220        addSpan(line1, "\xA0@", "RktRdr");
221        addSpan(line1, (is_top ? "other-doc" : "secref"), "RktSym");
222        addSpan(line1, "[", "RktPn");
223        if (!is_top)
224            addSpan(line1, tag, "RktVal");
225        if (is_long) {
226            /* indent additional lines: */
227            if (prefixes)
228                addSpan(line1x, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0", "RktPn");
229            addSpan(line2, "\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xA0", "RktPn");
230        }
231        if (prefixes) {
232            addSpan(line1x, " #:tag-prefixes ", "RktPn");
233            addSpan(line1x, "'", "RktVal");
234            addSpan(line1x, prefixes, "RktVal");
235        }
236        if (!is_top)
237            addSpan(line2, " #:doc ", "RktPn");
238        addSpan(line2, "'", "RktVal");
239        addSpan(line2, mod_path, "RktVal");
240        addSpan(line2, "]", "RktPn");
241
242        info.appendChild(line1);
243        if (is_long)
244            info.appendChild(line1x);
245        if (is_long)
246            info.appendChild(line2);
247
248        info.style.display = "none";
249
250        /* Add the new element afterthe header: */
251        var n = elem.nextSibling;
252        if (n)
253            elem.parentNode.insertBefore(info, n);
254        else
255            elem.parentNode.appendChild(info);
256
257        /* Clicking the information button shows the explanation element: */
258        const heading = elem.querySelector('.heading-source');
259        if (heading) {
260          heading.onclick = function () {
261            if (info.style.display === "none")
262                info.style.display = "block";
263            else
264                info.style.display = "none";
265          }
266        }
267    }
268}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.