WikiContent using easy-markdown-editor

This commit is contained in:
José David Guillén 2022-04-27 19:08:42 +00:00
parent 72489186ae
commit 5dc38e2de9
11 changed files with 117 additions and 128 deletions

View File

@ -62,6 +62,8 @@ or:
for integration tests for integration tests
// Markdown editor: https://simplemde.com/
// https://github.com/Ionaru/easy-markdown-editor
//--- //---
@ -74,10 +76,12 @@ podman run --name=nextcloud --replace=true -p 8080:80 -v /absolute/path/to/apps:
sudo docker run --name=nextcloud -p 8080:80 -v /absolute/path/to/apps:/var/www/html/custom_apps nextcloud sudo docker run --name=nextcloud -p 8080:80 -v /absolute/path/to/apps:/var/www/html/custom_apps nextcloud
Version000000Date20220302210900
//--- //---
php ./occ migrations:execute <appId> <versionNumber> php ./occ migrations:execute <appId> <versionNumber>
Example: sudo -u www-data php ./occ migrations:execute photos 000000Date20201002183800 Example: sudo -u www-data php ./occ migrations:execute mywiki 000000Date20220302210900
https://c.infdj.com/apps/files/?dir=/Documents/Manuals%20-%20Drivers/drivers/MAD&fileid=19227 https://c.infdj.com/apps/files/?dir=/Documents/Manuals%20-%20Drivers/drivers/MAD&fileid=19227

View File

@ -13,7 +13,7 @@
<category>organization</category> <category>organization</category>
<bugs>https://git.jd.guillen.io/wiki4nextcloud/issues</bugs> <bugs>https://git.jd.guillen.io/wiki4nextcloud/issues</bugs>
<dependencies> <dependencies>
<nextcloud min-version="12" max-version="12"/> <nextcloud min-version="12" max-version="24"/>
</dependencies> </dependencies>
<navigations> <navigations>
<navigation> <navigation>

View File

@ -1,23 +1,31 @@
#hello {
color: red;
}
li[data-id="wikis"] select { li[data-id="wikis"] select {
width: calc(100% - 50px); width: calc(100% - 50px);
} }
.-myWikiControls { li[class^="wikiPage-lvl-"] a::before {
width: 100%; display: inline-block;
margin: .25em;
} }
.-myWikiControls select { .wikiPage-lvl-1 a::before {
width: 98%; content: "•";
width: 1em;
}
.wikiPage-lvl-2 a::before {
content: "• •";
width: 1.5em;
}
.wikiPage-lvl-3 a::before {
content: "• • •";
width: 2em;
} }
option.separator { #app {
font-size: 1px; width:100%;
min-height:1px;
max-height:1px;
padding:0;
background-color: #000000;
} }
#app-content #app-content-wrapper {
display: inline;
}
#app-content-wrapper textarea {
width:100%;
height:100%;
}

View File

