WikiContent using easy-markdown-editor
This commit is contained in:
parent
72489186ae
commit
5dc38e2de9
@ -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
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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%;
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
|
30
js/script.js
30
js/script.js
@ -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);
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -1,10 +1 @@
|
|||||||
<h1>Hello world</h1>
|
|
||||||
|
|
||||||
<div id="emptycontent">
|
|
||||||
<div>
|
|
||||||
<button id="MyWiki-test">Test</button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<output></output>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -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');
|
||||||
|
@ -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>
|
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user