DokuWiki

It's better when it's simple

User Tools

Site Tools


plugin:embed

Embed Plugin

Compatible with DokuWiki

2008-05-05, 2006-11-06, 2007-05-24, 2007-06-26b

plugin This plugin allows to embed wikipages seamlessly into another page. In addition, parts marked with the label plugin can be replaced.

Last updated on
2007-05-14
Provides
Syntax

This extension has not been updated in over 2 years. It may no longer be maintained or supported and may have compatibility issues.

Similar to include

Tagged with embed, include

The idea

Sometimes you are required to include a wikipage while replacing parts of it, e.g. if building up hierarchical menus with the Sidebar Template.

Requirements

I've developed the plugin under the DokuWiki version of 2006-11-06 and seems to work with version 2007-06-26 as well.

Download / Installation

Download the plugin here (manually or via Plugin Manager): http://pb.wh4f.de/dokuwiki/embed.zip

Shortcomings

To assure proper use of ACLs, this plugin inhibits caching on pages which make use of the <embed …> tag.

Syntax

The Syntax is very simple:

<embed wikipage/>

With replacement:

<embed wikipage>
  <label replace_me>This text replaces the one marked with id 5 in wikipage</label>
</embed>

Use Case

A use case for this plugin is inherited creation of menus for sidebars, which are reused over different namespaces:

:sidebar

~~NOTOC~~ 

  * [[:start]]
    * <label research>[[:research:]]</label>
    * <label teaching>[[:teaching:]]</label>
    * <label publications>[[:publications:]]</label>

This will look like:


:teaching:sidebar (second level)

<embed ..:sidebar>
<label teaching><label teaching_header>**teaching**</label>
      * <label classes>[[classes:]]</label>
      * <label labs>[[labs:]]</label></label>
</embed>

This will look like:


:teaching:classes:sidebar (third level) (Two replacements!)

<embed ..:sidebar>
<label teaching_header>[[:teaching:]]</label>
<label classes>**classes**
        * [[OOSC]]
        * [[AOSC]]</label>
</embed>

This will look like:

Code

(sorry, will be properly indented when I have some time)

<?php
/**
* This plugin allows to embed wikipages into the current page
* In addition, parts marked with id's can be replaced.
*
* Inspired (and copy&pasted) from the include plugin:
*   http://www.dokuwiki.org/plugin:include
*
* For wikipage-portion-replacements, the label-plugin is required: http://www.dokuwiki.org/plugin:label
* 
* 
* @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author     Pascal Bihler <bihler@iai.uni-bonn.de>
*/
 
// must be run within DokuWiki
if(!defined('DOKU_INC')) die();
 
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');
 
//
 
class syntax_plugin_embed extends DokuWiki_Syntax_Plugin {
 
	function syntax_plugin_embed() {
		global $embedded_pages_by_plugin_embed;
		if (! $embedded_pages_by_plugin_embed) {
			$embedded_pages_by_plugin_embed = array(); // To avoid recursion;
		}
	}
 
	function getInfo(){
		return array(
		'author' => 'Pascal Bihler',
		'email'  => 'bihler@iai.uni-bonn.de',
		'date'   => '2007-05-14',
		'name'   => 'Embed',
		'desc'   => 'Allows to embed wikipages in other ones, while offering the possibility to replace parts of the original page marked with labels.',
		'url'    => 'http://www.dokuwiki.org/plugin:embed',
		);
	}
 
 
	function getType(){
		return 'substition';
	}
 
	function getSort(){
		return 500;
	}
 
	function connectTo($mode) {
		$this->Lexer->addSpecialPattern('<embed\s+[^>]+\s*>.*?</embed>',$mode,'plugin_embed');
		$this->Lexer->addSpecialPattern('<embed\s+[^/]+\s*/>',$mode,'plugin_embed');
	}
 
 
	/**
	* Handle the match
	*/
	function handle($match, $state, $pos, &$handler){
		switch ($state) {
		case DOKU_LEXER_SPECIAL :
			if (preg_match('/<embed\s+([^>]+)\s*>(.*?)<\/embed>/ms',$match,$matches)) 
			return array($matches[1],$matches[2]);
			else if (preg_match('/<embed\s+([^>]+)\s*\/>/',$match,$matches)) 
			return array($matches[1],'');
			break;
		}
		return array();
	}
 
	/**
	* Create output
	*/
	function render($mode, &$renderer, $data) {
		global $ID;
		global $embedded_pages_by_plugin_embed;
 
 
		if($mode == 'xhtml'){
			list($id,$replacement) = $data;
 
			$renderer->info['cache'] = false; // prevent caching (to ensure ACL conformity) (TODO sometimes: make more intelligent)
 
			resolve_pageid(getNS($ID), $id, $exists); // resolve shortcuts 
 
			//resolve_pageid(getNS($ID), $id, $exists); // resolve shortcuts 
 
			// avoid circular references
			if (in_array($id,$embedded_pages_by_plugin_embed))
				return false;
 
			array_push($embedded_pages_by_plugin_embed,$id);
 
			$ins = $this->_embed_file($id,$replacement);	 
			$renderer->doc .= p_render('xhtml', $ins, $info);            // ptype = 'normal'
 
			array_pop($embedded_pages_by_plugin_embed);
 
			return true;
		}
		return false;
	}
 
