MediaWiki:Common.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
import MarkdownIt from './markdown-it.js'
var self = new Hyperdrive(location)
var pathname = location.pathname.endsWith('/') ? location.pathname + 'index.md' : location.pathname
var isEditing = location.search === '?edit'
function h (tag, attrs, ...children) {
var el = document.createElement(tag)
for (let k in attrs) {
if (k === 'cls') el.className = attrs[k]
else el.setAttribute(k, attrs[k])
}
for (let child of children) el.append(child)
return el
}
async function ensureParentDir (p) {
let parts = p.split('/').slice(0, -1)
let acc = []
for (let part of parts) {
acc.push(part)
await self.mkdir(acc.join('/')).catch(e => undefined)
}
}
customElements.define('wiki-header', class extends HTMLElement {
constructor () {
super()
this.load()
}
async load () {
this.info = await self.getInfo()
this.render()
}
render () {
this.append(h('h1', {}, h('a', {href: '/'}, this.info.title)))
if (this.info.description) {
this.append(h('p', {}, this.info.description))
}
if (this.info.writable) {
let buttons = []
if (!isEditing) {
let newPage = h('button', {}, 'New Page')
newPage.addEventListener('click', async (e) => {
var newPathname = prompt('Enter the path of the new page')
if (!newPathname) return
if (!newPathname.endsWith('.md')) newPathname += '.md'
await ensureParentDir(newPathname)
if ((await self.stat(newPathname).catch(e => undefined)) === undefined) {
await self.writeFile(newPathname, `# ${newPathname}`)
}
location = newPathname + '?edit'
})
buttons.push(newPage)
if (/\.(png|jpe?g|gif|mp4|mp3|ogg|webm|mov)$/.test(pathname) === false) {
let editPage = h('button', {}, 'Edit Page')
editPage.addEventListener('click', async (e) => {
location.search = '?edit'
})
buttons.push(editPage)
}
} else {
let savePage = h('button', {cls: 'primary'}, 'Save Page')
savePage.addEventListener('click', async (e) => {
let value = document.body.querySelector('textarea.editor').value
await self.writeFile(pathname, value)
location.search = ''
})
buttons.push(savePage)
}
let deletePage = h('button', {}, 'Delete Page')
deletePage.addEventListener('click', async (e) => {
if (!confirm('Delete this page?')) return
await self.unlink(pathname)
if (isEditing) location.search = ''
else location.reload()
})
buttons.push(deletePage)
let editProps = h('button', {}, 'Edit Drive Properties')
editProps.addEventListener('click', async (e) => {
await navigator.drivePropertiesDialog(self.url)
if (!isEditing) location.reload()
})
buttons.push(editProps)
this.append(h('div', {cls: 'admin'}, ...buttons))
}
}
})
customElements.define('wiki-nav', class extends HTMLElement {
constructor () {
super()
this.load()
}
async load () {
this.files = await self.readdir('/', {recursive: true})
this.files = this.files.filter(file => file.endsWith('.md'))
this.files.sort()
this.render()
}
render () {
for (let file of this.files) {
let href = `/${file}`
let cls = pathname === href ? 'active' : ''
this.append(h('a', {href, cls}, file.slice(0, -3)))
}
if (this.files.length === 0) {
this.append(h('div', {cls: 'empty'}, 'This Wiki has no pages'))
}
}
})
customElements.define('wiki-page', class extends HTMLElement {
constructor () {
super()
this.render()
}
async render () {
// check existence
let stat = await self.stat(pathname).catch(e => undefined)
if (!stat) {
// 404
let canEdit = (await self.getInfo()).writable
if (canEdit) {
let btn = h('button', {}, 'Create Page')
btn.addEventListener('click', async (e) => {
await ensureParentDir(pathname)
await self.writeFile(pathname, `# ${pathname}`)
location.search = '?edit'
})
this.append(h('div', {cls: 'empty'}, h('h2', {}, 'This Page Does Not Exist'), btn))
} else {
this.append(h('div', {cls: 'empty'}, h('h2', {}, 'This Page Does Not Exist')))
}
return
}
// embed content
if (/\.(png|jpe?g|gif)$/i.test(pathname)) {
this.append(h('img', {src: pathname}))
} else if (/\.(mp4|webm|mov)/i.test(pathname)) {
this.append(h('video', {controls: true}, h('source', {src: pathname})))
} else if (/\.(mp3|ogg)/i.test(pathname)) {
this.append(h('audio', {controls: true}, h('source', {src: pathname})))
} else {
let content = await self.readFile(pathname)
if (isEditing) {
// render editor
let textarea = h('textarea', {cls: 'editor'}, content)
this.append(textarea)
} else {
// render content
if (/\.(md|html)$/i.test(pathname)) {
if (pathname.endsWith('.md')) {
let md = new MarkdownIt()
content = md.render(content)
}
let contentEl = h('div', {cls: 'content'})
contentEl.innerHTML = content
this.append(contentEl)
} else {
this.append(h('pre', {cls: 'content'}, content))
}
}
}
}
})