@ -4,13 +4,14 @@ class WikiPages {
/* /*
* The container is the <ul> for the navigation panel * The container is the <ul> for the navigation panel
*/ */
constructor(container) { constructor(container, onClickLoadPage) {
this.ul = container; this.ul = container;
this.wikiId = null; this._onClickLoadPage = onClickLoadPage;
} }
clear() { clear() {
this.ul.querySelectorAll('[data-wiki-id]').forEach( x=>x.remove() ); this.wikiId = null;
this.ul.querySelectorAll('[data-page-id]').forEach( x=>x.remove() );
} }
getWikiId() { getWikiId() {
@ -20,9 +21,8 @@ class WikiPages {
load(wikiId) { load(wikiId) {
const self = this; const self = this;
console.info('JDG :: Loading wiki', self.getWikiId() ); console.info('JDG :: Loading wiki', self.getWikiId() );
this.wikiId = null; this.clear();
if (wikiId<=0) { if (wikiId<=0) {
this.clear();
return; return;
} }
@ -43,12 +43,7 @@ class WikiPages {
draw(pages, lvl=0, pid=0) { draw(pages, lvl=0, pid=0) {
let self=this; const self=this;
if (lvl==0) {
this.clear();
}
// pages = [{"id":880,"pid":0,"title":"WikiTest","sort":1},...]
pages pages
.filter( x=>x.pid==pid ) .filter( x=>x.pid==pid )
.sort( (a,b)=>a.sort - b.sort ) .sort( (a,b)=>a.sort - b.sort )
@ -56,43 +51,52 @@ class WikiPages {
self.treeAdd(x.pid, x.id, x.title); self.treeAdd(x.pid, x.id, x.title);
self.draw(pages, lvl+1, x.id); self.draw(pages, lvl+1, x.id);
}); });
if (lvl==0) {
this.ul.querySelectorAll('button[data-id="add"]').forEach(x => x.addEventListener('click', e=>self.onClickAdd(e)) );
this.ul.querySelectorAll('button[data-id="delete"]').forEach(x => x.addEventListener('click', e=>self.onClickDelete(e)) );
this.ul.querySelectorAll('button[data-id="rename"]').forEach(x => x.addEventListener('click', e=>self.onClickEdit(e)) );
this.ul.querySelectorAll('.icon-close').forEach(x => x.addEventListener('click', e=>self.onClickClose(e)) );
this.ul.querySelectorAll('.icon-checkmark').forEach(x => x.addEventListener('click', e=>self.onClickRename(e)) );
}
} }
// ----------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------
addListener(root) {
const self = this;
root.querySelectorAll('a[data-id="page"]').forEach(x => x.addEventListener('click', e=>self.onClickLoadPage(e)) );
root.querySelectorAll('button[data-id="add"]').forEach(x => x.addEventListener('click', e=>self.onClickAdd(e)) );
root.querySelectorAll('button[data-id="delete"]').forEach(x => x.addEventListener('click', e=>self.onClickDelete(e)) );
root.querySelectorAll('button[data-id="rename"]').forEach(x => x.addEventListener('click', e=>self.onClickEdit(e)) );
root.querySelectorAll('.icon-close').forEach(x => x.addEventListener('click', e=>self.onClickClose(e)) );
root.querySelectorAll('.icon-checkmark').forEach(x => x.addEventListener('click', e=>self.onClickRename(e)) );
}
onClickLoadPage(e) {
const li = e.target.closest("li[data-page-id]");
let pageId = li.dataset.pageId;
this._onClickLoadPage(this.wikiId, pageId);
}
onClickEdit(e) { onClickEdit(e) {
const li = e.target.closest("li[data-wiki-id]"); const li = e.target.closest("li[data-page-id]");
li.querySelector("input").value = li.querySelector("a").innerText; li.querySelector("input").value = li.querySelector("a").innerText;
li.classList.add("editing"); li.classList.add("editing");
} }
onClickClose(e) { onClickClose(e) {
const li = e.target.closest("li[data-wiki-id]"); const li = e.target.closest("li[data-page-id]");
li.classList.remove("editing"); li.classList.remove("editing");
} }
onClickRename(e) { onClickRename(e) {
const li = e.target.closest("li[data-wiki-id]"); const li = e.target.closest("li[data-page-id]");
li.classList.remove("editing"); li.classList.remove("editing");
let pageId = li.dataset.wikiId; let pageId = li.dataset.pageId;
let value = li.querySelector('input').value; let value = li.querySelector('input').value;
this.rename(pageId, value); this.rename(pageId, value);
} }
onClickAdd(e) { onClickAdd(e) {
const li = e.target.closest("li[data-wiki-id]"); const li = e.target.closest("li[data-page-id]");
this.newPage(li?li.dataset.wikiId:0); this.newPage(li?li.dataset.pageId:0);
} }
onClickDelete(e) { onClickDelete(e) {
const li = e.target.closest("li[data-wiki-id]"); const self = this;
let pageId = li.dataset.wikiId; const li = e.target.closest("li[data-page-id]");
let pageId = li.dataset.pageId;
let pageTitle = li.querySelector('a').innerHTML; let pageTitle = li.querySelector('a').innerHTML;
OC.dialogs.confirm( t(appName, 'Delete the wiki page "{title}"?', {title:pageTitle}), OC.dialogs.confirm( t(appName, 'Delete the wiki page "{title}"?', {title:pageTitle}),
@ -129,7 +133,7 @@ class WikiPages {
// ----------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------
treeDelete(pageId) { treeDelete(pageId) {
const x = this.ul.querySelector(`[data-wiki-id="${pageId}"]`); const x = this.ul.querySelector(`[data-page-id="${pageId}"]`);
const pid = x.dataset.pid; const pid = x.dataset.pid;
x.parentNode.remove(x); x.parentNode.remove(x);
this.treeDeleteChildren(pageId); this.treeDeleteChildren(pageId);
@ -139,19 +143,19 @@ class WikiPages {
this.ul this.ul
.querySelectorAll(`[data-pid="${pageId}"]`) .querySelectorAll(`[data-pid="${pageId}"]`)
.forEach(x=>{ .forEach(x=>{
self.treeDeleteBranch( x.dataset.wikiId ); self.treeDeleteChildren( x.dataset.pageId );
x.parentNode.remove(x); x.parentNode.remove(x);
} }
); );
} }
treeRename(pageId, title) { treeRename(pageId, title) {
this.ul.querySelector(`[data-wiki-id="${pageId}"] a`).innerHTML = title; this.ul.querySelector(`[data-page-id="${pageId}"] a`).innerHTML = title;
} }
treeAdd(pid, pageId, title) { treeAdd(pid, pageId, title) {
let lvl = 0; let lvl = 0;
let nextNode, lastNode, parent = this.ul.querySelector(`[data-wiki-id="${pid}"]`); let nextNode, lastNode, parent = this.ul.querySelector(`[data-page-id="${pid}"]`);
if ( parent===null ) { if ( parent===null ) {
lastNode = this.ul.lastChild; lastNode = this.ul.lastChild;
} else { } else {
@ -163,14 +167,12 @@ class WikiPages {
} while(nextNode && nextNode.dataset.pid!=parent.dataset.pid); } while(nextNode && nextNode.dataset.pid!=parent.dataset.pid);
} }
const bullet = ' - ';
let li = document.createElement("li"); let li = document.createElement("li");
// li.classList.add("editing"); li.classList.add(`wikiPage-lvl-${lvl}`);
li.dataset.wikiId = pageId; li.dataset.pageId = pageId;
li.dataset.pid = pid||this.wikiId; li.dataset.pid = pid||this.wikiId;
li.dataset.lvl = lvl; li.dataset.lvl = lvl;
li.innerHTML = `<a href="#">${bullet.repeat(lvl)} ${title}</a> li.innerHTML = `<a href="#" data-id="page">${title}</a>
<div class="app-navigation-entry-utils"> <div class="app-navigation-entry-utils">
<ul> <ul>
<li class="app-navigation-entry-utils-menu-button"> <li class="app-navigation-entry-utils-menu-button">
@ -202,6 +204,7 @@ class WikiPages {
</ul> </ul>
</div> </div>
`; `;
this.addListener(li);
lastNode.parentNode.insertBefore(li, lastNode.nextSibling) lastNode.parentNode.insertBefore(li, lastNode.nextSibling)
} }

View File

@ -34,38 +34,12 @@ var MyWiki = MyWiki || {};
appNavigationEntryMenuClose(); appNavigationEntryMenuClose();
}) })
// ------------------------------------------------ // ------------------------------------------------
let wikiContent = new WikiContent(document.getElementById('app-content-wrapper'));
let wikiPages = new WikiPages(document.querySelector('li[data-id="pages"]').parentNode, (wikiId, pageId)=>wikiContent.load(wikiId, pageId));
let wikiPages = new WikiPages(document.querySelector('li[data-id="pages"]').parentNode, onSelectWikiPage);
let wikiNavigation = new WikiNavigation(document.querySelector('li[data-id="wikis"]'), let wikiNavigation = new WikiNavigation(document.querySelector('li[data-id="wikis"]'),
wikiId => wikiPages.load(wikiId), wikiId => wikiPages.load(wikiId),
e=>wikiPages.onClickAdd(e) e=>wikiPages.onClickAdd(e)
); );
function onSelectWikiPage(wikiPageId) {
console.info(`JDG :: WikiPage selected ${wikiPageId}` );
if ( wikiPageId > 0 ) {
// wikiEditor.load(wikiPage.getWikiId(), wikiPageId );
}
}
// ---------------------------------------------------------------------------------
$(`#${appName}-test`).on('click',test);
function test() {
var baseUrl = OC.generateUrl('/apps/mywiki/wikis');
$.ajax({
url: baseUrl + '/test',
type: 'GET',
contentType: 'application/json'
}).done(function (response) {
// handle success
$('output').html(response);
}).fail(function (response, code) {
// handle failure
$('output').html('<h2>'+response.statusText+'</h2><code>'+response.responseText+'</code>');
});
}
// ---------------------------------------------------------------------------------
})(window, jQuery, MyWiki); })(window, jQuery, MyWiki);

View File

@ -151,9 +151,24 @@ class WikiHelper {
return $wikiTreePage->id; return $wikiTreePage->id;
} }
public function getWikiPageContent($id): string {
try {
$pageFolder = $this->getFolderById($id);
$path = $pageFolder->getInternalPath().'/'.self::WIKI_FILE_CONTENT;
if ( $this->wikiFolder->nodeExists($path) ) {
return $this->getFileByName(self::WIKI_FILE_CONTENT)->getContent();
}
$this->wikiFolder->newFile(self::WIKI_FILE_CONTENT, '');
} catch(\Exception $ex) {
return null;
}
return '';
}
public function update(int $id, string $content) { public function update(int $id, string $content) {
try { try {
$path = $this->wikiFolder->getInternalPath().'/'.self::WIKI_FILE_CONTENT; $pageFolder = $this->getFolderById($id);
$path = $pageFolder->getInternalPath().'/'.self::WIKI_FILE_CONTENT;
if ( $this->wikiFolder->nodeExists($path) ) { if ( $this->wikiFolder->nodeExists($path) ) {
$this->getFileByName(self::WIKI_FILE_CONTENT)->putContent($content); $this->getFileByName(self::WIKI_FILE_CONTENT)->putContent($content);
} else { } else {

View File

@ -43,10 +43,13 @@ class WikiPageService {
} }
public function find(int $wikiId, int $id, string $userId) { public function find(int $wikiId, int $id, string $userId) {
echo "\nwikiId: $wikiId"; try {
echo "\nid: $id"; $wiki = $this->mapper->find($wikiId, $userId);
echo "\nuserId: $userId"; $wikiPageContent = $this->wikiHelper->setFolderId($wiki->getFileId())->getWikiPageContent($id);
die(); } catch(Exception $e) {
$this->handleException($e);
}
return ['content'=>$wikiPageContent];
} }
public function create(int $wikiId, int $parentFolderId, string $title, ?string $content, string $userId):array { public function create(int $wikiId, int $parentFolderId, string $title, ?string $content, string $userId):array {

View File

@ -1,10 +1 @@
<h1>Hello world</h1>
<div id="emptycontent">
<div>
<button id="MyWiki-test">Test</button>
</div>
<div>
<output></output>
</div>
</div>

View File

@ -1,6 +1,13 @@
<?php <?php
// ToDo: Must be a better way to include this
\OCP\Util::addStyle('mywiki', 'fontawesome/css/all.min');
\OCP\Util::addScript('mywiki', 'easy-markdown-editor-master/dist/easymde.min');
\OCP\Util::addStyle('mywiki', '../js/easy-markdown-editor-master/dist/easymde.min');
\OCP\Util::addScript('mywiki', 'WikiDropdownHelper'); \OCP\Util::addScript('mywiki', 'WikiDropdownHelper');
\OCP\Util::addScript('mywiki', 'WikiNavigation'); \OCP\Util::addScript('mywiki', 'WikiNavigation');
\OCP\Util::addScript('mywiki', 'WikiContent');
\OCP\Util::addScript('mywiki', 'WikiPages'); \OCP\Util::addScript('mywiki', 'WikiPages');
\OCP\Util::addScript('mywiki', 'script'); \OCP\Util::addScript('mywiki', 'script');
\OCP\Util::addStyle('mywiki', 'style'); \OCP\Util::addStyle('mywiki', 'style');

View File

@ -9,37 +9,22 @@
</ul> </ul>
</div> </div>
<div class="app-navigation-entry-menu"> <div class="app-navigation-entry-menu">
<ul> <ul>
<li> <li>
<button data-id="add" class="icon-folder">Add Wiki</button> <button data-id="add" class="icon-folder">Add Wiki</button>
</li> </li>
<li> <li>
<button disabled data-id="addPage" class="icon-add">Add Page</button> <button disabled data-id="addPage" class="icon-add">Add Page</button>
</li> </li>
<li> <li>
<button disabled data-id="rename" class="icon-rename">Rename Wiki</button> <button disabled data-id="rename" class="icon-rename">Rename Wiki</button>
</li> </li>
<li> <li>
<button disabled data-id="delete" class="icon-delete">Delete Wiki</button> <button disabled data-id="delete" class="icon-delete">Delete Wiki</button>
</li> </li>
</ul> </ul>
</div> </div>
</li> </li>
<li data-id="pages"> <li data-id="pages">
</li> </li>
</ul> </ul>
<div id="myWikiTree">
no data
</div>

View File

@ -6,9 +6,8 @@
</div> </div>
<div id="app-settings-content"> <div id="app-settings-content">
<!-- Your settings in here --> <!-- Your settings in here -->
<ul class="with-icon"> <ul>
<li data-id="deleteWiki"> <li>
<a href="#" class="icon-delete svg">Delete Current Wiki</a>
</li> </li>
</ul> </ul>
</div> </div>