From: Christian Weiske Date: Tue, 17 Mar 2015 21:03:39 +0000 (+0100) Subject: reStructuredText output X-Git-Tag: v0.5.0~4 X-Git-Url: https://git.cweiske.de/grauphel.git/commitdiff_plain/a375467d42cb53599ffddbd1d7ce8fae028972f8?hp=81554f1309cc6a80578100b9583a591012df0d43 reStructuredText output --- diff --git a/appinfo/routes.php b/appinfo/routes.php index c96ec30..29ce8ad 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -73,6 +73,11 @@ $application->registerRoutes( 'name' => 'notes#html', 'verb' => 'GET', ), + array( + 'url' => '/note/{guid}.txt', + 'name' => 'notes#text', + 'verb' => 'GET', + ), array( 'url' => '/note/{guid}.xml', 'name' => 'notes#xml', diff --git a/controller/guicontroller.php b/controller/guicontroller.php index 15380c7..29dd03f 100644 --- a/controller/guicontroller.php +++ b/controller/guicontroller.php @@ -130,6 +130,9 @@ class GuiController extends Controller 'guid' => $guid, 'username' => $this->user->getUid() ) ), + 'text' => $this->urlGen->linkToRoute( + 'grauphel.notes.text', array('guid' => $guid) + ), 'xml' => $this->urlGen->linkToRoute( 'grauphel.notes.xml', array('guid' => $guid) ), diff --git a/controller/notescontroller.php b/controller/notescontroller.php index 893a100..c599e75 100644 --- a/controller/notescontroller.php +++ b/controller/notescontroller.php @@ -124,7 +124,7 @@ class NotesController extends Controller } catch (\OCA\Grauphel\Converter\Exception $e) { $res = new ErrorResponse( 'Error converting note to HTML.' - . ' Please repport a bug to the grauphel developers.' + . ' Please report a bug to the grauphel developers.' ); $res->setStatus(\OCP\AppFramework\Http::STATUS_NOT_FOUND); return $res; @@ -141,6 +141,44 @@ class NotesController extends Controller return urlencode($noteTitle) . '.html'; } + /** + * Output a note as a standalone text file + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function text($guid) + { + $note = $this->getNotes()->load($guid, false); + if ($note === null) { + $res = new ErrorResponse('Note does not exist'); + $res->setStatus(\OCP\AppFramework\Http::STATUS_NOT_FOUND); + return $res; + } + + $converter = new \OCA\Grauphel\Converter\ReStructuredText(); + $converter->internalLinkHandler = array($this, 'textNoteLinkHandler'); + try { + $text = $note->title . "\n" + . str_repeat('*', strlen($note->title)) . "\n" + . "\n"; + $text .= $converter->convert($note->{'note-content'}); + return new \OCA\Grauphel\Response\TextResponse($text); + } catch (\OCA\Grauphel\Converter\Exception $e) { + $res = new ErrorResponse( + 'Error converting note to reStructuredText.' + . ' Please report a bug to the grauphel developers.' + ); + $res->setStatus(\OCP\AppFramework\Http::STATUS_NOT_FOUND); + return $res; + } + } + + public function textNoteLinkHandler($noteTitle) + { + return $noteTitle; + } + /** * Output a note in tomboy XML format * diff --git a/lib/converter/base.php b/lib/converter/base.php new file mode 100644 index 0000000..2694374 --- /dev/null +++ b/lib/converter/base.php @@ -0,0 +1,63 @@ + + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @link http://cweiske.de/grauphel.htm + */ +namespace OCA\Grauphel\Converter; + +/** + * Base class to convert tomboy XML to some other format. + * + * @category Tools + * @package Grauphel + * @author Christian Weiske + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @version Release: @package_version@ + * @link http://cweiske.de/grauphel.htm + */ +class Base +{ + /** + * Re-arranges the XML of formatted links to that clean link tags can + * be generated. + * + * Tomboy 1.15.2 allows link formatting, and the resulting XML is a + * mess of multiple(!) link tags that are within or around other formatting + * tags. + * + * This method tries to re-arrange the links so that only a single link tag + * appears with all the formatting inside. + * + * @param string $xmlContent Tomboy note content + * + * @return string XML content, with re-arranged link tags. + */ + protected function fixNastyLinks($xmlContent) + { + preg_match_all( + '#(?:<.*>)?.+.+#U', + $xmlContent, + $matches + ); + + foreach ($matches[0] as $nastyLink) { + $cleaner = str_replace('', '', $nastyLink); + $cleaner = preg_replace('#<([a-z]+)><(link:internal)>#U', '<\2><\1>', $cleaner); + $cleaner = preg_replace('##U', '', $cleaner); + $cleaner = str_replace('', '', $cleaner); + $xmlContent = str_replace($nastyLink, $cleaner, $xmlContent); + } + + return $xmlContent; + } +} +?> diff --git a/lib/converter/html.php b/lib/converter/html.php index eeb2b66..a6a92bc 100644 --- a/lib/converter/html.php +++ b/lib/converter/html.php @@ -30,7 +30,7 @@ use \XMLReader; * @version Release: @package_version@ * @link http://cweiske.de/grauphel.htm */ -class Html +class Html extends Base { protected static $tagMap = array( 'list' => 'ul', @@ -159,39 +159,5 @@ class Html { return $linkUrl . '.htm'; } - - /** - * Re-arranges the XML of formatted links to that clean link tags can - * be generated. - * - * Tomboy 1.15.2 allows link formatting, and the resulting XML is a - * mess of multiple(!) link tags that are within or around other formatting - * tags. - * - * This method tries to re-arrange the links so that only a single link tag - * appears with all the formatting inside. - * - * @param string $xmlContent Tomboy note content - * - * @return string XML content, with re-arranged link tags. - */ - protected function fixNastyLinks($xmlContent) - { - preg_match_all( - '#(?:<.*>)?.+.+#U', - $xmlContent, - $matches - ); - - foreach ($matches[0] as $nastyLink) { - $cleaner = str_replace('', '', $nastyLink); - $cleaner = preg_replace('#<([a-z]+)><(link:internal)>#U', '<\2><\1>', $cleaner); - $cleaner = preg_replace('##U', '', $cleaner); - $cleaner = str_replace('', '', $cleaner); - $xmlContent = str_replace($nastyLink, $cleaner, $xmlContent); - } - - return $xmlContent; - } } ?> diff --git a/lib/converter/restructuredtext.php b/lib/converter/restructuredtext.php new file mode 100644 index 0000000..8419af6 --- /dev/null +++ b/lib/converter/restructuredtext.php @@ -0,0 +1,188 @@ + + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @link http://cweiske.de/grauphel.htm + */ +namespace OCA\Grauphel\Converter; +use \XMLReader; + +/** + * Convert Tomboy note XML to reStructuredText. + * Mainly used to paste the content of a note into an e-mail + * + * @category Tools + * @package Grauphel + * @author Christian Weiske + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @version Release: @package_version@ + * @link http://cweiske.de/grauphel.htm + */ +class ReStructuredText extends Base +{ + protected static $simpleMap = array( + 'bold' => '**', + 'italic' => '*', + 'monospace' => '``', + 'strikethrough' => '-', + 'highlight' => '**', + ); + + public $internalLinkHandler; + + + + public function __construct() + { + $this->internalLinkHandler = array($this, 'internalLinkHandler'); + } + + /** + * Converts the tomboy note XML into reStructuredText + * + * @param string $xmlContent Tomboy note content + * + * @return string Plain text + */ + public function convert($xmlContent) + { + if (strpos($xmlContent, '') !== false) { + $xmlContent = $this->fixNastyLinks($xmlContent); + } + + $rst = ''; + $reader = new XMLReader(); + $reader->xml( + '' . "\n" + . '' + . $xmlContent + . '' + ); + + $withinLink = false; + $store = &$rst; + $listLevel = -1; + $listPrefix = ''; + $listItemCount = 0; + $heading = false; + $headingLength = 0; + while ($reader->read()) { + switch ($reader->nodeType) { + case XMLReader::ELEMENT: + //echo $reader->name . "\n"; + if (isset(static::$simpleMap[$reader->name])) { + $store .= static::$simpleMap[$reader->name]; + } else if ($reader->name == 'list') { + ++$listLevel; + $listItemCount = 0; + $listPrefix = str_repeat(' ', $listLevel); + } else if ($reader->name == 'list-item') { + ++$listItemCount; + if ($listItemCount == 1) { + $store .= "\n"; + } + $store .= $listPrefix . '- '; + } else if ($reader->name == 'size:large' + || $reader->name == 'size:huge' + ) { + $store .= "\n"; + $heading = true; + } else if (substr($reader->name, 0, 5) == 'link:') { + $withinLink = true; + $linkText = ''; + $store = &$linkText; + } + break; + case XMLReader::END_ELEMENT: + if (isset(static::$simpleMap[$reader->name])) { + $store .= static::$simpleMap[$reader->name]; + } else if ($reader->name == 'list') { + --$listLevel; + $listPrefix = str_repeat(' ', $listLevel); + if ($listLevel == -1) { + $store .= "\n"; + } + } else if ($reader->name == 'size:large') { + $store .= "\n" . str_repeat('-', $headingLength); + $heading = false; + } else if ($reader->name == 'size:huge') { + $store .= "\n" . str_repeat('=', $headingLength); + $heading = false; + } else if (substr($reader->name, 0, 5) == 'link:') { + $withinLink = false; + $store = &$rst; + $linkUrl = htmlspecialchars_decode(strip_tags($linkText)); + if ($reader->name == 'link:internal') { + $linkUrl = call_user_func($this->internalLinkHandler, $linkUrl); + } else { + $linkUrl = $this->fixLinkUrl($linkUrl); + } + $store .= $linkUrl; + } + break; + case XMLReader::TEXT: + case XMLReader::SIGNIFICANT_WHITESPACE: + if ($heading) { + $headingLength = strlen(trim($reader->value)); + $store .= trim($reader->value); + } else { + $text = wordwrap($reader->value, 72 - 2 * $listLevel, "\n", true); + $parts = explode("\n", $text); + foreach ($parts as $k => $v) { + if ($k == 0) { + continue; + } + if ($v != '') { + $parts[$k] = str_repeat(' ', $listLevel * 2 + 2) . $v; + } + } + $store .= implode("\n", $parts); + } + break; + default: + throw new Exception( + 'Unsupported XML node type: ' . $reader->nodeType + ); + } + } + + return $rst; + } + + /** + * Fixes external URLs without a protocol + * + * @param string $linkUrl URL to fix + * + * @return string Fixed URL + */ + protected function fixLinkUrl($linkUrl) + { + if ($linkUrl{0} == '/') { + //Unix file path + $linkUrl = 'file://' . $linkUrl; + } + return $linkUrl; + } + + /** + * Dummy internal link handler that simply adds ".htm" to the note title + * + * @param string $linkUrl Title of page that is linked + * + * @return string URL to link to + */ + public function internalLinkHandler($linkUrl) + { + return $linkUrl . '.htm'; + } +} +?> diff --git a/lib/response/textresponse.php b/lib/response/textresponse.php new file mode 100644 index 0000000..ba6bb70 --- /dev/null +++ b/lib/response/textresponse.php @@ -0,0 +1,43 @@ + + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @link http://cweiske.de/grauphel.htm + */ +namespace OCA\Grauphel\Response; + +/** + * Returns plain text + * + * @category Tools + * @package Grauphel + * @author Christian Weiske + * @copyright 2014 Christian Weiske + * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3 + * @version Release: @package_version@ + * @link http://cweiske.de/grauphel.htm + */ +class TextResponse extends \OCP\AppFramework\Http\Response +{ + protected $text; + + public function __construct($text) + { + $this->setStatus(\OCP\AppFramework\Http::STATUS_OK); + $this->addHeader('Content-Type', 'text/plain; charset=utf-8'); + $this->text = $text; + } + + public function render() + { + return $this->text; + } +} +?> diff --git a/templates/gui-note.php b/templates/gui-note.php index 86336bc..ae004d6 100644 --- a/templates/gui-note.php +++ b/templates/gui-note.php @@ -8,6 +8,7 @@