mirror of
https://github.com/til-schneider/slim-wiki.git
synced 2025-08-09 01:56:40 +02:00
Added "create article" support
This commit is contained in:
@@ -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';
|
||||
|
||||
|
@@ -10,7 +10,7 @@ body {
|
||||
|
||||
// Views
|
||||
|
||||
#fatal-error-message {
|
||||
#jumbo-message {
|
||||
margin-top: 150px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
|
@@ -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();
|
||||
|
@@ -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',
|
||||
|
@@ -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',
|
||||
|
@@ -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 -->
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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)));
|
||||
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user