From 8fde1e4762e8ff9f36acbf8602b099c2f7bd2211 Mon Sep 17 00:00:00 2001
From: Thomas Keller
Date: Tue, 6 Dec 2011 01:39:45 +0100
Subject: [PATCH] Render resources in markdown context properly and implement
all the documented render options.
---
src/IDF/Template/Markdown.php | 90 ++++++++++++++++++-
src/IDF/Wiki/PageRevision.php | 8 ++
src/IDF/Wiki/ResourceRevision.php | 91 ++++++++++++++++++--
src/IDF/templates/idf/wiki/viewResource.html | 9 +-
www/media/idf/css/style.css | 34 ++++++++
5 files changed, 221 insertions(+), 11 deletions(-)
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())
{
- $url = $this->getFileURL();
+ // 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 = '';
+ if ($opts['preview'] == 'yes' && !empty($raw)) {
+ $html .= '
'.$raw.'
'."\n";
+ } else {
+ $rawUrl = $this->getRawURL(true);
+ $download = '
';
+ }
$resource = $this->get_wikiresource();
+ $title = $opts['title'];
+ if (empty($title)) {
+ $title = $resource->title.' - '.$resource->mime_type.' - '.Pluf_Utils::prettySize($this->filesize);
+ }
+ $html .= '
'."\n";
+ $html .= '
';
+ return $html;
+ }
+
+ /**
+ * Renders a raw version of the resource, without any possibilities of formatting or the like
+ */
+ function renderRaw()
+ {
+ $resource = $this->get_wikiresource();
+ $url = $this->getRawURL();
if (preg_match('#^image/(gif|jpeg|png|tiff)$#', $resource->mime_type)) {
- return sprintf('', $url, $url, $resource->title);
+ return sprintf('', $url, $resource->title);
}
if (preg_match('#^text/(xml|html|sgml|javascript|ecmascript|css)$#', $resource->mime_type)) {
return sprintf('', $url, $resource->title);
}
- return __('Unable to render preview for this MIME type.');
+ return '';
}
}
diff --git a/src/IDF/templates/idf/wiki/viewResource.html b/src/IDF/templates/idf/wiki/viewResource.html
index 149159d..726f69f 100644
--- a/src/IDF/templates/idf/wiki/viewResource.html
+++ b/src/IDF/templates/idf/wiki/viewResource.html
@@ -19,13 +19,16 @@ by {$submitter}.{/blocktrans}
{$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)}
{if ($isOwner or $isAdmin) and !$rev.is_head}{aurl 'url', 'IDF_Views_Wiki::deleteResourceRev', array($project.shortname, $rev.id)}
{trans 'Delete this revision'}
diff --git a/www/media/idf/css/style.css b/www/media/idf/css/style.css
index 4ccf0ca..5454e0c 100644
--- a/www/media/idf/css/style.css
+++ b/www/media/idf/css/style.css
@@ -928,6 +928,40 @@ ol > li {
margin-left: 2em;
}
+.resource-container {
+ border: 1px solid #EEE;
+ padding: 5px;
+}
+
+.resource-container .preview {
+ margin-bottom: 5px;
+}
+
+.resource-container .preview * {
+ width: 100%;
+ height: 100%;
+}
+
+.resource-container .preview img {
+ height: auto;
+}
+
+.resource-container .preview + .title {
+ font-size: 80%;
+}
+
+.resource-container .title * {
+ vertical-align: middle;
+}
+
+.resource-container .title .download {
+ display: inline-block;
+ margin-right: 5px;
+ background: url("../img/down-large.png") no-repeat;
+ width: 22px;
+ height: 22px;
+}
+
/**
* main menu
*/