Revision | bdd91ef0e3092b4b29f539571625a3e6f6b8d8d1 (tree) |
---|---|
Zeit | 2017-05-28 05:43:20 |
Autor | umorigu <umorigu@gmai...> |
Commiter | umorigu |
BugTrack/2420 AutoTicketLink
@@ -186,12 +186,47 @@ function catbody($title, $page, $body) | ||
186 | 186 | } |
187 | 187 | } |
188 | 188 | |
189 | + // Embed Scripting data | |
190 | + $html_scripting_data = get_html_scripting_data(); | |
191 | + | |
189 | 192 | // Compat: 'HTML convert time' without time about MenuBar and skin |
190 | 193 | $taketime = elapsedtime(); |
191 | 194 | |
192 | 195 | require(SKIN_FILE); |
193 | 196 | } |
194 | 197 | |
198 | +/** | |
199 | + * Get data used by JavaScript modules | |
200 | + */ | |
201 | +function get_html_scripting_data() | |
202 | +{ | |
203 | + global $ticket_link_sites; | |
204 | + if (!isset($ticket_link_sites) || !is_array($ticket_link_sites)) { | |
205 | + return ''; | |
206 | + } | |
207 | + // Require: PHP 5.4+ | |
208 | + if (!defined('JSON_UNESCAPED_UNICODE')) { | |
209 | + return ''; | |
210 | + }; | |
211 | + $text = ''; | |
212 | + foreach ($ticket_link_sites as $s) { | |
213 | + if (!preg_match('/^([a-zA-Z0-9]+)([\.\-][a-zA-Z0-9]+)*$/', $s['key'])) { | |
214 | + continue; | |
215 | + } | |
216 | + $site_info_json = htmlsc(json_encode($s, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); | |
217 | + $text .= <<<EOS | |
218 | + <span class="pukiwiki-ticketlink-site" data-site="$site_info_json"></span> | |
219 | +EOS; | |
220 | + $text .= "\n"; | |
221 | + } | |
222 | + $data = <<<EOS | |
223 | +<div class="pukiwiki-ticketlink-def" style="display:none;"> | |
224 | +$text | |
225 | +</div> | |
226 | +EOS; | |
227 | + return $data; | |
228 | +} | |
229 | + | |
195 | 230 | // Show 'edit' form |
196 | 231 | function edit_form($page, $postdata, $digest = FALSE, $b_template = TRUE) |
197 | 232 | { |
@@ -288,6 +288,31 @@ $edit_auth_pages = array( | ||
288 | 288 | $search_auth = 0; |
289 | 289 | |
290 | 290 | ///////////////////////////////////////////////// |
291 | +// AutoTicketLink | |
292 | +$ticket_link_sites = array( | |
293 | +/* | |
294 | + array( | |
295 | + 'key' => 'phpbug', | |
296 | + 'type' => 'redmine', // type: redmine, jira or git | |
297 | + 'title' => 'PHP :: Bug #$1', | |
298 | + 'base_url' => 'https://bugs.php.net/bug.php?id=', | |
299 | + ), | |
300 | + array( | |
301 | + 'key' => 'asfjira', | |
302 | + 'type' => 'jira', | |
303 | + 'title' => 'ASF JIRA [$1]', | |
304 | + 'base_url' => 'https://issues.apache.org/jira/browse/', | |
305 | + ), | |
306 | + array( | |
307 | + 'key' => 'pukiwiki-commit', | |
308 | + 'type' => 'git', | |
309 | + 'title' => 'PukiWiki revision $1', | |
310 | + 'base_url' => 'https://ja.osdn.net/projects/pukiwiki/scm/git/pukiwiki/commits/', | |
311 | + ), | |
312 | +*/ | |
313 | +); | |
314 | + | |
315 | +///////////////////////////////////////////////// | |
291 | 316 | // $whatsnew: Max number of RecentChanges |
292 | 317 | $maxshow = 60; |
293 | 318 |
@@ -0,0 +1,147 @@ | ||
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 | + default: | |
52 | + continue; | |
53 | + } | |
54 | + site.reText = reText; | |
55 | + site.re = new RegExp(headReText + reText + tailReText); | |
56 | + } | |
57 | + } | |
58 | + function getSiteList() { | |
59 | + return _siteList; | |
60 | + } | |
61 | + function getSiteListFromBody() { | |
62 | + var list = []; | |
63 | + var defRoot = document.querySelector('.pukiwiki-ticketlink-def'); | |
64 | + var siteNodes = defRoot.querySelectorAll('.pukiwiki-ticketlink-site'); | |
65 | + Array.prototype.forEach.call(siteNodes, function (e) { | |
66 | + var siteInfoText = e.dataset && e.dataset.site; | |
67 | + if (!siteInfoText) return; | |
68 | + var info = textToSiteInfo(siteInfoText); | |
69 | + if (info) { | |
70 | + list.push(info); | |
71 | + } | |
72 | + }); | |
73 | + setupSites(list); | |
74 | + return list; | |
75 | + } | |
76 | + function textToSiteInfo(siteDef) { | |
77 | + if (!siteDef) return null; | |
78 | + var info = JSON.parse(siteDef); | |
79 | + if (info && info.key && info.type && info.base_url) { | |
80 | + return info; | |
81 | + } | |
82 | + return null; | |
83 | + } | |
84 | + function startsWith(s, searchString) { | |
85 | + if (String.prototype.startsWith) { | |
86 | + return s.startsWith(searchString); | |
87 | + } | |
88 | + return s.substr(0, searchString.length) === searchString; | |
89 | + } | |
90 | + function getRegex(list) { | |
91 | + var reText = ''; | |
92 | + for (var i = 0, length = list.length; i < length; i++) { | |
93 | + if (reText.length > 0) { | |
94 | + reText += '|' | |
95 | + } | |
96 | + reText += list[i].reText; | |
97 | + } | |
98 | + return new RegExp(headReText + '(' + reText + ')' + tailReText); | |
99 | + } | |
100 | + function makeTicketLink(element) { | |
101 | + var siteList = getSiteList(); | |
102 | + if (!siteList || siteList.length === 0) { | |
103 | + return; | |
104 | + } | |
105 | + var re = getRegex(siteList); | |
106 | + var f, m, text = element.nodeValue; | |
107 | + while (m = text.match(re)) { | |
108 | + // m[1]: head, m[2]: keyText | |
109 | + f || (f = document.createDocumentFragment()); | |
110 | + if (m.index > 0 || m[1].length > 0) { | |
111 | + f.appendChild(document.createTextNode(text.substr(0, m.index) + m[1])); | |
112 | + } | |
113 | + var a = document.createElement('a'); | |
114 | + a.textContent = m[2]; | |
115 | + var linkInfo = ticketToLink(a.textContent); | |
116 | + a.href = linkInfo.url; | |
117 | + a.title = linkInfo.title; | |
118 | + f.appendChild(a); | |
119 | + text = text.substr(m.index + m[0].length); | |
120 | + } | |
121 | + if (f) { | |
122 | + text.length > 0 && f.appendChild(document.createTextNode(text)); | |
123 | + element.parentNode.replaceChild(f, element) | |
124 | + } | |
125 | + } | |
126 | + var ignoreTags = ['A', 'INPUT', 'TEXTAREA', 'BUTTON', | |
127 | + 'SCRIPT', 'FRAME', 'IFRAME']; | |
128 | + function walkElement(element) { | |
129 | + var e = element.firstChild; | |
130 | + while (e) { | |
131 | + if (e.nodeType == 3 && e.nodeValue && | |
132 | + e.nodeValue.length > 5 && /\S/.test(e.nodeValue)) { | |
133 | + var next = e.nextSibling; | |
134 | + makeTicketLink(e); | |
135 | + e = next; | |
136 | + } else { | |
137 | + if (e.nodeType == 1 && ignoreTags.indexOf(e.tagName) == -1) { | |
138 | + walkElement(e); | |
139 | + } | |
140 | + e = e.nextSibling; | |
141 | + } | |
142 | + } | |
143 | + } | |
144 | + var target = document.getElementById('body'); | |
145 | + walkElement(target); | |
146 | + }); | |
147 | +} |
@@ -2,7 +2,7 @@ | ||
2 | 2 | // PukiWiki - Yet another WikiWikiWeb clone. |
3 | 3 | // pukiwiki.skin.php |
4 | 4 | // Copyright |
5 | -// 2002-2016 PukiWiki Development Team | |
5 | +// 2002-2017 PukiWiki Development Team | |
6 | 6 | // 2001-2002 Originally written by yu-ji |
7 | 7 | // License: GPL v2 or (at your option) any later version |
8 | 8 | // |
@@ -68,6 +68,7 @@ header('Content-Type: text/html; charset=' . CONTENT_CHARSET); | ||
68 | 68 | <link rel="SHORTCUT ICON" href="<?php echo $image['favicon'] ?>" /> |
69 | 69 | <link rel="stylesheet" type="text/css" href="<?php echo SKIN_DIR ?>pukiwiki.css" /> |
70 | 70 | <link rel="alternate" type="application/rss+xml" title="RSS" href="<?php echo $link['rss'] ?>" /><?php // RSS auto-discovery ?> |
71 | + <script type="text/javascript" src="skin/main.js" defer></script> | |
71 | 72 | |
72 | 73 | <?php echo $head_tag ?> |
73 | 74 | </head> |
@@ -267,6 +268,7 @@ function _toolbar($key, $x = 20, $y = 20){ | ||
267 | 268 | <?php echo S_COPYRIGHT ?>. |
268 | 269 | Powered by PHP <?php echo PHP_VERSION ?>. HTML convert time: <?php echo elapsedtime() ?> sec. |
269 | 270 | </div> |
271 | +<?php echo $html_scripting_data ?> | |
270 | 272 | |
271 | 273 | </body> |
272 | 274 | </html> |