OSDN Git Service

BugTrack/2420 Avoid JavaScript error on PHP5.3 env
[pukiwiki/pukiwiki.git] / skin / main.js
1 // PukiWiki - Yet another WikiWikiWeb clone.
2 // main.js
3 // Copyright
4 //   2017 PukiWiki Development Team
5 // License: GPL v2 or (at your option) any later version
6 //
7 // PukiWiki JavaScript client script
8 if (window.addEventListener) {
9   window.addEventListener('DOMContentLoaded', function() {
10     if (!Array.prototype.indexOf || !document.createDocumentFragment) {
11       return;
12     }
13     var headReText = '([\\s\\b]|^)';
14     var tailReText = '\\b';
15     var _siteList = getSiteListFromBody();
16     function ticketToLink(keyText) {
17       var siteList = getSiteList();
18       for (var i = 0; i < siteList.length; i++) {
19         var site = siteList[i];
20         var m = keyText.match(site.re);
21         if (m) {
22           var title = site.title;
23           var ticketKey = m[3]
24           if (title) {
25             title = title.replace(/\$1/g, ticketKey);
26           }
27           return {
28             url: site.base_url + m[3],
29             title: title
30           };
31         }
32       }
33       return null;
34     }
35     function regexEscape(key) {
36       return key.replace(/[\-\.]/g, function (m) {
37         return '\\' + m;
38       });
39     }
40     function setupSites(siteList) {
41       for (var i = 0, length = siteList.length; i < length; i++) {
42         var site = siteList[i];
43         var reText = '';
44         switch (site.type) {
45           case 'jira':
46             reText = '(' + regexEscape(site.key) + '):' + '([A-Z][A-Z0-9_]+-\\d+)';
47             break;
48           case 'redmine':
49             reText = '(' + regexEscape(site.key) + '):' + '(\\d+)';
50             break;
51           case 'git':
52             reText = '(' + regexEscape(site.key) + '):' + '([0-9a-f]{7,40})';
53             break;
54           default:
55             continue;
56         }
57         site.reText = reText;
58         site.re = new RegExp(headReText + reText + tailReText);
59       }
60     }
61     function getSiteList() {
62       return _siteList;
63     }
64     function getSiteListFromBody() {
65       var list = [];
66       var defRoot = document.querySelector('.pukiwiki-ticketlink-def');
67       if (!defRoot) {
68         return [];
69       }
70       var siteNodes = defRoot.querySelectorAll('.pukiwiki-ticketlink-site');
71       Array.prototype.forEach.call(siteNodes, function (e) {
72         var siteInfoText = e.dataset && e.dataset.site;
73         if (!siteInfoText) return;
74         var info = textToSiteInfo(siteInfoText);
75         if (info) {
76           list.push(info);
77         }
78       });
79       setupSites(list);
80       return list;
81     }
82     function textToSiteInfo(siteDef) {
83       if (!siteDef) return null;
84       var info = JSON.parse(siteDef);
85       if (info && info.key && info.type && info.base_url) {
86         return info;
87       }
88       return null;
89     }
90     function startsWith(s, searchString) {
91       if (String.prototype.startsWith) {
92         return s.startsWith(searchString);
93       }
94       return s.substr(0, searchString.length) === searchString;
95     }
96     function getRegex(list) {
97       var reText = '';
98       for (var i = 0, length = list.length; i < length; i++) {
99         if (reText.length > 0) {
100           reText += '|'
101         }
102         reText += list[i].reText;
103       }
104       return new RegExp(headReText + '(' + reText + ')' + tailReText);
105     }
106     function makeTicketLink(element) {
107       var siteList = getSiteList();
108       if (!siteList || siteList.length === 0) {
109         return;
110       }
111       var re = getRegex(siteList);
112       var f, m, text = element.nodeValue;
113       while (m = text.match(re)) {
114         // m[1]: head, m[2]: keyText
115         f || (f = document.createDocumentFragment());
116         if (m.index > 0 || m[1].length > 0) {
117           f.appendChild(document.createTextNode(text.substr(0, m.index) + m[1]));
118         }
119         var a = document.createElement('a');
120         a.textContent = m[2];
121         var linkInfo = ticketToLink(a.textContent);
122         a.href = linkInfo.url;
123         a.title = linkInfo.title;
124         f.appendChild(a);
125         text = text.substr(m.index + m[0].length);
126       }
127       if (f) {
128         text.length > 0 && f.appendChild(document.createTextNode(text));
129         element.parentNode.replaceChild(f, element)
130       }
131     }
132     var ignoreTags = ['A', 'INPUT', 'TEXTAREA', 'BUTTON',
133       'SCRIPT', 'FRAME', 'IFRAME'];
134     function walkElement(element) {
135       var e = element.firstChild;
136       while (e) {
137         if (e.nodeType == 3 && e.nodeValue &&
138             e.nodeValue.length > 5 && /\S/.test(e.nodeValue)) {
139           var next = e.nextSibling;
140           makeTicketLink(e);
141           e = next;
142         } else {
143           if (e.nodeType == 1 && ignoreTags.indexOf(e.tagName) == -1) {
144             walkElement(e);
145           }
146           e = e.nextSibling;
147         }
148       }
149     }
150     var target = document.getElementById('body');
151     walkElement(target);
152   });
153 }