1
0
mirror of https://github.com/til-schneider/slim-wiki.git synced 2025-08-09 18:16:38 +02:00

Added "create article" support

This commit is contained in:
til-schneider
2015-12-26 12:40:09 +01:00
parent 9651972351
commit 4d63af476d
10 changed files with 103 additions and 35 deletions

View File

@@ -16,6 +16,8 @@
if (mode == 'edit') {
initEditMode();
} else if (mode == 'createArticle') {
initCreateArticle();
} else if (mode == 'createUser') {
initCreateUserForm();
}
@@ -36,6 +38,21 @@
editor.on('scroll', onEditorScroll)
}
function initCreateArticle() {
document.getElementById('createArticleBtn').addEventListener('click', function() {
var articleFilename = slimwiki.settings.articleFilename,
pageTitle = slimwiki.settings.pageTitle;
callRpc('editor', 'createArticle', [ articleFilename, pageTitle ], function(result, error) {
if (error) {
console.error('Creating article failed:', error);
showErrorLogged();
} else {
location.href = slimwiki.settings.requestPath + '?edit';
}
})
});
}
function initCreateUserForm() {
document.getElementById('create-user-box').style.display = 'block';

View File

@@ -10,7 +10,7 @@ body {
// Views
#fatal-error-message {
#jumbo-message {
margin-top: 150px;
text-align: center;
font-size: 20px;

View File

@@ -37,7 +37,7 @@ function init() {
require_once __DIR__ . '/server/logic/Main.php';
Main::get()->dispatch($baseUrl, $basePath, $requestPathArray, $uriParts['query']);
(new Main())->dispatch($baseUrl, $basePath, $requestPathArray, $uriParts['query']);
}
init();

View File

@@ -11,6 +11,9 @@ $i18n = array(
'button.back' => 'Zurück',
'button.edit' => 'Bearbeiten',
'button.createUser' => 'Benutzer erstellen',
'button.createArticle' => 'Artikel anlegen',
'createArticle.text' => 'Diesen Artikel gibt es noch nicht.',
'createArticle.content' => 'Dies ist ihr neuer Artikel.',
'createUser.userName' => 'Benutzername',
'createUser.password' => 'Passwort',
'createUser.showConfig' => 'Konfiguration anzeigen',

View File

@@ -11,6 +11,9 @@ $i18n = array(
'button.back' => 'Back',
'button.edit' => 'Edit',
'button.createUser' => 'Create user',
'button.createArticle' => 'Create article',
'createArticle.text' => 'This article does not exist yet.',
'createArticle.content' => 'This is your new article.',
'createUser.userName' => 'User name',
'createUser.password' => 'Password',
'createUser.showConfig' => 'Show config',

View File

@@ -45,7 +45,9 @@ $mode = $data['mode'];
$settings = array(
"mode" => $mode
);
if ($mode == 'edit') {
if ($mode == 'edit' || $mode == 'createArticle') {
$settings['pageTitle'] = end($data['breadcrumbs'])['name'];
$settings['requestPath'] = $data['requestPath'];
$settings['articleFilename'] = $data['articleFilename'];
}
echo json_encode($settings);
@@ -61,14 +63,14 @@ $mode = $data['mode'];
if ($mode != 'view') {
// Show an error message if JavaScript is off or if the browser is not supported.
// NOTE: In view mode we don't show an error. Instead, syntax highlighting will be off for unsupported browsers.
?><div id="fatal-error-message"><div><?php echo ($mode == 'error') ? $data['fatalErrorMessage'] : $i18n['error.noJavaScript']; ?></div>
?><div id="jumbo-message"><div><?php echo ($mode == 'error') ? $data['fatalErrorMessage'] : $i18n['error.noJavaScript']; ?></div>
<a class="btn btn-default" href="<?php echo $data['requestPath']; ?>"><?php echo $i18n['button.back']; ?></a>
</div><?php
if ($mode != 'error') {
?><script type="text/javascript">
(function() {
var errElem = document.getElementById('fatal-error-message');
var errElem = document.getElementById('jumbo-message');
if (slimwiki.supportedBrowser) {
errElem.parentNode.removeChild(errElem);
} else {
@@ -104,7 +106,7 @@ if ($mode == 'edit') {
<?php
}
if ($mode == 'view' || $mode == 'edit') {
if ($mode == 'view' || $mode == 'edit' || $mode == 'noSuchArticle' || $mode == 'createArticle') {
?><nav class="breadcrumbs"><div class="main-column"><?php
$isFirst = true;
foreach ($data['breadcrumbs'] as $item) {
@@ -121,12 +123,23 @@ if ($mode == 'edit') {
if ($data['showCreateUserButton']) {
?><a class="btn btn-default btn-xs pull-right" href="<?php echo $data['requestPath']; ?>?createUser"><?php echo $i18n['button.createUser']; ?></a><?php
}
if ($mode == 'view') {
if ($mode == 'view' || $mode == 'noSuchArticle') {
?><a class="btn btn-default btn-xs pull-right" href="<?php echo $data['requestPath']; ?>?edit"><?php echo $i18n['button.edit']; ?></a><?php
}
?></div></nav>
<article id="content" class="markdown main-column"><?php echo $data['articleHtml']; ?></article><?php
} // if ($mode == 'view' || $mode == 'edit')
?></div></nav><?php
}
if ($mode == 'view' || $mode == 'edit') {
?><article id="content" class="markdown main-column"><?php echo $data['articleHtml']; ?></article><?php
}
if ($mode == 'noSuchArticle' || $mode == 'createArticle') {
?><div id="jumbo-message"><div><?php echo $i18n['createArticle.text']; ?></div><?php
if ($mode == 'createArticle') {
?><button id="createArticleBtn" class="btn btn-default""><?php echo $i18n['button.createArticle']; ?></button><?php
}
?></div><?php
}
if ($mode == 'createUser') {
?><form id="create-user-box" onsubmit="return false">
@@ -153,7 +166,7 @@ if ($mode == 'edit') {
?></div><?php // id="main-wrapper" ?>
<?php if ($mode == 'edit' || $mode == 'createUser') { ?>
<?php if ($mode == 'edit' || $mode == 'createArticle' || $mode == 'createUser') { ?>
<!-- build:js client/edit.js -->
<script src="client/libs/CodeMirror/lib/codemirror.js"></script>
<script src="client/libs/CodeMirror/addon/mode/overlay.js"></script> <!-- Allow language-in-language -->

View File

@@ -75,7 +75,7 @@ class Context {
public function getRenderService() {
if (is_null($this->renderService)) {
require_once __DIR__ . '/RenderService.php';
$this->renderService = new RenderService();
$this->renderService = new RenderService($this);
}
return $this->renderService;
}

View File

@@ -10,7 +10,7 @@ class EditorService {
}
public function isRpcMethod($methodName) {
return ($methodName == 'saveArticle' || $methodName == 'createUserConfig');
return ($methodName == 'createArticle' || $methodName == 'saveArticle' || $methodName == 'createUserConfig');
}
// Returns one of: 'logged-in', 'no-credentials', 'wrong-credentials'
@@ -62,6 +62,17 @@ class EditorService {
return null;
}
public function createArticle($articleFilename, $pageTitle) {
if (! $this->str_endswith($articleFilename, '.md')) {
$articleFilename .= '.md';
}
$markdownText = $pageTitle . "\n" . str_repeat('=', strlen($pageTitle)) . "\n\n"
. $this->context->getI18n()['createArticle.content'];
return $this->saveArticle($articleFilename, $markdownText);
}
public function saveArticle($articleFilename, $markdownText) {
$this->assertLoggedIn();
@@ -111,4 +122,11 @@ class EditorService {
return "\$config['user.".strtolower($user)."'] = array('type' => '$type', 'salt' => '$salt', 'hash' => '$hash');";
}
function str_endswith($string, $test) {
$strlen = strlen($string);
$testlen = strlen($test);
if ($testlen > $strlen) return false;
return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
}
}

View File

@@ -4,22 +4,13 @@ require_once __DIR__ . '/Context.php';
class Main {
private static $singleton;
private $context;
private function __construct() {
public function __construct() {
$this->context = new Context();
}
public static function get() {
if (is_null(self::$singleton)) {
self::$singleton = new self();
}
return self::$singleton;
}
// Parameters:
// - $baseUrl: E.g. 'http://localhost/slim-wiki/?edit'
// - $basePath: E.g. '/slim-wiki/'
@@ -96,18 +87,28 @@ class Main {
$articleFilename = $this->getArticleFilename($requestPathArray);
if ($articleFilename == null) {
header('HTTP/1.0 404 Not Found');
header('HTTP/1.0 403 Forbidden');
header('Content-Type:text/html; charset=utf-8');
echo '<h1>File not found</h1>'; // TODO: Show error page
echo '<h1>Forbidden</h1>';
} else {
$config = $this->context->getConfig();
$renderService = $this->context->getRenderService();
$fatalErrorMessage = null;
if ($mode == 'edit') {
$fatalErrorMessage = $this->context->getEditorService()->checkForError($articleFilename);
if ($mode == 'view') {
if (! $renderService->articleExists($articleFilename)) {
$mode = 'noSuchArticle';
}
} else if ($mode == 'edit') {
$editorService = $this->context->getEditorService();
$fatalErrorMessage = $editorService->checkForError($articleFilename);
if ($fatalErrorMessage != null) {
$fatalErrorMessage = $this->context->getI18n()['error.editingArticleFailed'] . '<br/>' . $fatalErrorMessage;
$mode = 'error';
} else if (! $renderService->articleExists($articleFilename)) {
$mode = 'createArticle';
$showCreateUserButton = false;
}
}
@@ -121,14 +122,17 @@ class Main {
$data[$key] = $config[$key];
}
$data['breadcrumbs'] = $this->createBreadcrumbs($requestPathArray, $config['wikiName']);
$data['breadcrumbs'] = $this->createBreadcrumbs($requestPathArray);
$data['showCreateUserButton'] = $showCreateUserButton;
$data['requestPath'] = implode('/', $requestPathArray);
$data['articleFilename'] = $articleFilename;
$articleMarkdown = file_get_contents($this->context->getArticleBaseDir() . $articleFilename);
$data['articleMarkdown'] = $articleMarkdown;
$data['articleHtml'] = $this->context->getRenderService()->renderMarkdown($articleMarkdown, $mode == 'edit');
if ($mode == 'view' || $mode == 'edit') {
$articleMarkdown = file_get_contents($this->context->getArticleBaseDir() . $articleFilename);
$data['articleMarkdown'] = $articleMarkdown;
$data['articleHtml'] = $renderService->renderMarkdown($articleMarkdown, $mode == 'edit');
}
$this->renderPage($data);
}
@@ -162,14 +166,13 @@ class Main {
if (! $this->context->isValidArticleFilename($articleFilename)) {
// Attempt to break out of article base directory (e.g. `../../outside.ext`)
return null;
} else if (file_exists($articleFullFilename) && is_readable($articleFullFilename)) {
return $articleFilename;
} else {
return null;
return $articleFilename;
}
}
private function createBreadcrumbs($requestPathArray, $wikiName) {
private function createBreadcrumbs($requestPathArray) {
$wikiName = $this->context->getConfig()['wikiName'];
$pathCount = count($requestPathArray);
$breadcrumbArray = array(array('name' => $wikiName, 'path' => '', 'active' => ($pathCount == 0)));

View File

@@ -2,6 +2,17 @@
class RenderService {
private $context;
public function __construct($context) {
$this->context = $context;
}
public function articleExists($articleFilename) {
return file_exists($this->context->getArticleBaseDir() . $articleFilename);
}
public function renderMarkdown($markdownText, $isEditMode) {
require_once __DIR__ . '/../lib/parsedown/Parsedown.php';
$html = Parsedown::instance()->text($markdownText);