pWiki/index.html
Alex A. Naanou 406d386f64 tweaking and cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2016-07-11 18:41:23 +03:00

282 lines
6.0 KiB
HTML
Executable File

<!DOCTYPE html>
<html>
<head>
<title>pWiki</title>
</head>
<style>
</style>
<script src="ext-lib/jquery.js"></script>
<script src="wiki.js"></script>
<script>
var clear = () => {
delete localStorage['wiki-data']
delete localStorage['wiki-location']
}
var macro = {
__macro__pattern__: null,
context: null,
filter: {
},
macro: {
filter: function(args, text, filters){
var filter = args[0] || args.name
filters.push(filter)
return ''
},
include: function(args){
var path = args[0] || args.src
var text = this.context.get(path).text
// XXX get new context???
return this.parse(text)
},
slot: function(args){
// XXX processing stages:
// - if we slot for first time return it as-is
// - if slot text available in slots us it to fill
// - slot seen again, save text to slots but return ''
},
},
parseArgs: function(args){
// XXX
},
parse: function(text){
var that = this
var filters = []
var slots = {}
// macro stage 1...
text = text.replace(this.__macro__pattern__, function(match, macro, args, text){
args = that.parseArgs(args)
return macro in that.macro ?
that.macro[macro].call(that, args, text, filters)
: match
})
// macro stage 2...
text = text.replace(this.__macro__pattern__, function(match, macro, args, text){
args = that.parseArgs(args)
return macro in that.macro ?
that.macro[macro].call(that, args, text, filters)
: match
})
// filter stage....
filters.forEach(function(k){
text = that.filter[k].call(that, text)
})
return text
},
}
var reload = () => {
$('.path').text('/' + Wiki.path)
$('.title').text(Wiki.title)
// process text...
var text = Wiki.text
var editing = $('.text').prop('contenteditable') != 'true'
var filters = []
var slots = {}
// expand macros...
if(editing){
text = text
// Syntax:
// @<macro>( <args> )
.replace(/@([a-zA-Z-_]+)\(([^)]*)\)/g, function(_, macro, args){
args = $('<div>')
.html(args)
.text()
.trim()
.split(/\s+/g)
//console.log('>>>>>', macro, args)
if(macro == 'filter' && args.length == 1){
filters.push(args[0])
return ''
}
if(macro == 'include' && args.length == 1){
w = Object.create(Wiki)
w.location = args[0]
return w.text
}
if(macro == 'attr'
&& args.length == 1
&& ['title', 'path', 'location', 'dir'].indexOf(args[0]) >= 0){
return Wiki[args[0]]
}
return _
})
// html-like macro syntax...
.replace(/\&lt;[a-zA-Z-_:]+.*?\/?\&gt;/g, function(t){
var elem = $($('<div>').html(t).text())
var macro = elem.prop('tagName').toLowerCase()
var args = {}
var a = elem.prop('attributes')
for(var i=0; i<a.length; i++){
args[a[i].name] = a[i].value
}
//console.log('>>>>>', macro, args)
if(macro == 'filter' && args.name != null){
console.log('FILTER:', args.name)
// XXX
return ''
}
if(macro == 'include' && args.src != null){
w = Object.create(Wiki)
w.location = args.src
return w.text
}
// XXX need content...
// Procedure:
// - if new slot
// - add to list
// - fill
// - if slot exists
// - fill original
if(macro == 'slot' && args.name != null){
slots[args.name] = ''
return t
}
if(macro == 'attr'
&& args.name != null
&& ['title', 'path', 'location', 'dir'].indexOf(args.name) >= 0){
return Wiki[args.name]
}
return t
})
}
$('.text').html(activateWikiWords(text, filters.indexOf('show_link_brackets') < 0 && editing))
// XXX save...
localStorage['wiki-data'] = JSON.stringify(Wiki.__wiki_data)
localStorage['wiki-location'] = Wiki.location
$('title').text(Wiki.location)
}
var go = (path) => {
history.pushState({
wikipath: path
},
Wiki.title,
window.location)
Wiki.location = path
reload()
}
var clearWikiWords = elem => {
// clear existing...
elem.find('.WikiWord').each(function(){
$(this).attr('braced') == 'yes' ?
$(this).replaceWith(['['].concat(this.childNodes, [']']))
: $(this).replaceWith(this.childNodes)
})
return elem
}
var activateWikiWords = (text, show_brackets) =>
text
// set new...
.replace(
Wiki.__wiki_link__,
function(l){
return '<a '
+'class="WikiWord" '
+'href="#" '
+'braced="'+ (show_brackets && l[0] == '[' ? 'yes' : 'no') +'"'
+'onclick="go($(this).text().replace(/^\\[|\\]$/g, \'\'))">'
+ (show_brackets && l[0] == '[' ? l.slice(1, -1) : l)
+'</a>'
})
$(() => {
$(window).on('popstate', function(evt){
event.state
&& event.state.wikipath
&& go(event.state.wikipath)
})
// load stored data...
Wiki.__wiki_data = localStorage['wiki-data'] ?
JSON.parse(localStorage['wiki-data'])
: data
Wiki.__wiki_data.__proto__ = BaseData
Wiki.location = localStorage['wiki-location'] || Wiki.location
reload()
// XXX make this update on enter...
$('.title')
.on('blur', () => {
Wiki.title = $('.title').text()
reload()
})
// live update text...
// XXX is this the right way to go for large documents???
$('.text')
.focus(() => {
$('.text').prop('contenteditable', $('.text').prop('contenteditable') != 'true')
reload()
})
.on('keyup', () => {
if($('.text').prop('contenteditable') == 'true'){
Wiki.text = clearWikiWords($('.text').clone()).html()
}
})
// XXX do this live, but on a timeout after user input...
// XXX need to place the cursor in the same position...
.blur(() => {
$('.text').prop('contenteditable', false)
reload()
})
})
</script>
<body>
<div class="path"></div>
<hr>
<h1 class="title" contenteditable tabindex=0></h1>
<div class="text" tabindex=0></div>
</body>
</html>
<!-- vim:set sw=4 ts=4 : -->