-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Hungarian translation & add links to website
- Loading branch information
Showing
15 changed files
with
940 additions
and
19 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** | ||
* This file is part of Feather Wiki. | ||
* | ||
* Feather Wiki is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | ||
* | ||
* Feather Wiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License along with Feather Wiki. If not, see https://www.gnu.org/licenses/. | ||
*/ | ||
// Ez a kiterjesztés a Feather Wiki Warbler verzióit automatikusan elmenti a szerverre, amikor az oldalakon változtatásokat végeznek. | ||
FW.ready(() => { | ||
const { state, emitter } = FW; | ||
console.log('auto-save.js futtatása'); | ||
const { events } = state; | ||
[events.UPDATE_PAGE, events.NOTIFY].forEach(ev => { | ||
emitter.on(ev, (noti = null) => { | ||
if (!state.canPut && noti !== 'Nem lehet automatikusan menteni') { | ||
emitter.emit(events.NOTIFY, 'Nem lehet automatikusan menteni', 5000, 'background:#e88'); | ||
return; | ||
} | ||
if (typeof noti !== 'string' || noti === 'Settings updated' || noti === 'Beállítások frissítve') { | ||
emitter.emit(events.PUT_SAVE_WIKI); | ||
} | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/** | ||
* This file is part of Feather Wiki. | ||
* | ||
* Feather Wiki is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | ||
* | ||
* Feather Wiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License along with Feather Wiki. If not, see https://www.gnu.org/licenses/. | ||
*/ | ||
// Ez a kiterjesztés minden oldalon a „Szerkesztés” gomb mellé egy „Oldal klónozása” gombot helyez. Kattintson rá, adjon meg egy új nevet, és megjelenik az aktuális oldal másolata szerkesztésre. | ||
FW.ready(() => { | ||
const { state, emitter } = FW; | ||
console.log('a clone-page.js futtatása'); | ||
|
||
['DOMContentLoaded', 'render'].forEach(ev => { | ||
emitter.on(ev, () => { | ||
setTimeout(() => { // Adds a very small delay so it injects after render when elements exist in DOM | ||
renderClonePageButton(); | ||
}, 50); | ||
}); | ||
}); | ||
emitter.emit('DOMContentLoaded'); | ||
|
||
function renderClonePageButton () { | ||
const editButton = Array.from(document.querySelectorAll('main > section > header button')).find(el => el.textContent === 'Edit'); | ||
if (!editButton || !!document.querySelector('#cloneButton')) return; | ||
const pg = { ...state.pg }; | ||
const cloneButton = html`<button id="cloneButton" style="background-color:#fff;border:1px solid #000;color:#000;margin-left:8px;" onclick=${() => { | ||
let newName = prompt('A Klónozott Oldal Neve:', pg.name + ' Klón'); | ||
if (!newName) return; | ||
newName = newName.trim(); | ||
if (newName.length < 2) return alert('Írjon be egynél több karaktert egy új oldal létrehozásához.'); | ||
emitter.emit(state.events.CREATE_PAGE, newName); | ||
const wait = setInterval(() => { | ||
if (state.pg.id !== pg.id) { | ||
clearInterval(wait); | ||
state.pg = {...pg, ...state.pg}; | ||
emitter.emit(state.events.START_EDIT); | ||
} | ||
}, 100); | ||
}}>Oldal Klónozása</button>`; | ||
editButton.parentElement.insertBefore(cloneButton, editButton.nextSibling); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
/** | ||
* This file is part of Feather Wiki. | ||
* | ||
* Feather Wiki is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | ||
* | ||
* Feather Wiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License along with Feather Wiki. If not, see https://www.gnu.org/licenses/. | ||
*/ | ||
// Ez a kiegészítő egy „Adatkezelés” szekciót ad a Wiki beállítások oldalához, amely lehetővé teszi, hogy több HTML, Markdown és egyszerű szöveges fájlt importáljon új oldalaként a wikibe és | ||
// exportálja a jelenlegi wiki összes oldalát HTML vagy Markdown fájlként. Exportáláskor egy CDN-ből tölti be a JSZip modult, hogy az összes oldalt egyetlen .zip fájlba csomagolja. | ||
// A wiki teljes nyers JSON-adatait is exportálhatja tömörítetlen formában, de ez kevésbé hasznos lehet számára, ha nem tudja, hogyan lehet a JSON-adatokat manipulálni. | ||
FW.ready(() => { | ||
const { state, emitter } = FW; | ||
console.log('a data-import-export.js futtatása'); | ||
|
||
window.FW.data = { | ||
import: () => { | ||
const input = html`<input type="file" multiple accept="text/html,.md,.markdown,text/plain" onchange=${e => { | ||
const { files } = e.target; | ||
if (files.length < 1) return; | ||
function readFile(file, callback) { | ||
const reader = new FileReader(); | ||
reader.onload = e => callback(e.target.result); | ||
reader.onerror = e => callback(null); | ||
reader.readAsText(file); | ||
} | ||
let processed = 0; | ||
for (let i = 0; i < files.length; i++) { | ||
const f = files[i]; | ||
readFile(f, (content => { | ||
if (content) { | ||
const pg = window.FW.data['parse' + (f.type === 'text/html' ? 'Html' : 'Text')](f, content); | ||
pg.content = window.FW.img.fix(pg.content, true); | ||
state.p.pages.push(pg); | ||
emitter.emit(state.events.CHECK_CHANGED); | ||
} | ||
processed++; | ||
})); | ||
} | ||
const checkDone = setInterval(() => { | ||
if (processed >= files.length) { | ||
clearInterval(checkDone); | ||
emitter.emit(state.events.NOTIFY, 'Az importálás befejeződött. Ne felejtse el menteni a wikijét!'); | ||
} | ||
}, 300); | ||
}} />`; | ||
document.body.appendChild(input); | ||
input.click(); | ||
document.body.removeChild(input); | ||
}, | ||
parseHtml: (file, content) => { | ||
let name; | ||
if (content.includes('</head>')) { | ||
const headContent = content.replace(/.*?<head[^>]*?>(.*)?<\/head>.*/ims, '$1'); | ||
const head = html`<head>${html.raw(headContent)}</head>`; | ||
if (head.querySelector('title')) { | ||
name = head.querySelector('title').innerText; | ||
} | ||
} | ||
const body = content.includes('</body>') ? content.replace(/.*?<body[^>]*?>(.*)?<\/body>.*/ims, '$1') : content; | ||
const doc = html`<body>${html.raw(body)}</body>`; | ||
if (!name && doc.querySelector('h1')) { | ||
name = doc.querySelector('h1').innerText; | ||
} | ||
const pg = window.FW.data.generatePage(name ?? file.name); | ||
if (pg.cd > (file.lastModified ?? (Date.now() + 1))) { | ||
pg.cd = file.lastModified; | ||
} | ||
pg.content = doc.innerHtml; | ||
return pg; | ||
}, | ||
parseText: (file, content) => { | ||
let name, tags, headContent; | ||
if (content.match(/^---/) !== null) { | ||
headContent = content.replace(/^---\r?\n(.*)?\r?\n---.*/ms, '$1'); | ||
if (headContent.match(/^(name|title): */im) !== null) { | ||
name = headContent.replace(/.*\n(?:name|title): *(.+?)\r?\n.*/ims, '$1'); | ||
} | ||
if (headContent.match(/^tags: */im) !== null) { | ||
if (headContent.match(/^tags:\s*^- /ims) !== null) { | ||
tags = headContent.replace(/.*\ntags:\s*(- .+)+.*/ims, '$1').replace(/- /g, '').split('\n'); | ||
} else { | ||
tagsRaw = headContent.replace(/.*\ntags: *(.+).*/ims, '$1'); | ||
try { | ||
if (tagsRaw.includes('[')) { | ||
tags = JSON.parse(tagsRaw); | ||
} else { | ||
tags = tagsRaw.split(','); | ||
} | ||
} catch (e) {} | ||
} | ||
} | ||
} | ||
const body = headContent ? content.replace(new RegExp('---\\r?\\n' + headContent + '\\r?\\n---\\r?\\n'), '') : content; | ||
const doc = html`<body>${md(body)}</body>`; | ||
if (!name && doc.querySelector('h1')) { | ||
name = doc.querySelector('h1').innerText; | ||
} | ||
const pg = window.FW.data.generatePage(name ?? file.name); | ||
if (pg.cd > (file.lastModified ?? (Date.now() + 1))) { | ||
pg.cd = file.lastModified; | ||
} | ||
pg.content = body; | ||
pg.editor = 'md'; | ||
if (tags) pg.tags = tags.map(t => t.trim()).filter(t => t.length).join(','); | ||
return pg; | ||
}, | ||
generatePage: name => { | ||
const genId = () => { | ||
const s = []; | ||
for (let i = 0; i < 9; i++) { | ||
const code = Math.round(Math.random() * (126 - 32)) + 32; | ||
s.push(String.fromCharCode(code)); | ||
} | ||
return s.join(''); | ||
} | ||
let id; | ||
do { | ||
id = genId(); | ||
} | ||
while (state.p.pages.findIndex(p => p.id === id) >= 0); | ||
// Ensure unique slug | ||
let d = 0, | ||
s = FW.slug(name), | ||
slug; | ||
do { | ||
slug = s + (d > 0 ? '_' + d : ''); | ||
d++; | ||
} | ||
while (state.p.pages.some(pp => pp.slug === slug)) | ||
return { id, name, slug, cd: Date.now() }; | ||
}, | ||
export: () => { | ||
// If JSZip hasn't been loaded yet, load it before running the export | ||
if (typeof JSZip === 'undefined') { | ||
const jszipScript = document.createElement('script'); | ||
document.body.appendChild(jszipScript); | ||
jszipScript.onload = () => window.FW.data.doExport(); | ||
jszipScript.src = 'https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js'; | ||
} else { | ||
window.FW.data.doExport(); | ||
} | ||
}, | ||
dl: (mime, b64, suffix) => { | ||
const download = html`<a href="data:${mime};base64,${b64}" download="${window.FW.slug(state.p.name)}${suffix}">download</a>`; | ||
document.body.appendChild(download); | ||
download.click(); | ||
document.body.removeChild(download); | ||
}, | ||
doExport: () => { | ||
var zip = new JSZip(); | ||
state.p.pages.forEach(pg => { | ||
let filename = pg.slug; | ||
let content = window.FW.inject.img(window.FW.img.fix(pg.content ?? '')); | ||
// replace internal links | ||
(content?.match(/\[\[.+?(?=\]\])/g) ?? []).forEach(l => { | ||
const match = l.replace('[[', '').split('|'); | ||
const slug = match[1] ? match[1].trim() : window.FW.slug(match[0]); | ||
const exists = state.p.pages.find(pg => pg.slug === slug); | ||
if (exists) { | ||
content = content.replace( | ||
`${l}]]`, | ||
`<a href="${slug}.${exists.editor === 'md' ? 'md' : 'html'}">${match[0]}</a>` | ||
); | ||
} | ||
}); | ||
if (pg.editor === 'md') { | ||
filename += '.md'; | ||
if (pg.tags) { | ||
content = 'Tagged: ' + pg.tags + '\n\n' + content; | ||
} | ||
content = '# ' + pg.name + '\n\n' + content; | ||
} else { | ||
filename += '.html'; | ||
if (pg.tags) { | ||
content = '<p>Tagged: ' + pg.tags + '</p>\n' + content; | ||
} | ||
content = '<h1>' + pg.name + '</h1>\n' + content; | ||
} | ||
zip.file(filename, content); | ||
}); | ||
zip.generateAsync({type:"base64"}).then(function (base64) { | ||
window.FW.data.dl('application/zip', base64, '_pages.zip'); | ||
}); | ||
}, | ||
exportJson: () => { | ||
window.FW.data.dl('application/json', btoa(unescape(encodeURIComponent(JSON.stringify(state.p)))), '.json'); | ||
}, | ||
exportStaticHtml: () => { | ||
const css = state.c + ' main>section>header{display:none;} @media print{main>.sb{display:none;}main>section>article{page-break-after:always;}main>section>header{display:unset;}}'; | ||
const st = { ...state, c: css, p: { ...state.p, static: true, published: true } }; | ||
const static = FW.gen(st) | ||
.replace(/<script.+?<\/script>/gsm, '') | ||
.replace(/<\/main> <footer>.+?<\/footer>/g, '</main>') | ||
// Insert print-only header | ||
.replace('</ul></nav></div> <section>', `</ul></nav></div> <section><header><span class=db><a href=? class=t>${st.p.name}</a></span>${ st.p.desc ? `<p class=pb>${st.p.desc}</p>` : ''}<hr></header>`); | ||
window.FW.data.dl('text/html', btoa(unescape(encodeURIComponent(static))), '.html'); | ||
}, | ||
}; | ||
['DOMContentLoaded', 'render'].forEach(ev => { | ||
emitter.on(ev, () => { | ||
setTimeout(() => { // Adds a very small delay so it injects after render when elements exist in DOM | ||
renderImportExportSection(); | ||
}, 50); | ||
}); | ||
}); | ||
emitter.emit('DOMContentLoaded'); | ||
|
||
function renderImportExportSection () { | ||
// Don't run if not on settings page or if already rendered | ||
if (state.query.page !== 's' || !!document.querySelector('#dataManagementSection')) return; | ||
const section = html`<section id="dataManagementSection" style="margin-top:20px;"> | ||
<h1>Adatkezelés</h1> | ||
<div class="r"> | ||
<div class="c w12"> | ||
<button onclick=${() => window.FW.data.import()} style="margin-right:10px;">Fájlok Importálása Oldalakként</button> | ||
<p class="h">Válasszon ki 1 vagy több HTML-, Markdown- és egyszerű szöveges fájlt, amelyeket oldalakként szeretne importálni.</p> | ||
<p class="h">Ha a HTML fájlok rendelkeznek egy <code>title</code> elemmel a <code>head</code> elemen belül, vagy egy <code>H1</code> elemet tartalmaznak, szövegük az oldal címe lesz. Egyéb esetben az oldal címe a fájl neve, kiterjesztés nélkül.</p> | ||
<p class="h">Ha a Markdown fájlok rendelkeznek YAML frontmatterrel, a <code>name</code> vagy a <code>title</code> mező lesz az oldal címe és a <code>tags</code> mező a címkéket határozza meg. Egyéb esetben az első <code>#</code> címsorszint (ha légezik), vagy a fájl neve kiterjesztés nélkül lesz használva.</p> | ||
<p class="h">Az importáló mindent megtesz a tartalom és a fájltípus elemzése érdekében, de különböző felhasználási esetek kimaradhatnak. Minél egyszerűbbek a fájlok, annál jobbak lesznek az eredmények.</p> | ||
</div> | ||
<div class="c w12"> | ||
<button onclick=${() => window.FW.data.export()}>Oldalak Exportálása</button> | ||
<p class="h">Összegyűjt minden wiki oldalt egy <code>.zip</code> fájlba, az oldalakat slugjuknak megfelelően elnevezve. Az oldalak neve egy <code>H1</code> elemben lesz megadva a fájlok elején, minden létező címke ezek alatt lesz megtalálható.</p> | ||
<p class="h">A szülő/gyerek kapcsolatok <em>nem</em> lesznek megőrizve a kiterjesztéssel való exportáláskor, valamint minden kép az oldal tartalmába lesz beszúrva. Belső hivatkozások HTML hivatkozásokká alakulnak át, megfelelően hivatkozva a céloldal HTML fájljára.</p> | ||
<p class="h">Megjegyzés: az exportban a wiki beállítások oldalán megadott tartalom nem lesz elérhető.</p> | ||
<button onclick=${() => window.FW.data.exportJson()}>Nyers JSON Adat exportálása</button> | ||
<button onclick=${() => window.FW.data.exportStaticHtml()}>Statikus HTML Exportálása</button> | ||
</div> | ||
</div> | ||
</section>`; | ||
const page = document.querySelector('article.mw'); | ||
page.appendChild(section); | ||
} | ||
}); |
Oops, something went wrong.