Render resources in markdown context properly and implement all the

documented render options.
This commit is contained in:
Thomas Keller 2011-12-06 01:39:45 +01:00
parent 3897d7facb
commit 8fde1e4762
5 changed files with 221 additions and 11 deletions

View File

@ -55,8 +55,17 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
$text = IDF_Template_safePregReplace('#\[\[([A-Za-z0-9\-]+)\]\]#im', $text = IDF_Template_safePregReplace('#\[\[([A-Za-z0-9\-]+)\]\]#im',
array($this, 'callbackWikiPageNoName'), array($this, 'callbackWikiPageNoName'),
$text); $text);
$filter = new IDF_Template_MarkdownPrefilter(); $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) function callbackWikiPageNoName($m)
@ -80,6 +89,85 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage', array($this->project->shortname, $pages[0]->title)).'" title="'.Pluf_esc($pages[0]->summary).'">'.$m[1].'</a>'; return '<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::viewPage', array($this->project->shortname, $pages[0]->title)).'" title="'.Pluf_esc($pages[0]->summary).'">'.$m[1].'</a>';
} }
function callbackWikiResource($m)
{
@list($match, $resourceName, $opts) = $m;
if (!$this->request->rights['hasWikiAccess']) {
return '<span title="'.__('You are not allowed to access the wiki.').'">'.$match.'</span>';
}
$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 '<span title="'.__('The wiki resource has not been found.').'">'.$match.'</span>';
}
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::createResource',
array($this->project->shortname),
array('name' => $resourceName));
return '<img style="vertical-align: text-bottom;" alt=" " src="'.Pluf::f('url_media').'/idf/img/add.png" />'.
'<a href="'.$url.'" title="'.__('The wiki resource has not been found. Create it!').'">'.$match.'</a>';
}
// 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 '<span title="'.__('This revision of the resource is no longer available.').'">'.$match.'</span>';
}
}
$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) function callbackEmbeddedDoc($m)
{ {
$scm = IDF_Scm::get($this->request->project); $scm = IDF_Scm::get($this->request->project);

View File

@ -99,6 +99,14 @@ class IDF_Wiki_PageRevision extends Pluf_Model
'type' => 'normal', '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() function changedRevision()

View File

@ -101,6 +101,14 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model
'verbose' => __('creation date'), '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() function __toString()
@ -165,11 +173,22 @@ class IDF_Wiki_ResourceRevision extends Pluf_Model
$this->get_wikiresource()->id, $this->id, $this->fileext); $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(); $prj = $this->get_wikiresource()->get_project();
return Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::rawResource', 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 = '<div class="resource-container" style="'.implode(';', $styles).'">';
if ($opts['preview'] == 'yes' && !empty($raw)) {
$html .= '<div class="preview">'.$raw.'</div>'."\n";
} else {
$rawUrl = $this->getRawURL(true);
$download = '<a href="'.$rawUrl.'" class="download" title="'.sprintf(__('Download (%s)'), Pluf_Utils::prettySize($this->filesize)).'"></a>';
}
$resource = $this->get_wikiresource(); $resource = $this->get_wikiresource();
$title = $opts['title'];
if (empty($title)) {
$title = $resource->title.' - '.$resource->mime_type.' - '.Pluf_Utils::prettySize($this->filesize);
}
$html .= '<div class="title">'.$download.'<a href="'.$viewUrl.'" title="'.__('View resource details').'">'.$title.'</a></div>'."\n";
$html .= '</div>';
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)) { if (preg_match('#^image/(gif|jpeg|png|tiff)$#', $resource->mime_type)) {
return sprintf('<a href="%s"><img src="%s" alt="%s" /></a>', $url, $url, $resource->title); return sprintf('<img src="%s" alt="%s" />', $url, $resource->title);
} }
if (preg_match('#^text/(xml|html|sgml|javascript|ecmascript|css)$#', $resource->mime_type)) { if (preg_match('#^text/(xml|html|sgml|javascript|ecmascript|css)$#', $resource->mime_type)) {
return sprintf('<iframe src="%s" alt="%s"></iframe>', $url, $resource->title); return sprintf('<iframe src="%s" alt="%s"></iframe>', $url, $resource->title);
} }
return __('Unable to render preview for this MIME type.'); return '';
} }
} }

View File

@ -19,13 +19,16 @@ by {$submitter}.{/blocktrans}</p>
<div id="wiki-resource"> <div id="wiki-resource">
<p class="desc">{$resource.summary}</p> <p class="desc">{$resource.summary}</p>
<p class="preview">{$rev.render()|unsafe}</p> {assign $preview = $rev.renderRaw()}
{if $preview == ''}
{assign $preview = __('Unable to render preview for this MIME type.')}
{/if}
<p class="preview">{$preview|unsafe}</p>
{aurl 'url', 'IDF_Views_Wiki::rawResource', array($project.shortname, $rev.id), array('attachment' => 1)}
<ul> <ul>
<li>{trans 'File size'}: {$rev.filesize|size}</li> <li>{trans 'File size'}: {$rev.filesize|size}</li>
<li>{trans 'MIME type'}: {$resource.mime_type}</li> <li>{trans 'MIME type'}: {$resource.mime_type}</li>
<li><a href="{$url}">{trans 'Download this file'}</a></li> <li><a href="{$rev.getRawURL(true)}">{trans 'Download this file'}</a></li>
</ul> </ul>
{if ($isOwner or $isAdmin) and !$rev.is_head}{aurl 'url', 'IDF_Views_Wiki::deleteResourceRev', array($project.shortname, $rev.id)} {if ($isOwner or $isAdmin) and !$rev.is_head}{aurl 'url', 'IDF_Views_Wiki::deleteResourceRev', array($project.shortname, $rev.id)}
<p class="delp"><a href="{$url}" title="{trans 'Delete this revision'}"><img src="{media '/idf/img/trash.png'}" style="vertical-align: text-bottom;" alt="{trans 'Trash'}" /></a> <a href="{$url}">{trans 'Delete this revision'}</a></p> <p class="delp"><a href="{$url}" title="{trans 'Delete this revision'}"><img src="{media '/idf/img/trash.png'}" style="vertical-align: text-bottom;" alt="{trans 'Trash'}" /></a> <a href="{$url}">{trans 'Delete this revision'}</a></p>

View File

@ -928,6 +928,40 @@ ol > li {
margin-left: 2em; 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 * main menu
*/ */