PageSourceSearch

http://infobureau.work/wiki/uta_macross/skin/main.js

js infobureau.work collected 2026-10-07 14:16:28 UTC 20,540 bytes, 609 lines download raw bytes

1// PukiWiki - Yet another WikiWikiWeb clone.
2// main.js
3// Copyright 2017-2019 PukiWiki Development Team
4// License: GPL v2 or (at your option) any later version
5//
6// PukiWiki JavaScript client script
7window.addEventListener && window.addEventListener('DOMContentLoaded', function() { // eslint-disable-line no-unused-expressions
8  'use strict';
9  /**
10   * @param {NodeList} nodeList
11   * @param {function(Node, number): void} func
12   */
13  function forEach(nodeList, func) {
14    if (nodeList.forEach) {
15      nodeList.forEach(func);
16    } else {
17      for (var i = 0, n = nodeList.length; i < n; i++) {
18        func(nodeList[i], i);
19      }
20    }
21  }
22  // Name for comment
23  function setYourName() {
24    var NAME_KEY_ID = 'pukiwiki_comment_plugin_name';
25    var actionPathname = null;
26    function getPathname(formAction) {
27      if (actionPathname) return actionPathname;
28      try {
29        var u = new URL(formAction, document.location);
30        var u2 = new URL('./', u);
31        actionPathname = u2.pathname;
32        return u2.pathname;
33      } catch (e) {
34        // Note: Internet Explorer doesn't support URL class
35        var m = formAction.match(/^https?:\/\/([^/]+)(\/([^?&]+\/)?)/);
36        if (m) {
37          actionPathname = m[2]; // pathname
38        } else {
39          actionPathname = '/';
40        }
41        return actionPathname;
42      }
43    }
44    function getNameKey(form) {
45      var pathname = getPathname(form.action);
46      var key = 'path.' + pathname + '.' + NAME_KEY_ID;
47      return key;
48    }
49    function getForm(element) {
50      if (element.form && element.form.tagName === 'FORM') {
51        return element.form;
52      }
53      var e = element.parentElement;
54      for (var i = 0; i < 5; i++) {
55        if (e.tagName === 'FORM') {
56          return e;
57        }
58        e = e.parentElement;
59      }
60      return null;
61    }
62    function handleCommentPlugin(form) {
63      var namePrevious = '';
64      var nameKey = getNameKey(form);
65      if (typeof localStorage !== 'undefined') {
66        namePrevious = localStorage[nameKey];
67      }
68      var onFocusForm = function () {
69        if (form.name && !form.name.value && namePrevious) {
70          form.name.value = namePrevious;
71        }
72      };
73      var addOnForcusForm = function(eNullable) {
74        if (!eNullable) return;
75        if (eNullable.addEventListener) {
76          eNullable.addEventListener('focus', onFocusForm);
77        }
78      };
79      if (namePrevious) {
80        var textList = form.querySelectorAll('input[type=text],textarea');
81        textList.forEach(function (v) {
82          addOnForcusForm(v);
83        });
84      }
85      form.addEventListener('submit', function() {
86        if (typeof localStorage !== 'undefined') {
87          localStorage[nameKey] = form.name.value;
88        }
89      }, false);
90    }
91    function setNameForComment() {
92      if (!document.querySelectorAll) return;
93      var elements = document.querySelectorAll(
94        'input[type=hidden][name=plugin][value=comment],' +
95        'input[type=hidden][name=plugin][value=pcomment],' +
96        'input[type=hidden][name=plugin][value=article],' +
97        'input[type=hidden][name=plugin][value=bugtrack]');
98      for (var i = 0; i < elements.length; i++) {
99        var form = getForm(elements[i]);
100        if (form) {
101          handleCommentPlugin(form);
102        }
103      }
104    }
105    setNameForComment();
106  }
107  // AutoTicketLink
108  function autoTicketLink() {
109    var headReText = '([\\s\\b:\\[\\(,;]|^)';
110    var tailReText = '\\b';
111    var ignoreTags = ['A', 'INPUT', 'TEXTAREA', 'BUTTON',
112      'SCRIPT', 'FRAME', 'IFRAME'];
113    var ticketSiteList = [];
114    var jiraProjects = null;
115    var jiraDefaultInfo = null;
116    function regexEscape(key) {
117      return key.replace(/[-.]/g, function (m) {
118        return '\\' + m;
119      });
120    }
121    function setupSites(siteList) {
122      for (var i = 0, length = siteList.length; i < length; i++) {
123        var site = siteList[i];
124        var reText = '';
125        switch (site.type) {
126          case 'jira':
127            reText = '(' + regexEscape(site.key) +
128              '):([A-Z][A-Z0-9]{1,20}(?:_[A-Z0-9]{1,10}){0,2}-\\d{1,10})';
129            break;
130          case 'redmine':
131            reText = '(' + regexEscape(site.key) + '):(\\d{1,10})';
132            break;
133          case 'git':
134            reText = '(' + regexEscape(site.key) + '):([0-9a-f]{7,40})';
135            break;
136          default:
137            continue;
138        }
139        site.reText = reText;
140        site.re = new RegExp(headReText + reText + tailReText);
141      }
142    }
143    function getJiraSite() {
144      var reText = '()([A-Z][A-Z0-9]{1,20}(?:_[A-Z0-9]{1,10}){0,2}-\\d{1,10})';
145      var site = {
146        title: 'Builtin JIRA',
147        type: '_jira_',
148        key: '_jira_',
149        reText: reText,
150        re: new RegExp(headReText + reText + tailReText)
151      };
152      return site;
153    }
154    function getSiteListFromBody() {
155      var defRoot = document.querySelector('#pukiwiki-site-properties .ticketlink-def');
156      if (defRoot && defRoot.value) {
157        var list = JSON.parse(defRoot.value);
158        setupSites(list);
159        return list;
160      }
161      return [];
162    }
163    function getJiraProjectsFromBody() {
164      var defRoot = document.querySelector('#pukiwiki-site-properties .ticketlink-jira-def');
165      if (defRoot && defRoot.value) {
166        try {
167          return JSON.parse(defRoot.value); // List
168        } catch (e) {
169          return null;
170        }
171      }
172      return null;
173    }
174    function getJiraDefaultInfoFromBody() {
175      var defRoot = document.querySelector('#pukiwiki-site-properties .ticketlink-jira-default-def');
176      if (defRoot && defRoot.value) {
177        try {
178          return JSON.parse(defRoot.value); // object
179        } catch (e) {
180          return null;
181        }
182      }
183      return null;
184    }
185    function getSiteList() {
186      return ticketSiteList;
187    }
188    function getJiraProjectList() {
189      return jiraProjects;
190    }
191    function getDefaultJira() {
192      return jiraDefaultInfo;
193    }
194    function ticketToLink(keyText) {
195      var siteList = getSiteList();
196      for (var i = 0; i < siteList.length; i++) {
197        var site = siteList[i];
198        var m = keyText.match(site.re);
199        if (m) {
200          var ticketKey = m[3];
201          var title = ticketKey;
202          var ticketUrl;
203          if (site.type === '_jira_') {
204            // JIRA issue
205            var projects = getJiraProjectList();
206            var hyphen = keyText.indexOf('-');
207            if (hyphen > 0) {
208              var projectKey = keyText.substr(0, hyphen);
209              if (projects) {
210                for (var j = 0; j < projects.length; j++) {
211                  var p = projects[j];
212                  if (p.key === projectKey) {
213                    if (p.title) {
214                      title = p.title.replace(/\$1/g, ticketKey);
215                    }
216                    ticketUrl = p.base_url + ticketKey;
217                    break;
218                  }
219                }
220              }
221              if (!ticketUrl) {
222                var defaultJira = getDefaultJira();
223                if (defaultJira) {
224                  if (defaultJira.title) {
225                    title = defaultJira.title.replace(/\$1/g, ticketKey);
226                  }
227                  ticketUrl = defaultJira.base_url + ticketKey;
228                }
229              }
230            }
231            if (!ticketUrl) {
232              return null;
233            }
234          } else {
235            // Explicit TicketLink
236            if (site.title) {
237              title = site.title.replace(/\$1/g, ticketKey);
238            }
239            ticketUrl = site.base_url + ticketKey;
240          }
241          return {
242            url: ticketUrl,
243            title: title
244          };
245        }
246      }
247      return null;
248    }
249    function getRegex(list) {
250      var reText = '';
251      for (var i = 0, length = list.length; i < length; i++) {
252        if (reText.length > 0) {
253          reText += '|';
254        }
255        reText += list[i].reText;
256      }
257      return new RegExp(headReText + '(' + reText + ')' + tailReText);
258    }
259    function makeTicketLink(element) {
260      var siteList = getSiteList();
261      if (!siteList || siteList.length === 0) {
262        return;
263      }
264      var re = getRegex(siteList);
265      var f;
266      var m;
267      var text = element.nodeValue;
268      while (m = text.match(re)) { // eslint-disable-line no-cond-assign
269        // m[1]: head, m[2]: keyText
270        if (!f) {
271          f = document.createDocumentFragment();
272        }
273        if (m.index > 0 || m[1].length > 0) {
274          f.appendChild(document.createTextNode(text.substr(0, m.index) + m[1]));
275        }
276        var linkKey = m[2];
277        var linkInfo = ticketToLink(linkKey);
278        if (linkInfo) {
279          var a = document.createElement('a');
280          a.textContent = linkKey;
281          a.href = linkInfo.url;
282          a.title = linkInfo.title;
283          f.appendChild(a);
284        } else {
285          f.appendChild(document.createTextNode(m[2]));
286        }
287        text = text.substr(m.index + m[0].length);
288      }
289      if (f) {
290        if (text.length > 0) {
291          f.appendChild(document.createTextNode(text));
292        }
293        element.parentNode.replaceChild(f, element);
294      }
295    }
296    function walkElement(element) {
297      var e = element.firstChild;
298      while (e) {
299        if (e.nodeType === 3 && e.nodeValue &&
300            e.nodeValue.length > 5 && /\S/.test(e.nodeValue)) {
301          var next = e.nextSibling;
302          makeTicketLink(e);
303          e = next;
304        } else {
305          if (e.nodeType === 1 && ignoreTags.indexOf(e.tagName) === -1) {
306            walkElement(e);
307          }
308          e = e.nextSibling;
309        }
310      }
311    }
312    if (!Array.prototype.indexOf || !document.createDocumentFragment) {
313      return;
314    }
315    ticketSiteList = getSiteListFromBody();
316    jiraProjects = getJiraProjectsFromBody();
317    jiraDefaultInfo = getJiraDefaultInfoFromBody();
318    if (jiraDefaultInfo || (jiraProjects && jiraProjects.length > 0)) {
319      ticketSiteList.push(getJiraSite());
320    }
321    var target = document.getElementById('body');
322    walkElement(target);
323  }
324  function confirmEditFormLeaving() {
325    function trim(s) {
326      if (typeof s !== 'string') {
327        return s;
328      }
329      return s.replace(/^\s+|\s+$/g, '');
330    }
331    if (!document.querySelector) return;
332    var canceled = false;
333    var pluginNameE = document.querySelector('#pukiwiki-site-properties .plugin-name');
334    if (!pluginNameE) return;
335    var originalText = null;
336    if (pluginNameE.value !== 'edit') return;
337    var editForm = document.querySelector('.edit_form form._plugin_edit_edit_form');
338    if (!editForm) return;
339    var cancelMsgE = editForm.querySelector('#_msg_edit_cancel_confirm');
340    var unloadBeforeMsgE = editForm.querySelector('#_msg_edit_unloadbefore_message');
341    var textArea = editForm.querySelector('textarea[name="msg"]');
342    if (!textArea) return;
343    originalText = textArea.value;
344    var isPreview = false;
345    var inEditE = document.querySelector('#pukiwiki-site-properties .page-in-edit');
346    if (inEditE && inEditE.value) {
347      isPreview = (inEditE.value === 'true');
348    }
349    var cancelForm = document.querySelector('.edit_form form._plugin_edit_cancel');
350    var submited = false;
351    editForm.addEventListener('submit', function() {
352      canceled = false;
353      submited = true;
354    });
355    cancelForm.addEventListener('submit', function(e) {
356      submited = false;
357      canceled = false;
358      if (trim(textArea.value) === trim(originalText)) {
359        canceled = true;
360        return false;
361      }
362      var message = 'The text you have entered will be discarded. Is it OK?';
363      if (cancelMsgE && cancelMsgE.value) {
364        message = cancelMsgE.value;
365      }
366      if (window.confirm(message)) { // eslint-disable-line no-alert
367        // Execute "Cancel"
368        canceled = true;
369        return true;
370      }
371      e.preventDefault();
372      return false;
373    });
374    window.addEventListener('beforeunload', function(e) {
375      if (canceled) return;
376      if (submited) return;
377      if (!isPreview) {
378        if (trim(textArea.value) === trim(originalText)) return;
379      }
380      var message = 'Data you have entered will not be saved.';
381      if (unloadBeforeMsgE && unloadBeforeMsgE.value) {
382        message = unloadBeforeMsgE.value;
383      }
384      e.returnValue = message;
385    }, false);
386  }
387  function showPagePassage() {
388    /**
389     * @param {Date} now
390     * @param {string} dateText
391     */
392    function getSimplePassage(dateText, now) {
393      if (!dateText) {
394        return '';
395      }
396      var units = [{u: 'm', max: 60}, {u: 'h', max: 24}, {u: 'd', max: 1}];
397      var d = new Date();
398      d.setTime(Date.parse(dateText));
399      var t = (now.getTime() - d.getTime()) / (1000 * 60); // minutes
400      var unit = units[0].u; var card = units[0].max;
401      for (var i = 0; i < units.length; i++) {
402        unit = units[i].u; card = units[i].max;
403        if (t < card) break;
404        t = t / card;
405      }
406      return '' + Math.floor(t) + unit;
407    }
408    /**
409     * @param {Date} now
410     * @param {string} dateText
411     */
412    function getPassage(dateText, now) {
413      return '(' + getSimplePassage(dateText, now) + ')';
414    }
415    var now = new Date();
416    var elements = document.getElementsByClassName('page_passage');
417    forEach(elements, function(e) {
418      var dt = e.getAttribute('data-mtime');
419      if (dt) {
420        var d = new Date(dt);
421        e.textContent = ' ' + getPassage(d, now);
422      }
423    });
424    var links = document.getElementsByClassName('link_page_passage');
425    forEach(links, function(e) {
426      var dt = e.getAttribute('data-mtime');
427      if (dt) {
428        var d = new Date(dt);
429        if (e.title) {
430          e.title = e.title + ' ' + getPassage(d, now);
431        } else {
432          e.title = e.textContent + ' ' + getPassage(d, now);
433        }
434      }
435    });
436    var simplePassages = document.getElementsByClassName('simple_passage');
437    forEach(simplePassages, function(e) {
438      var dt = e.getAttribute('data-mtime');
439      if (dt) {
440        var d = new Date(dt);
441        e.textContent = getSimplePassage(d, now);
442      }
443    });
444    // new plugin
445    var newItems = document.getElementsByClassName('__plugin_new');
446    forEach(newItems, function(e) {
447      var dt = e.getAttribute('data-mtime');
448      if (dt) {
449        var d = new Date(dt);
450        var diff = now.getTime() - d.getTime();
451        var daySpan = diff / 1000 / 60 / 60 / 24;
452        if (daySpan < 1) {
453          e.textContent = ' New!';
454          e.title = getPassage(d, now);
455          if (e.classList && e.classList.add) {
456            e.classList.add('new1');
457          }
458        } else if (daySpan < 5) {
459          e.textContent = ' New';
460          e.title = getPassage(d, now);
461          if (e.classList && e.classList.add) {
462            e.classList.add('new5');
463          }
464        }
465      }
466    });
467  }
468  function convertExternalLinkToCushionPageLink() {
469    function domainQuote(domain) {
470      return domain.replace(/\./g, '\\.');
471    }
472    function domainsToRegex(domains) {
473      var regexList = [];
474      domains.forEach(function(domain) {
475        if (domain.substr(0, 2) === '*.') {
476          // Wildcard domain
477          var apex = domain.substr(2);
478          var r = new RegExp('((^.*\\.)|^)' + domainQuote(apex) + '$', 'i');
479          regexList.push(r);
480        } else {
481          // Normal domain
482          regexList.push(new RegExp('^' + domainQuote(domain) + '$', 'i'));
483        }
484      });
485      return regexList;
486    }
487    function domainMatch(domain, regexList) {
488      for (var i = 0, n = regexList.length; i < n; i++) {
489        if (regexList[i].test(domain)) {
490          return true;
491        }
492      }
493      return false;
494    }
495    function removeCushionPageLinks() {
496      var links = document.querySelectorAll('a.external-link');
497      forEach(links, function(link) {
498        var originalUrl = link.getAttribute('data-original-url');
499        if (originalUrl) {
500          link.setAttribute('href', originalUrl);
501        }
502      });
503    }
504    if (!document.querySelector || !JSON) return;
505    if (!Array || !Array.prototype || !Array.prototype.indexOf) return;
506    var extLinkDef = document.querySelector('#pukiwiki-site-properties .external-link-cushion');
507    if (!extLinkDef || !extLinkDef.value) return;
508    var extLinkInfo = JSON.parse(extLinkDef.value);
509    if (!extLinkInfo) return;
510    var refInternalDomains = extLinkInfo.internal_domains;
511    var silentExternalDomains = extLinkInfo.silent_external_domains;
512    if (!Array.isArray(refInternalDomains)) {
513      refInternalDomains = [];
514    }
515    var internalDomains = refInternalDomains.slice();
516    var location = document.location;
517    if (location.protocol === 'file:') {
518      removeCushionPageLinks();
519      return;
520    }
521    if (location.protocol !== 'http:' && location.protocol !== 'https:') return;
522    if (internalDomains.indexOf(location.hostname) < 0) {
523      internalDomains.push(location.hostname);
524    }
525    if (!Array.isArray(silentExternalDomains)) {
526      silentExternalDomains = [];
527    }
528    var propsE = document.querySelector('#pukiwiki-site-properties .site-props');
529    if (!propsE || !propsE.value) return;
530    var siteProps = JSON.parse(propsE.value);
531    var sitePathname = siteProps && siteProps.base_uri_pathname;
532    if (!sitePathname) return;
533    var internalDomainsR = domainsToRegex(internalDomains);
534    var silentExternalDomainsR = domainsToRegex(silentExternalDomains);
535    var links = document.querySelectorAll('a:not(.external-link):not(.internal-link)');
536    var classListEnabled = null;
537    forEach(links, function(link) {
538      if (classListEnabled === null) {
539        classListEnabled = link.classList && link.classList.add && true;
540      }
541      if (!classListEnabled) return;
542      var href = link.getAttribute('href');
543      if (!href) return; // anchor without href attribute (a name)
544      var m = href.match(/^https?:\/\/([0-9a-zA-Z.-]+)(:\d+)?/);
545      if (m) {
546        var host = m[1];
547        if (domainMatch(host, internalDomainsR)) {
548          link.classList.add('internal-link');
549        } else {
550          if (domainMatch(host, silentExternalDomainsR) ||
551            link.textContent.replace(/\s+/g, '') === '') {
552            // Don't show extenal link icons on these domains
553            link.classList.add('external-link-silent');
554          }
555          link.classList.add('external-link');
556          link.setAttribute('title', href);
557          link.setAttribute('data-original-url', href);
558          link.setAttribute('href', sitePathname + '?cmd=external_link&url=' + encodeURIComponent(href));
559        }
560      } else {
561        link.classList.add('internal-link');
562      }
563    });
564  }
565  function makeTopicpathTitle() {
566    if (!document.createDocumentFragment || !window.JSON) return;
567    var sitePropE = document.querySelector('#pukiwiki-site-properties');
568    if (!sitePropE) return;
569    var pageNameE = sitePropE.querySelector('.page-name');
570    if (!pageNameE || !pageNameE.value) return;
571    var pageName = pageNameE.value;
572    var topicpathE = sitePropE.querySelector('.topicpath-links');
573    if (!topicpathE || !topicpathE.value) return;
574    var topicpathLinks = JSON.parse(topicpathE.value);
575    if (!topicpathLinks) return;
576    var titleH1 = document.querySelector('h1.title');
577    if (!titleH1) return;
578    var aList = titleH1.querySelectorAll('a');
579    if (!aList || aList.length > 1) return;
580    var a = titleH1.querySelector('a');
581    if (!a) return;
582    if (a.textContent !== pageName) return;
583    var fragment = document.createDocumentFragment();
584    for (var i = 0, n = topicpathLinks.length; i < n; i++) {
585      var path = topicpathLinks[i];
586      var a1 = document.createElement('a');
587      a1.setAttribute('href', path.uri);
588      a1.setAttribute('title', path.page);
589      a1.textContent = path.leaf;
590      fragment.appendChild(a1);
591      var span = document.createElement('span');
592      span.className = 'topicpath-slash';
593      span.textContent = '/';
594      fragment.appendChild(span);
595    }
596    var a2 = document.createElement('a');
597    a2.setAttribute('href', a.getAttribute('href'));
598    a2.setAttribute('title', 'Backlinks');
599    a2.textContent = a.textContent.replace(/^.+\//, '');
600    fragment.appendChild(a2);
601    a.parentNode.replaceChild(fragment, a);
602  }
603  setYourName();
604  autoTicketLink();
605  confirmEditFormLeaving();
606  showPagePassage();
607  convertExternalLinkToCushionPageLink();
608  makeTopicpathTitle();
609});

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.