修订版 | d5b3306ee8e913446ddef831a08a05a04527c4b2 (tree) |
---|---|
时间 | 2018-03-22 02:14:44 |
作者 | umorigu <umorigu@gmai...> |
Commiter | umorigu |
BugTrack/2247 External link cushion page - Control Referer etc.
* New plugin: external_link.inc.php
* New config: $external_link_cushion_page, $external_link_cushion
You can set "internal domains", on these host, you don't need to
see cushion page.
@@ -446,3 +446,11 @@ $_loginform_messages = array( | ||
446 | 446 | 'login' => 'Log in', |
447 | 447 | 'invalid_username_or_password' => 'The username or password you entered is incorrect' |
448 | 448 | ); |
449 | + | |
450 | +/////////////////////////////////////// | |
451 | +// external_link.inc.php | |
452 | +$_external_link_messages = array( | |
453 | + 'page_title' => 'External link: %s', | |
454 | + 'desc' => 'The selected URL is not the contents of this site.', | |
455 | + 'wait_n_seconds' => 'It will move to the page automatically after %s seconds.', | |
456 | +); |
@@ -448,3 +448,11 @@ $_loginform_messages = array( | ||
448 | 448 | 'login' => 'ログイン', |
449 | 449 | 'invalid_username_or_password' => 'ユーザー名またはパスワードが違います' |
450 | 450 | ); |
451 | + | |
452 | +/////////////////////////////////////// | |
453 | +// external_link.inc.php | |
454 | +$_external_link_messages = array( | |
455 | + 'page_title' => '外部リンク: %s', | |
456 | + 'desc' => '選択されたURLは本サイトのコンテンツではありません。', | |
457 | + 'wait_n_seconds' => '%s 秒後に自動的に移動します。', | |
458 | +); |
@@ -219,6 +219,7 @@ function _decorate_Nth_word($matches) | ||
219 | 219 | function get_html_scripting_data() |
220 | 220 | { |
221 | 221 | global $ticket_link_sites, $plugin; |
222 | + global $external_link_cushion_page, $external_link_cushion; | |
222 | 223 | if (!isset($ticket_link_sites) || !is_array($ticket_link_sites)) { |
223 | 224 | return ''; |
224 | 225 | } |
@@ -261,11 +262,21 @@ EOS; | ||
261 | 262 | $ticketlink_data = <<<EOS |
262 | 263 | <input type="hidden" class="ticketlink-def" value="$h_ticket_link_sites" /> |
263 | 264 | EOS; |
265 | + // External link cushion page | |
266 | + $external_link_cushion_data = ''; | |
267 | + if ($external_link_cushion_page) { | |
268 | + $h_cushion = htmlsc(json_encode($external_link_cushion, | |
269 | + JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); | |
270 | + $external_link_cushion_data = <<<EOS | |
271 | +<input type="hidden" class="external-link-cushion" value="$h_cushion" /> | |
272 | +EOS; | |
273 | + } | |
264 | 274 | $data = <<<EOS |
265 | 275 | <div id="pukiwiki-site-properties" style="display:none;"> |
266 | 276 | $site_props |
267 | 277 | $plugin_prop |
268 | 278 | $ticketlink_data |
279 | +$external_link_cushion_data | |
269 | 280 | </div> |
270 | 281 | EOS; |
271 | 282 | return $data; |
@@ -314,6 +314,26 @@ $ticket_link_sites = array( | ||
314 | 314 | ); |
315 | 315 | |
316 | 316 | ///////////////////////////////////////////////// |
317 | +// Show External Link Cushion Page | |
318 | +// 0: Disabled | |
319 | +// 1: Enabled | |
320 | +$external_link_cushion_page = 0; | |
321 | +$external_link_cushion = array( | |
322 | + // Wait N seconds before jumping to an external site | |
323 | + 'wait_seconds' => 5, | |
324 | + // Internal site domain list | |
325 | + 'internal_domains' => array( | |
326 | + 'localhost', | |
327 | + // '*.example.com', | |
328 | + ), | |
329 | + // Don't show extenal link icons on these domains | |
330 | + 'silent_external_domains' => array( | |
331 | + 'pukiwiki.osdn.jp', | |
332 | + 'pukiwiki.example.com', | |
333 | + ), | |
334 | +); | |
335 | + | |
336 | +///////////////////////////////////////////////// | |
317 | 337 | // $whatsnew: Max number of RecentChanges |
318 | 338 | $maxshow = 500; |
319 | 339 |
@@ -370,8 +370,94 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function( | ||
370 | 370 | } |
371 | 371 | }); |
372 | 372 | } |
373 | + function convertExternalLinkToCushionPageLink() { | |
374 | + function domainQuote(domain) { | |
375 | + return domain.replace(/\./g, '\\.'); | |
376 | + } | |
377 | + function domainsToRegex(domains) { | |
378 | + var regexList = []; | |
379 | + domains.forEach(function(domain) { | |
380 | + if (domain.substr(0, 2) === '*.') { | |
381 | + // Wildcard domain | |
382 | + var apex = domain.substr(2); | |
383 | + var r = new RegExp('((^.*\\.)|^)' + domainQuote(apex) + '$', 'i'); | |
384 | + regexList.push(r); | |
385 | + } else { | |
386 | + // Normal domain | |
387 | + regexList.push(new RegExp('^' + domainQuote(domain) + '$', 'i')); | |
388 | + } | |
389 | + }); | |
390 | + return regexList; | |
391 | + } | |
392 | + function domainMatch(domain, regexList) { | |
393 | + for (var i = 0, n = regexList.length; i < n; i++) { | |
394 | + if (regexList[i].test(domain)) { | |
395 | + return true; | |
396 | + } | |
397 | + } | |
398 | + return false; | |
399 | + } | |
400 | + if (!(document.querySelector && JSON)) return; | |
401 | + var location = document.location; | |
402 | + if (location.protocol !== 'http:' && location.protocol !== 'https:') return; | |
403 | + var extLinkInfo = null; | |
404 | + var refInternalDomains = null; | |
405 | + var silentExternalDomains = null; | |
406 | + var extLinkDef = document.querySelector('#pukiwiki-site-properties .external-link-cushion'); | |
407 | + if (extLinkDef && extLinkDef.value) { | |
408 | + extLinkInfo = JSON.parse(extLinkDef.value); | |
409 | + refInternalDomains = extLinkInfo.internal_domains; | |
410 | + silentExternalDomains = extLinkInfo.silent_external_domains; | |
411 | + } | |
412 | + if (!Array.isArray(refInternalDomains)) { | |
413 | + refInternalDomains = []; | |
414 | + } | |
415 | + var internalDomains = refInternalDomains.slice(); | |
416 | + var hostname = document.location.hostname; | |
417 | + if (internalDomains.indexOf(hostname) < 0) { | |
418 | + internalDomains.push(hostname); | |
419 | + } | |
420 | + if (!Array.isArray(silentExternalDomains)) { | |
421 | + silentExternalDomains = []; | |
422 | + } | |
423 | + var propsE = document.querySelector('#pukiwiki-site-properties .site-props'); | |
424 | + if (!propsE) return; | |
425 | + var siteProps = JSON.parse(propsE.value); | |
426 | + var sitePathname = siteProps && siteProps.base_uri_pathname; | |
427 | + if (!sitePathname) return; | |
428 | + var internalDomainsR = domainsToRegex(internalDomains); | |
429 | + var silentExternalDomainsR = domainsToRegex(silentExternalDomains); | |
430 | + var links = document.querySelectorAll('a:not(.external-link):not(.internal-link)'); | |
431 | + var classListEnabled = null; | |
432 | + forEach(links, function(link) { | |
433 | + if (classListEnabled === null) { | |
434 | + classListEnabled = link.classList && link.classList.add && true; | |
435 | + } | |
436 | + if (!classListEnabled) return; | |
437 | + var href = link.getAttribute('href'); | |
438 | + var m = href.match(/^https?:\/\/([0-9a-zA-Z.-]+)(:\d+)?/); | |
439 | + if (m) { | |
440 | + var host = m[1]; | |
441 | + if (domainMatch(host, internalDomainsR)) { | |
442 | + link.classList.add('internal-link'); | |
443 | + } else { | |
444 | + if (domainMatch(host, silentExternalDomainsR) || | |
445 | + link.innerText.replace(/\s+/g, '') === '') { | |
446 | + // Don't show extenal link icons on these domains | |
447 | + link.classList.add('external-link-silent'); | |
448 | + } | |
449 | + link.classList.add('external-link'); | |
450 | + link.setAttribute('title', href); | |
451 | + link.setAttribute('href', sitePathname + '?cmd=external_link&url=' + encodeURIComponent(href)); | |
452 | + } | |
453 | + } else { | |
454 | + link.classList.add('internal-link'); | |
455 | + } | |
456 | + }); | |
457 | + } | |
373 | 458 | setYourName(); |
374 | 459 | autoTicketLink(); |
375 | 460 | confirmEditFormLeaving(); |
376 | 461 | showPagePassage(); |
462 | + convertExternalLinkToCushionPageLink(); | |
377 | 463 | }); |
@@ -47,6 +47,11 @@ a:hover { | ||
47 | 47 | text-decoration:underline; |
48 | 48 | } |
49 | 49 | |
50 | +a.external-link:not(.external-link-silent)::after { | |
51 | + content:url(../image/external-link.png); | |
52 | + margin:3px; | |
53 | +} | |
54 | + | |
50 | 55 | h1, h2 { |
51 | 56 | font-family:verdana, arial, helvetica, Sans-Serif; |
52 | 57 | color:inherit; |
@@ -30,6 +30,11 @@ img { border: 0 } | ||
30 | 30 | /* --------------------- */ |
31 | 31 | /* PukiWiki original CSS */ |
32 | 32 | |
33 | +a.external-link:not(.external-link-silent)::after { | |
34 | + content:url(../image/external-link.png); | |
35 | + margin:3px; | |
36 | +} | |
37 | + | |
33 | 38 | pre { |
34 | 39 | white-space:pre-wrap; |
35 | 40 | word-wrap:break-word; |