diff --git a/src/IDF/Template/Markdown.php b/src/IDF/Template/Markdown.php index c058d63..82b12cd 100644 --- a/src/IDF/Template/Markdown.php +++ b/src/IDF/Template/Markdown.php @@ -55,8 +55,17 @@ class IDF_Template_Markdown extends Pluf_Template_Tag $text = IDF_Template_safePregReplace('#\[\[([A-Za-z0-9\-]+)\]\]#im', array($this, 'callbackWikiPageNoName'), $text); + $filter = new IDF_Template_MarkdownPrefilter(); - echo $filter->go(Pluf_Text_MarkDown_parse($text)); + $text = $filter->go(Pluf_Text_MarkDown_parse($text)); + + // Replace [[!ResourceName]] with corresponding HTML for the resource; + // we need to do that after the HTML filtering as we'd otherwise be unable to use + // certain HTML elements, such as iframes, that are used to display text content + // FIXME: no support for escaping yet in place + echo IDF_Template_safePregReplace('#\[\[!([A-Za-z0-9\-]+)(?:,\s*([^\]]+))?\]\]#im', + array($this, 'callbackWikiResource'), + $text); } function callbackWikiPageNoName($m) @@ -80,6 +89,85 @@ class IDF_Template_Markdown extends Pluf_Template_Tag return ''.$m[1].''; } + function callbackWikiResource($m) + { + @list($match, $resourceName, $opts) = $m; + + if (!$this->request->rights['hasWikiAccess']) { + return ''.$match.''; + } + + $sql = new Pluf_SQL('project=%s AND title=%s', + array($this->project->id, $resourceName)); + $resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen())); + + if ($resources->count() == 0) { + if ($this->request->user->isAnonymous()) { + return ''.$match.''; + } + + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::createResource', + array($this->project->shortname), + array('name' => $resourceName)); + return ''. + ''.$match.''; + } + + // by default, render the most recent revision + $resourceRevision = $resources[0]->get_current_revision(); + + list($urlConf, $urlMatches) = $this->request->view; + + // if we currently look at an existing wiki page, look up its name and find the proper resource (if any) + if ($urlConf['model'] == 'IDF_Views_Wiki' && $urlConf['method'] == 'viewPage') { + $sql = new Pluf_SQL('project=%s AND title=%s', + array($this->project->id, $urlMatches[2])); + $pages = Pluf::factory('IDF_Wiki_Page')->getList(array('filter'=>$sql->gen())); + if ($pages->count() == 0) throw new Exception('page not found'); + $pageRevision = $pages[0]->get_current_revision(); + + // if we look at an old version of the page, figure out the resource version back then + if (isset($this->request->GET['rev']) and preg_match('/^[0-9]+$/', $this->request->GET['rev'])) { + $pageRevision = Pluf_Shortcuts_GetObjectOr404('IDF_Wiki_PageRevision', + $this->request->GET['rev']); + if ($pageRevision->wikipage != $pages[0]->id) { + return ''.$match.''; + } + } + + $sql = new Pluf_SQL('wikiresource=%s AND idf_wiki_pagerevision_id=%s', + array($resources[0]->id, $pageRevision->id)); + $resourceRevision = Pluf::factory('IDF_Wiki_ResourceRevision')->getOne( + array('filter' => $sql->gen(), 'view' => 'join_pagerevision')); + + } + + $validOpts = array( + 'align' => '/^(left|right|center)$/', + 'width' => '/^\d+(%|px|em)?$/', + 'height' => '/^\d+(%|px|em)?$/', + 'preview' => '/^yes|no$/', + 'title' => '/.+/', + ); + + $parsedOpts = array(); + // FIXME: no support for escaping yet in place + $opts = preg_split('/\s*,\s*/', $opts, -1, PREG_SPLIT_NO_EMPTY); + foreach ((array)@$opts as $opt) + { + list($key, $value) = preg_split('/\s*=\s*/', $opt, 2); + if (!array_key_exists($key, $validOpts)) { + continue; + } + if (!preg_match($validOpts[$key], $value)) { + continue; + } + $parsedOpts[$key] = $value; + } + + return $resourceRevision->render($parsedOpts); + } + function callbackEmbeddedDoc($m) { $scm = IDF_Scm::get($this->request->project); diff --git a/src/IDF/Wiki/PageRevision.php b/src/IDF/Wiki/PageRevision.php index 295bbd0..2b4c848 100644 --- a/src/IDF/Wiki/PageRevision.php +++ b/src/IDF/Wiki/PageRevision.php @@ -99,6 +99,14 @@ class IDF_Wiki_PageRevision extends Pluf_Model 'type' => 'normal', ), ); + $table = $this->_con->pfx.'idf_wiki_pagerevision_idf_wiki_resourcerevision_assoc'; + $this->_a['views'] = array( + 'join_pagerevision' => + array( + 'join' => 'LEFT JOIN '.$table + .' ON idf_wiki_pagerevision_id=id', + ), + ); } function changedRevision() diff --git a/src/IDF/Wiki/ResourceRevision.php b/src/IDF/Wiki/ResourceRevision.php index 4a0a3b7..13a8642 100644 --- a/src/IDF/Wiki/ResourceRevision.php +++ b/src/IDF/Wiki/ResourceRevision.php @@ -101,6 +101,14 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model 'verbose' => __('creation date'), ), ); + $table = $this->_con->pfx.'idf_wiki_pagerevision_idf_wiki_resourcerevision_assoc'; + $this->_a['views'] = array( + 'join_pagerevision' => + array( + 'join' => 'LEFT JOIN '.$table + .' ON idf_wiki_resourcerevision_id=id', + ), + ); } function __toString() @@ -165,11 +173,22 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model $this->get_wikiresource()->id, $this->id, $this->fileext); } - function getFileURL() + function getViewURL() + { + $prj = $this->get_wikiresource()->get_project(); + $resource = $this->get_wikiresource(); + return Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewResource', + array($prj->shortname, $resource->title), + array('rev' => $this->id)); + } + + function getRawURL($attachment = false) { + $query = $attachment ? array('attachment' => 1) : array(); $prj = $this->get_wikiresource()->get_project(); return Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::rawResource', - array($prj->shortname, $this->id)); + array($prj->shortname, $this->id), + $query); } /** @@ -195,20 +214,78 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model } /** - * Renders the resource + * Renders the resource with the given view options, including a link to the resource' detail page */ - function render() + function render($opts = array()) + { + // give some reasonable defaults + $opts = array_merge(array( + 'align' => 'left', + 'width' => '', + 'height' => '', + 'preview' => 'yes', // if possible + 'title' => '', + ), $opts); + + $attrs = array('class="resource-container"'); + $styles = array(); + if (!empty($opts['align'])) { + switch ($opts['align']) { + case 'left': + $styles[] = 'float: left'; + $styles[] = 'margin-right: 10px'; + break; + case 'center': + $styles[] = 'margin: 0 auto 0 auto'; + break; + case 'right': + $styles[] = 'float: right'; + $styles[] = 'margin-left: 10px'; + break; + } + } + if (!empty($opts['width'])) { + $styles[] = 'width:'.$opts['width']; + } + if (!empty($opts['height'])) { + $styles[] = 'height:'.$opts['height']; + } + + $raw = $this->renderRaw(); + $viewUrl = $this->getViewURL(); + $download = ''; + $html = '
{$resource.summary}
-{$rev.render()|unsafe}
+{assign $preview = $rev.renderRaw()} +{if $preview == ''} + {assign $preview = __('Unable to render preview for this MIME type.')} +{/if} +{$preview|unsafe}
-{aurl 'url', 'IDF_Views_Wiki::rawResource', array($project.shortname, $rev.id), array('attachment' => 1)}