	function _embed_file($id,$replacement) { 
 
 
		// check permission
		$perm = auth_quickaclcheck($id);
		if ($perm < AUTH_READ) return false;
 
 
		//Read embeded page
		$page = io_readfile(wikiFN($id));
 
		// convert relative links
		$page = $this->_convertInstructions($page,$id);
 
		// do replacements (on text-base to preserve List indentation and ordering etc.):
		$page = $this->_do_replacements($page,$replacement);
 
		$ins = p_get_instructions($page);						
 
		return $ins;
	}
 
	function _do_replacements($page,$r_str) {		  
		//Build up list of replacements (this needs to be done manually to allow several replacements with nesting if <label>s
		$r_list = array();
		preg_match_all('/<label\s+([a-zA-Z0-9_]+)\s*>/',$r_str, $matches_label, PREG_OFFSET_CAPTURE);
		preg_match_all('/<\/label>/',$r_str, $matches_labelx, PREG_OFFSET_CAPTURE);		
 
		$level = 0;
		$element = array_shift($matches_label[1]);
		$end_element = array_shift($matches_labelx[0]);
		while ($element || $end_element) {
			if ($element && $element[1] < $end_element[1]) { // <label ..> before </label> 
				if ($level == 0) {		 
					$section_name = $element[0];
					$section_start = $element[1]+strlen($section_name)+1;
				} 
				$level++;
				$element = array_shift($matches_label[1]);					  
			} else {  //</label> before <label ..>
				$level--;
				if ($level == 0) {
					$section_end = $end_element[1];
					$r_list[$section_name] = substr($r_str,$section_start,$section_end-$section_start);
				}  
				$end_element = array_shift($matches_labelx[0]);
			}
		}
 
		// now do replacements
		foreach ($r_list as $section => $rep) {
			$page = preg_replace('/<label\s+' . $section .'\s*>.*?<\/label>/ms',$rep, $page);
		}
		return $page;
	}
 
	//Does not support CamelCase Links currently
	function _convert_link($link,$inclNS) {
 
		//Check if external:
		if (preg_match('/^(https?:\/\/|mailto:|\\\\)/',$link)) 
		return $link;
 
		//check if interwiki or email:
		if (strpos('>',$link) !== false || strpos('@',$link) !== false)
		return $link;
 
		// convert internal links and media from relative to absolute 
 
		// relative subnamespace 
		if ($link{0} == '.') {
			// parent namespace
			if ($link{1} == '.')
			$link = getNS($inclNS).':'.substr($link, 2);
			// current namespace
			else
			$link = $inclNS.':'.substr($link, 1);
		} elseif (strpos($link, ':') === false){
			$link = $inclNS.':'.$link;
		} 
 
		return $link;
	}
 
	function _convertInstructions($page,$page_id) {
		global $ID; 
 
		if (! $page) return;
 
		// check if embeded page is in same namespace 
		$inclNS = getNS($page_id);
		if (getNS($ID) == $inclNS) return $page; 
 
		// convert links
		$page = preg_replace("/\[\[([^\|\]]+)(\|[^\]]+)?\]\]/e",
		"'[[' . \$this->_convert_link('\\1','$inclNS') . '\\2]]'",
		$page);
 
		//convert embeddings
		$page = preg_replace("/<embed\s+([^>]+)\s*\/?>/e",
		"'<embed ' . \$this->_convert_link('\\1','$inclNS') . '>'",
		$page);
 
		//convert images
		$page = preg_replace("/{{(\s*)([^ \|}]+)(\s*)(||[^}]+)}}/e",
		"'{{\\1' . \$this->_convert_link('\\2','$inclNS') . '\\3\\4}}'",
		$page);
		return $page;
 
	}
}
//Setup VIM: ex: et ts=4 enc=utf-8 :

Bugs?

Getting Fatal error: Maximum execution time of 35 seconds exceeded in lib/plugins/embed/syntax.php on line 139? Using DokuWiki 2008-05-05. I'm trying to embed 2 pages in one sidebar

Some problem with the embedding engine leads to no generation of TOC for <embed>ed headers. Any way to fix this?

I've no clue, since all I do is text-substitution…
Take a look at the include plugin. It does something quite similar to what you are doing and has solved the caching and header issues, you may be able to reuse some of its ideas/code. — Christopher Smith 2007-07-10 14:29
I started with this plugin, but since it works not on the text, but on the node representation of wikisource, the substitution of elements (via label) was incompatible with the list rendering (and therefore not acceptable)

Embeds with absolute internal links go wrong; they come out as ns:ns:page instead of just ns:page. fixed by change line 184 from

} elseif (strpos($link, ':') === false){

to

} elseif (strpos($link, ':')){

Stopped working

I wanted to make a “dynamic mediawiki style infobox” and this was the best plugin for it, until a day it stopped working.

plugin/embed.txt · Last modified: 2017-02-18 23:32 by 79.121.122.71