Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1822395
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
20 KB
Subscribers
None
View Options
diff --git a/action.php b/action.php
new file mode 100644
--- /dev/null
+++ b/action.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * DokuWiki linksenhanced PlugIn - Ajax component
+ * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
+ * @author Andreas Böhler <dev@aboehler.at>
+ */
+
+if(!defined('DOKU_INC')) die();
+
+class action_plugin_linksenhanced extends DokuWiki_Action_Plugin {
+
+ function register(Doku_Event_Handler $controller) {
+ $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call_unknown');
+ $controller->register_hook('DOKUWIKI_STARTED', 'AFTER', $this, 'add_jsinfo_information');
+ }
+
+ /**
+ * Add the language variable to the JSINFO variable
+ */
+ function add_jsinfo_information(Doku_Event $event, $param) {
+ global $JSINFO;
+
+ $JSINFO['plugin']['linksenhanced']['sectok'] = getSecurityToken();
+ }
+
+ function handle_ajax_call_unknown(&$event, $param) {
+ if($event->data != 'plugin_linksenhanced') return;
+
+ $event->preventDefault();
+ $event->stopPropagation();
+ global $INPUT;
+
+ $action = trim($INPUT->post->str('action'));
+ $url = trim($INPUT->post->str('url'));
+
+ if(!checkSecurityToken())
+ {
+ echo "CSRF Attack.";
+ return;
+ }
+
+ $data = array();
+
+ $data['result'] = false;
+
+ if($action === 'check')
+ {
+ $client = new DokuHTTPClient();
+ $client->sendRequest($url);
+ $httpcode = $client->status;
+
+ $data['error'] = $client->error;
+ $data['httpcode'] = $httpcode;
+
+ if($httpcode>=200 && $httpcode<300)
+ $data['result'] = true;
+ }
+ else
+ {
+ echo "Unknown operation.";
+ return;
+ }
+
+ // If we are still here, JSON output is requested
+
+ //json library of DokuWiki
+ require_once DOKU_INC . 'inc/JSON.php';
+ $json = new JSON();
+
+ //set content type
+ header('Content-Type: application/json');
+ echo $json->encode($data);
+ }
+
+}
diff --git a/conf/default.php b/conf/default.php
new file mode 100644
--- /dev/null
+++ b/conf/default.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Default settings for the linksenhanced plugin
+ *
+ * @author Andreas Boehler <dev@aboehler.at>
+ */
+
+$conf['check_all_external'] = 0;
+$conf['check_only_namespace'] = '';
diff --git a/conf/metadata.php b/conf/metadata.php
new file mode 100644
--- /dev/null
+++ b/conf/metadata.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Options for the linksenhanced plugin
+ *
+ * @author Andreas Boehler <dev@aboehler.at>
+ */
+
+
+$meta['check_all_external'] = array('onoff');
+$meta['check_only_namespace'] = array('string');
diff --git a/plugin.info.txt b/plugin.info.txt
--- a/plugin.info.txt
+++ b/plugin.info.txt
@@ -1,7 +1,7 @@
base linksenhanced
author Andreas Boehler
email dev@aboehler.at
-date 2015-03-10
+date 2019-01-23
name linksenhanced plugin
desc Enhanced Link Syntax
url http://www.aboehler.at
diff --git a/script.js b/script.js
new file mode 100644
--- /dev/null
+++ b/script.js
@@ -0,0 +1,33 @@
+jQuery(function() {
+
+ jQuery('div.dokuwiki a.plugin_linksenhanced_pending').each(function() {
+ var $link = jQuery(this).prop('href');
+ if(!$link)
+ return;
+ var $obj = jQuery(this);
+ // If we are still here, we found our target link
+ jQuery.post(
+ DOKU_BASE + 'lib/exe/ajax.php',
+ {
+ call: 'plugin_linksenhanced',
+ url: $link,
+ action: 'check',
+ sectok: JSINFO.plugin.linksenhanced['sectok'],
+ },
+ function(data)
+ {
+ var result = data['result'];
+ if(result === true)
+ {
+ $obj.removeClass('plugin_linksenhanced_pending');
+ $obj.addClass('plugin_linksenhanced_online');
+ }
+ else
+ {
+ $obj.removeClass('plugin_linksenhanced_pending');
+ $obj.addClass('plugin_linksenhanced_offline');
+ }
+ }
+ );
+ });
+});
diff --git a/style.css b/style.css
new file mode 100644
--- /dev/null
+++ b/style.css
@@ -0,0 +1,35 @@
+div.dokuwiki a.plugin_linksenhanced_pending::before{
+ content: '';
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ margin-right:3px;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ border-radius: 0.5em;
+ background-color: #e7793c;
+}
+
+div.dokuwiki a.plugin_linksenhanced_online::before{
+ content: '';
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ margin-right:3px;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ border-radius: 0.5em;
+ background-color: #1ac423;
+}
+
+div.dokuwiki a.plugin_linksenhanced_offline::before{
+ content: '';
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ margin-right:3px;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ border-radius: 0.5em;
+ background-color: #e52020;
+}
\ No newline at end of file
diff --git a/syntax.php b/syntax.php
--- a/syntax.php
+++ b/syntax.php
@@ -1,396 +1,415 @@
<?php
/**
* linksenhanced Plugin - Render Link Title using Wiki Markup
* Heavily based on the standard linking code.
*
* Usage:
*
+ * [[check^http://www.dokuwiki.org|www.dokuwiki.org]]
* [[render noparagraph^http://www.dokuwiki.org|<faicon fa fe-euro> FontAwesome Code]]
* [[render^http://www.dokuwiki.org|//Formatted Output, probably within a paragraph//]]
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Böhler <dev@aboehler.at>
*/
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
/**
* All DokuWiki plugins to extend the parser/rendering mechanism
* need to inherit from this class
*/
class syntax_plugin_linksenhanced extends DokuWiki_Syntax_Plugin {
function getType() {
return 'substition';
}
function getPType() {
return 'normal';
}
function getAllowedTypes() {
return array('container','substition','protected','disabled','paragraphs','formatting');
}
function getSort() {
return 202;
}
function connectTo($mode) {
$this->Lexer->addSpecialPattern('\[\[(?:(?:[^[\]]*?\[.*?\])|.*?)\]\]',$mode,'plugin_linksenhanced');
}
/**
* Handle the match. Use either the standard linking mechanism or, when enabled,
* pass the title through the parser
*/
function handle($match, $state, $pos, Doku_Handler $handler) {
+ global $ID;
+
$match = substr($match, 2, -2);
$link = explode('|',$match,2);
$nopara = false;
$optionsSet = explode('^', $link[0], 2);
$options = array('render' => false,
'noparagraph' => false,
+ 'check' => false,
'class' => false,
'target' => false);
if(isset($optionsSet[1]))
{
$link[0] = $optionsSet[1];
$opts = explode(' ', $optionsSet[0]);
foreach($opts as $opt)
{
if(strpos($opt, 'class') === 0)
$options['class'] = explode('=', $opt)[1];
elseif(strpos($opt, 'target') === 0)
$options['target'] = explode('=', $opt)[1];
else
$options[$opt] = true;
}
}
-
+
+ if($this->getConf('check_all_external') == 1)
+ {
+ if($this->getConf('check_only_namespace') != '')
+ {
+ if(getNS($ID) == $this->getConf('check_only_namespace'))
+ $options['check'] = true;
+ }
+ else
+ {
+ $options['check'] = true;
+ }
+ }
if($options['render'] && isset($link[1]))
{
$link[1] = $this->render_text($link[1]);
if($options['noparagraph'])
{
$link[1] = str_replace('</p>', '', str_replace('<p>', '', $link[1]));
}
if($link[1] === '')
$link[1] = null;
}
else if ( isset($link[1]) && preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) {
// If the title is an image, convert it to an array containing the image details
$link[1] = Doku_Handler_Parse_Media($link[1]);
}
else if(!isset($link[1]))
{
$link[1] = null;
}
$link[0] = trim($link[0]);
//decide which kind of link it is
if ( preg_match('/^[a-zA-Z0-9\.]+>{1}.*$/u',$link[0]) ) {
$type = 'interwiki';
}elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) {
$type = 'windowsshare';
}elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) {
$type = 'external';
}elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) {
$type = 'email';
}elseif ( preg_match('!^#.+!',$link[0]) ){
$type = 'local';
$link[0] = substr($link[0],1);
}else{
$type = 'internal';
}
return array($type, $link, $options);
}
/**
* Create output. This is largely based on the internal linking mechanism.
*/
function render($mode, Doku_Renderer $renderer, $data) {
if (empty($data)) return false;
global $conf;
global $ID;
global $INFO;
global $lang;
list($type, $link, $options) = $data;
$url = $link[0];
$name = $link[1];
-
if($mode == 'xhtml') {
switch($type)
{
case 'interwiki':
$interwiki = explode('>',$link[0],2);
$wikiName = strtolower($interwiki[0]);
$wikiUri = $interwiki[1];
$link = array();
$link['target'] = $conf['target']['interwiki'];
$link['pre'] = '';
$link['suf'] = '';
$link['more'] = '';
if($name === null || !$options['render'])
$link['name'] = $renderer->_getLinkTitle($name, $wikiUri, $isImage);
else
$link['name'] = $name;
//get interwiki URL
$exists = null;
$url = $renderer->_resolveInterWiki($wikiName, $wikiUri, $exists);
if(!$isImage) {
$class = preg_replace('/[^_\-a-z0-9]+/i', '_', $wikiName);
$link['class'] = "interwiki iw_$class";
} else {
$link['class'] = 'media';
}
//do we stay at the same server? Use local target
if(strpos($url, DOKU_URL) === 0 OR strpos($url, DOKU_BASE) === 0) {
$link['target'] = $conf['target']['wiki'];
}
if($options['target'] !== false)
$link['target'] = $options['target'];
if($exists !== null && !$isImage) {
if($exists) {
$link['class'] .= ' wikilink1';
} else {
$link['class'] .= ' wikilink2';
$link['rel'] = 'nofollow';
}
}
if($options['class'] !== false)
$link['class'] = $options['class'];
$link['url'] = $url;
$link['title'] = htmlspecialchars($link['url']);
//output formatted
$renderer->doc .= $renderer->_formatLink($link);
break;
case 'windowsshare':
//simple setup
$link['target'] = $conf['target']['windows'];
$link['pre'] = '';
$link['suf'] = '';
$link['style'] = '';
if($options['target'] !== false)
$link['target'] = $options['target'];
if($name === null || !$options['render'])
$link['name'] = $renderer->_getLinkTitle($name, $url, $isImage);
else
$link['name'] = $name;
if ( !$isImage ) {
$link['class'] = 'windows';
} else {
$link['class'] = 'media';
}
if($options['class'] !== false)
$link['class'] = $options['class'];
$link['title'] = $renderer->_xmlEntities($url);
$url = str_replace('\\','/',$url);
$url = 'file:///'.$url;
$link['url'] = $url;
//output formatted
$renderer->doc .= $renderer->_formatLink($link);
break;
case 'external':
if($name === null || !$options['render'])
$name = $renderer->_getLinkTitle($name, $url, $isImage);
// url might be an attack vector, only allow registered protocols
$schemes = getSchemes();
list($scheme) = explode('://',$url);
$scheme = strtolower($scheme);
if(!in_array($scheme,$schemes)) $url = '';
// is there still an URL?
if(!$url){
$renderer->doc .= $name;
return;
}
// set class
if ( !$isImage ) {
$class='urlextern';
} else {
$class='media';
}
if($options['class'] !== false)
$class = $options['class'];
//prepare for formating
$link['target'] = $conf['target']['extern'];
$link['style'] = '';
$link['pre'] = '';
$link['suf'] = '';
$link['more'] = '';
$link['class'] = $class;
$link['url'] = $url;
if($options['target'] !== false)
$link['target'] = $options['target'];
-
+
+ if($options['check'] !== false)
+ {
+ $link['class'] = 'plugin_linksenhanced_pending';
+ }
$link['name'] = $name;
$link['title'] = $renderer->_xmlEntities($url);
if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"';
//output formatted
$renderer->doc .= $renderer->_formatLink($link);
break;
case 'email':
$link = array();
$link['target'] = '';
$link['pre'] = '';
$link['suf'] = '';
$link['style'] = '';
$link['more'] = '';
if($name === null || !$options['render'])
$name = $renderer->_getLinkTitle($name, '', $isImage);
if ( !$isImage ) {
$link['class']='mail';
} else {
$link['class']='media';
}
if($options['class'] !== false)
$link['class'] = $options['class'];
$url = $renderer->_xmlEntities($url);
$url = obfuscate($url);
$title = $url;
if(empty($name)){
$name = $url;
}
if($conf['mailguard'] == 'visible') $url = rawurlencode($url);
$link['url'] = 'mailto:'.$url;
$link['name'] = $name;
$link['title'] = $title;
//output formatted
$renderer->doc .= $renderer->_formatLink($link);
break;
case 'local':
if($name === null || !$options['render'])
$name = $renderer->_getLinkTitle($name, $url, $isImage);
$url = $renderer->_headerToLink($url);
$title = $ID.' ↵';
if($options['class'] !== false)
$class = $options['class'];
else
$class = "wikilink1";
$renderer->doc .= '<a href="#'.$url.'" title="'.$title.'" class="'.$class.'">';
$renderer->doc .= $name;
$renderer->doc .= '</a>';
break;
case 'internal':
$id = $url;
$params = '';
$linktype = 'content';
$parts = explode('?', $id, 2);
if (count($parts) === 2) {
$id = $parts[0];
$params = $parts[1];
}
// For empty $id we need to know the current $ID
// We need this check because _simpleTitle needs
// correct $id and resolve_pageid() use cleanID($id)
// (some things could be lost)
if ($id === '') {
$id = $ID;
}
// default name is based on $id as given
$default = $renderer->_simpleTitle($id);
// now first resolve and clean up the $id
resolve_pageid(getNS($ID),$id,$exists);
if($name === null || !$options['render'])
$name = $renderer->_getLinkTitle($name, $default, $isImage, $id, $linktype);
if ( !$isImage ) {
if ( $exists ) {
$class='wikilink1';
} else {
$class='wikilink2';
$link['rel']='nofollow';
}
} else {
$class='media';
}
if($options['class'] !== false)
$class = $options['class'];
//keep hash anchor
@list($id,$hash) = explode('#',$id,2);
if(!empty($hash)) $hash = $renderer->_headerToLink($hash);
//prepare for formating
$link['target'] = $conf['target']['wiki'];
$link['style'] = '';
$link['pre'] = '';
$link['suf'] = '';
// highlight link to current page
if ($id == $INFO['id']) {
$link['pre'] = '<span class="curid">';
$link['suf'] = '</span>';
}
$link['more'] = '';
$link['class'] = $class;
$link['url'] = wl($id, $params);
$link['name'] = $name;
$link['title'] = $id;
if($options['target'] !== false)
$link['target'] = $options['target'];
//add search string
if($search){
($conf['userewrite']) ? $link['url'].='?' : $link['url'].='&';
if(is_array($search)){
$search = array_map('rawurlencode',$search);
$link['url'] .= 's[]='.join('&s[]=',$search);
}else{
$link['url'] .= 's='.rawurlencode($search);
}
}
//keep hash
if($hash) $link['url'].='#'.$hash;
//output formatted
if($returnonly){
return $renderer->_formatLink($link);
}else{
$renderer->doc .= $renderer->_formatLink($link);
}
break;
}
}
return false;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Dec 24, 6:00 PM (1 d, 2 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
532419
Default Alt Text
(20 KB)
Attached To
rLE linksenhanced PlugIn
Event Timeline
Log In to Comment