PageSourceSearch

https://html.spec.whatwg.org/html-dfn.js

js whatwg.org collected 2026-10-01 06:16:08 UTC 6,065 bytes, 198 lines download raw bytes

1// A fork of https://resources.whatwg.org/dfn.js which works for HTML's multipage version by using xrefs.json.
2'use strict';
3
4(function() {
5
6var isMultipage = document.documentElement.classList.contains('split');
7var dfnMapDone = false;
8var dfnMap = {};
9var dfnPanel;
10
11function isCrossSpecDfn(dfn) {
12  return dfn.firstChild && dfn.firstChild instanceof HTMLAnchorElement;
13}
14
15function handleClick(event) {
16  if (event.button !== 0) {
17    return;
18  }
19  var current = event.target;
20  var node;
21  var eventInDfnPanel = false;
22  while (current) {
23    if (current.matches(
24      "dfn, h2[data-dfn-type], h3[data-dfn-type], h4[data-dfn-type], h5[data-dfn-type], h6[data-dfn-type]"
25    )) {
26      node = current;
27    }
28    if (dfnPanel && current === dfnPanel) {
29      eventInDfnPanel = true;
30    }
31    current = current.parentElement;
32  }
33  if (!eventInDfnPanel) {
34    closePanel();
35  }
36  if (!node) {
37    return;
38  }
39  var id = node.id || node.parentNode.id;
40  var path = '';
41  if (isMultipage) {
42    path = location.pathname;
43  }
44  var specURL = '';
45  if (isCrossSpecDfn(node)) {
46    specURL = node.firstChild.href;
47    event.preventDefault();
48  }
49  loadReferences(id, path, specURL);
50  node.appendChild(dfnPanel);
51  if (isMultipage) {
52    sessionStorage.dfnId = id;
53    sessionStorage.dfnPath = path;
54    sessionStorage.dfnSpecURL = specURL;
55  }
56}
57
58function loadReferences(id, path, specURL) {
59  if (dfnPanel) {
60    dfnPanel.remove();
61    dfnPanel = null;
62  }
63  dfnPanel = createPanel(id, path, specURL);
64  var p = document.createElement('p');
65  dfnPanel.appendChild(p);
66  if (!dfnMapDone) {
67    p.textContent = 'Loading cross-references…';
68    import('./xrefs.json', { with: { type: 'json' } })
69      .then(module => {
70        dfnMap = module.default;
71        dfnMapDone = true;
72        if (dfnPanel) {
73          fillInReferences(id);
74        }
75      }).catch(err => {
76        p.textContent = 'Error loading cross-references.';
77      });
78  } else {
79    fillInReferences(id);
80  }
81}
82
83function createPanel(id, path, specURL) {
84  var panel = document.createElement('div');
85  panel.className = 'dfn-panel on';
86  if (id) {
87    var permalinkP = document.createElement('p');
88    var permalinkA = document.createElement('a');
89    permalinkA.href = path + '#' + id;
90    permalinkA.onclick = closePanel;
91    permalinkA.textContent = '#' + id;
92    permalinkP.appendChild(permalinkA);
93    panel.appendChild(permalinkP);
94  }
95  if (specURL) {
96    var realLinkP = document.createElement('p');
97    realLinkP.className = 'spec-link';
98    realLinkP.textContent = 'Spec: ';
99    var realLinkA = document.createElement('a');
100    realLinkA.href = specURL;
101    realLinkA.onclick = closePanel;
102    realLinkA.textContent = specURL;
103    realLinkP.appendChild(realLinkA);
104    panel.appendChild(realLinkP);
105  }
106  panel.dataset.id = id;
107  return panel;
108}
109
110function fillInReferences(id) {
111  var p = dfnPanel.lastChild;
112  if (id in dfnMap) {
113    p.textContent = 'Referenced in:';
114    var ul = document.createElement('ul');
115    var anchorMap = dfnMap[id];
116    for (var header in anchorMap) {
117      var li = document.createElement('li');
118      for (var i = 0; i < anchorMap[header].length; i += 1) {
119        var a = document.createElement('a');
120        a.onclick = movePanel;
121        a.href = anchorMap[header][i];
122        if (!isMultipage) {
123          a.href = a.href.substring(a.href.indexOf('#'));
124        }
125        if (i === 0) {
126          var headerFormatted = header.replace(/</g, '&lt;');
127          headerFormatted = headerFormatted.replace(/ ([^ ]+) (element(?!s)|attribute(?!s)|interface(?!s)|common interface|object)/g, ' <code>$1</code> $2');
128          headerFormatted = headerFormatted.replace(/<code>(Before|After|Other|The|on|an|for|user|User|custom|Custom|built-in|abstract|exotic|global|settings|Browser|Serializable|Transferable|HTML|IDL|document)<\/code>/, '$1');
129          headerFormatted = headerFormatted.replace(/(type=[^\)]+)/g, '<code>$1</code>');
130          headerFormatted = headerFormatted.replace(/(Link type) "([^"]+)"/g, '$1 "<code>$2</code>"');
131          headerFormatted = headerFormatted.replace(/(ImageBitmap|WindowOrWorkerGlobalScope|multipart\/x-mixed-replace|registerProtocolHandler\(\)|registerContentHandler\(\))|storage|/, '<code>$1</code>');
132          a.innerHTML = headerFormatted;
133        } else {
134          li.appendChild(document.createTextNode(' '));
135          a.appendChild(document.createTextNode('(' + (i + 1) + ')'));
136        }
137        li.appendChild(a);
138      }
139      ul.appendChild(li);
140    }
141    dfnPanel.appendChild(ul);
142  } else {
143    p.textContent = 'No references in this specification.';
144  }
145}
146
147function closePanel(event) {
148  if (dfnPanel) {
149    dfnPanel.remove();
150    dfnPanel = null;
151  }
152  if (event) {
153    event.stopPropagation();
154  }
155  if (isMultipage) {
156    delete sessionStorage.dfnId;
157    delete sessionStorage.dfnPath;
158    delete sessionStorage.dfnSpecURL;
159  }
160}
161
162function movePanel(event) {
163  if (!dfnPanel) {
164    return;
165  }
166  dfnPanel.classList.add("activated");
167  if (event) {
168    event.stopPropagation();
169  }
170}
171
172function restoreOrClosePanelOnNav(event) {
173  // Invoking this function twice is fine since on the second invocation,
174  // if the panel is open, `dfnPanel.dataset.id === id` so nothing happens;
175  // if the panel is closed, it will call `closePanel` which only clean up
176  // sessionStorage (which should already be cleared in that case).
177  if (sessionStorage.dfnId) {
178    var id = sessionStorage.dfnId;
179    var path = sessionStorage.dfnPath;
180    var specURL = sessionStorage.dfnSpecURL;
181    if (!dfnPanel || (dfnPanel && dfnPanel.dataset.id !== id)) {
182      loadReferences(id, path, specURL);
183      movePanel();
184      document.body.insertBefore(dfnPanel, document.body.firstChild);
185    }
186  } else {
187    closePanel();
188  }
189}
190
191document.addEventListener('click', handleClick);
192if (isMultipage) {
193  document.addEventListener('DOMContentLoaded', restoreOrClosePanelOnNav);
194  // Also listen for pageshow to handle history navigation without page-reload.
195  window.addEventListener('pageshow', restoreOrClosePanelOnNav);
196}
197
198})();

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.