commit
d9495f6afb
@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "mdwiki"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
clap = { version = "4.0.18", features = ["derive"] }
|
||||||
|
|
||||||
|
actix-web = "4"
|
||||||
|
actix-files = "0.6.2"
|
||||||
|
askama = { version = "0.11.1", features = ["with-actix-web"] }
|
||||||
|
askama_actix = "0.13.0"
|
||||||
|
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
git2 = "0.16.0"
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
mdwiki
|
||||||
|
======
|
||||||
|
|
||||||
|
Wiki utilisant la syntaxe MarkDown pour être rapide et facile à modifier.
|
||||||
|
Idéal pour la prise de notes.
|
||||||
|
Création dynamique de pages en créant un lien dans une page.
|
||||||
|
|
||||||
|
Ranges :
|
||||||
|
https://stackoverflow.com/questions/6249095/how-to-set-the-caret-cursor-position-in-a-contenteditable-element-div
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub struct Arguments {
|
||||||
|
/// IP address
|
||||||
|
#[arg(short, long, default_value_t = String::from("127.0.0.1"))]
|
||||||
|
pub ip: String,
|
||||||
|
/// Port to listen to
|
||||||
|
#[arg(short, long, default_value_t = 8081)]
|
||||||
|
pub port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arguments {
|
||||||
|
|
||||||
|
pub fn parse_args() -> Arguments {
|
||||||
|
let args = Arguments::parse();
|
||||||
|
args
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppData {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
use actix_web::web;
|
||||||
|
use actix_web::{HttpResponse, Responder, get};
|
||||||
|
|
||||||
|
use askama_actix::Template;
|
||||||
|
use askama_actix::TemplateToResponse;
|
||||||
|
|
||||||
|
use crate::commons::AppData;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "index.html")]
|
||||||
|
pub struct IndexTemplate {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn index(data: web::Data<AppData>) -> impl Responder {
|
||||||
|
let name = data.name.to_owned();
|
||||||
|
IndexTemplate { name }.to_response()
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
pub mod index;
|
||||||
|
pub mod commons;
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
use actix_web::{post, web, App, HttpResponse, HttpServer, Responder};
|
||||||
|
use actix_files;
|
||||||
|
|
||||||
|
use mdwiki::commons::{Arguments, AppData};
|
||||||
|
use mdwiki::index;
|
||||||
|
|
||||||
|
#[actix_web::main]
|
||||||
|
async fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
|
let args = Arguments::parse_args();
|
||||||
|
|
||||||
|
let ip = args.ip;
|
||||||
|
let port = args.port;
|
||||||
|
|
||||||
|
let appdata = AppData {
|
||||||
|
name: String::from("MdNotes"),
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpServer::new(move || {
|
||||||
|
App::new()
|
||||||
|
.app_data(web::Data::new(appdata.to_owned()))
|
||||||
|
.service(index::index)
|
||||||
|
.service(actix_files::Files::new("/static", "./static"))
|
||||||
|
})
|
||||||
|
.bind((ip, port))?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
html {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#mdnotes {
|
||||||
|
font-family: sans-serif;
|
||||||
|
padding-top: 1rem;
|
||||||
|
padding-left: 3rem;
|
||||||
|
padding-right: 3rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#mdnotes div.h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
border-bottom: 1px solid #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#mdnotes div.h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#mdnotes div.h3 {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#mdnotes div.h4 {
|
||||||
|
font-style: italic;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
}
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
function change(evt) {
|
||||||
|
reId(document.getElementById('mdnotes'));
|
||||||
|
let res = getStartPositionInLine();
|
||||||
|
let line = res[0];
|
||||||
|
if (line == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let position = res[1];
|
||||||
|
let id = line.id;
|
||||||
|
toMD();
|
||||||
|
toHTML();
|
||||||
|
line = document.getElementById(id);
|
||||||
|
setStartPositionInLine(line, position);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reId(obj) {
|
||||||
|
let prevId = '';
|
||||||
|
let children = obj.childNodes;
|
||||||
|
for (i = 0; i < children.length; i++) {
|
||||||
|
let child = children[i];
|
||||||
|
if (child.classList.contains('mdnotes_line')) {
|
||||||
|
if (prevId == child.id) {
|
||||||
|
child.className = 'mdnotes_line';
|
||||||
|
}
|
||||||
|
prevId = child.id;
|
||||||
|
child.id = 'mdnotes_' + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStartPositionInLine() {
|
||||||
|
let selection = window.getSelection();
|
||||||
|
let range = selection.getRangeAt(0).cloneRange();
|
||||||
|
let obj = range.startContainer;
|
||||||
|
|
||||||
|
let position = range.startOffset;
|
||||||
|
let line = null;
|
||||||
|
|
||||||
|
while (obj != null) {
|
||||||
|
if (obj.previousSibling != null) {
|
||||||
|
obj = obj.previousSibling;
|
||||||
|
if (obj.innerText != null) {
|
||||||
|
position += obj.innerText.length;
|
||||||
|
} else if (obj.length != null) {
|
||||||
|
position += obj.length;
|
||||||
|
}
|
||||||
|
} else if (obj.parentNode != null && obj.parentNode.classList != null && !obj.parentNode.classList.contains('mdnotes_line')) {
|
||||||
|
obj = obj.parentNode;
|
||||||
|
} else if (obj.parentNode != null && obj.parentNode.classList != null && obj.parentNode.classList.contains('mdnotes_line')) {
|
||||||
|
line = obj.parentNode;
|
||||||
|
obj = null;
|
||||||
|
} else {
|
||||||
|
obj = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [line, position];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStartPositionInLine(line, position) {
|
||||||
|
setStartPositionInDiv(line, position)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStartPositionInDiv(obj, position) {
|
||||||
|
let temppos = position;
|
||||||
|
if (temppos > obj.innerText.length) {
|
||||||
|
return temppos - obj.innerText.length;
|
||||||
|
}
|
||||||
|
let children = obj.childNodes;
|
||||||
|
for (i = 0; i < children.length; i++) {
|
||||||
|
let child = children[i];
|
||||||
|
if (child.nodeType == 3) {
|
||||||
|
temppos = setStartPositionInText(child, position);
|
||||||
|
} else {
|
||||||
|
temppos = setStartPositionInDiv(child, temppos);
|
||||||
|
if (temppos == 0) {
|
||||||
|
return temppos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temppos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStartPositionInText(obj, position) {
|
||||||
|
if (position > obj.length) {
|
||||||
|
return position - obj.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
let selection = window.getSelection();
|
||||||
|
selection.removeAllRanges();
|
||||||
|
let range = document.createRange();
|
||||||
|
range.setStart(obj, position);
|
||||||
|
selection.addRange(range);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toHTML() {
|
||||||
|
let ta = document.getElementById('ta');
|
||||||
|
let mda = document.getElementById('mdnotes');
|
||||||
|
mda.innerHTML = '';
|
||||||
|
let lines = ta.value.split('\n');
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
let obj = document.createElement('div');
|
||||||
|
let line = lines[i];
|
||||||
|
if (line == '') {
|
||||||
|
let br = document.createElement('br');
|
||||||
|
obj.append(br);
|
||||||
|
}
|
||||||
|
let normLine = line.trim();
|
||||||
|
if (normLine.startsWith('#### ')) {
|
||||||
|
obj.classList.add('h4');
|
||||||
|
} else if (normLine.startsWith('### ')) {
|
||||||
|
obj.classList.add('h3');
|
||||||
|
} else if (normLine.startsWith('## ')) {
|
||||||
|
obj.classList.add('h2');
|
||||||
|
} else if (normLine.startsWith('# ')) {
|
||||||
|
obj.classList.add('h1');
|
||||||
|
}
|
||||||
|
obj.classList.add('mdnotes_line');
|
||||||
|
if (line !== '') {
|
||||||
|
obj.innerText = line;
|
||||||
|
}
|
||||||
|
obj.id = 'mdnotes_' + i;
|
||||||
|
mda.append(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMD() {
|
||||||
|
let mda = document.getElementById('mdnotes');
|
||||||
|
let content = mda.childNodes;
|
||||||
|
let text = eltToMD(mda)
|
||||||
|
let ta = document.getElementById('ta');
|
||||||
|
ta.value = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function eltToMD(elt) {
|
||||||
|
let text = '';
|
||||||
|
if (getType(elt) == 'TEXT') {
|
||||||
|
text = elt.nodeValue;
|
||||||
|
} else if (elt.innerText.length == 0) {
|
||||||
|
text = '';
|
||||||
|
} else {
|
||||||
|
let children = elt.childNodes;
|
||||||
|
let prevType = 'DIV';
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
let type = getType(children[i]);
|
||||||
|
if (type == 'DIV' && prevType != 'DIV') {
|
||||||
|
text += "\n";
|
||||||
|
}
|
||||||
|
text += eltToMD(children[i]);
|
||||||
|
if (type == 'DIV') {
|
||||||
|
text += "\n";
|
||||||
|
}
|
||||||
|
prevType = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getType(elt) {
|
||||||
|
if (elt.nodeType == 3) {
|
||||||
|
return 'TEXT'
|
||||||
|
} else if (elt.nodeType == 1) {
|
||||||
|
return elt.tagName;
|
||||||
|
} else {
|
||||||
|
return 'UNKNOWN';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toHTML();
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{name}}</title>
|
||||||
|
<link rel="stylesheet" href="static/mdnotes.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<textarea id="ta" class="mdnotes" style="display: none;">
|
||||||
|
# Titre 1
|
||||||
|
Un petit texte
|
||||||
|
## Titre 2
|
||||||
|
### Titre 3-1
|
||||||
|
Encore un joli texte
|
||||||
|
### Titre 3-2
|
||||||
|
T'en as marre ???
|
||||||
|
#### Titre 4
|
||||||
|
Moi oui !!!</textarea>
|
||||||
|
<div id="mdnotes" class="mdnotes" oninput="return change(event)" contenteditable="true"></div>
|
||||||
|
<script type="text/javascript" src="static/mdnotes.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in new issue