reworked the include system...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2016-07-19 23:13:51 +03:00
parent 913d204f12
commit a0ad716986
2 changed files with 66 additions and 37 deletions

View File

@ -121,6 +121,9 @@ var reload = () => {
} }
var go = (path) => { var go = (path) => {
path = path.trim()
path = path[0] == '[' ? path.slice(1, -1) : path
history.pushState({ history.pushState({
wikipath: path wikipath: path
}, },

100
wiki.js
View File

@ -27,7 +27,7 @@ var normalizePath = function(path){
var clearWikiWords = function(elem){ var clearWikiWords = function(elem){
// clear existing... // clear existing...
elem.find('.WikiWord').each(function(){ elem.find('.wikiword').each(function(){
$(this).attr('braced') == 'yes' ? $(this).attr('braced') == 'yes' ?
$(this).replaceWith(['['].concat(this.childNodes, [']'])) $(this).replaceWith(['['].concat(this.childNodes, [']']))
: $(this).replaceWith(this.childNodes) : $(this).replaceWith(this.childNodes)
@ -41,11 +41,12 @@ var setWikiWords = function(text, show_brackets){
Wiki.__wiki_link__, Wiki.__wiki_link__,
function(l){ function(l){
return '<a ' return '<a '
+'class="WikiWord" ' +'class="wikiword" '
+'href="#" ' +'href="#" '
+'braced="'+ (show_brackets && l[0] == '[' ? 'yes' : 'no') +'"' +'braced="'+ (show_brackets && l[0] == '[' ? 'yes' : 'no') +'" '
+'onclick="go($(this).text().replace(/^\\[|\\]$/g, \'\'))">' +'onclick="go($(this).text())" '
+ (show_brackets && l[0] == '[' ? l.slice(1, -1) : l) +'>'
+ (!!show_brackets && l[0] == '[' ? l.slice(1, -1) : l)
+'</a>' +'</a>'
})} })}
@ -56,6 +57,8 @@ var setWikiWords = function(text, show_brackets){
// XXX should inline macros support named args??? // XXX should inline macros support named args???
var macro = { var macro = {
__include_marker__: '__include_marker__',
// Abstract macro syntax: // Abstract macro syntax:
// Inline macro: // Inline macro:
// @macro(arg ..) // @macro(arg ..)
@ -78,8 +81,6 @@ var macro = {
'wikiword', 'wikiword',
], ],
context: null,
// Maacros... // Maacros...
// //
// stage 1... // stage 1...
@ -90,40 +91,45 @@ var macro = {
macro: { macro: {
// select filter to post-process text... // select filter to post-process text...
filter_args: ['name'], filter_args: ['name'],
filter: function(args, text, _, filters){ filter: function(context, args, text, state){
var filter = args[0] || args.name var filter = args[0] || args.name
filter[0] == '-' ? filter[0] == '-' ?
// disabled -- keep at head of list... // disabled -- keep at head of list...
filters.unshift(filter) state.filters.unshift(filter)
// normal -- tail... // normal -- tail...
: filters.push(filter) : state.filters.push(filter)
return '' return ''
}, },
// include page/slot... // include page/slot...
//
// NOTE: this will render the page in the caller's context.
include_args: ['src', 'slot'], include_args: ['src', 'slot'],
include: function(args){ include: function(context, args, _, state){
var path = args.src var path = args.src
var text = this.context.get(path).text var text = context.get(path).text
return this.parse(text) //return this.parse(context, text)
state.include.push(this.parse(context, text))
return this.__include_marker__
}, },
// fill/define slot (stage 1)... // fill/define slot (stage 1)...
slot_args: ['name'], slot_args: ['name'],
slot: function(args, text, slots){ slot: function(context, args, text, state){
var name = args.name var name = args.name
if(slots[name] == null){ if(state.slots[name] == null){
slots[name] = text state.slots[name] = text
// return a slot macro parsable by stage 2... // return a slot macro parsable by stage 2...
return '<slot name="'+name+'">'+ text +'</slot>' return '<slot name="'+name+'">'+ text +'</slot>'
} else if(name in slots){ } else if(name in state.slots){
slots[name] = text state.slots[name] = text
return '' return ''
} }
}, },
@ -132,32 +138,36 @@ var macro = {
// XXX rename... // XXX rename...
macro2: { macro2: {
slot_args: ['name'], slot_args: ['name'],
slot: function(args, text, slots){ slot: function(context, args, text, state){
var name = args.name var name = args.name
if(slots[name] == null){ if(state.slots[name] == null){
return text return text
} else if(name in slots){ } else if(name in state.slots){
return slots[name] return state.slots[name]
} }
}, },
}, },
// Filters... // Filters...
// //
// NOTE: a filter should be applicable multiple times without any
// side effects...
// XXX is this good???
//
// XXX this is preliminary... // XXX this is preliminary...
// XXX add wikiword... // XXX add wikiword...
// filter(text) -> html // filter(text) -> html
filter: { filter: {
default: 'html', default: 'html',
html: function(text){ return $('<div>').html(text).html() }, html: function(context, text){ return $('<div>').html(text).html() },
json: 'text', json: 'text',
text: function(text){ return $('<div>').text(text).html() }, text: function(context, text){ return $('<div>').text(text).html() },
wikiword: function(text){ return setWikiWords(text) }, wikiword: function(context, text){ return setWikiWords(text) },
}, },
@ -194,34 +204,37 @@ var macro = {
return res return res
}, },
parse: function(text, context){ parse: function(context, text){
var that = this var that = this
var filters = [] var state = {
var slots = {} filters: [],
slots: {},
include: [],
}
var _parse = function(text, macro){ var _parse = function(context, text, macro){
return text.replace(that.__macro__pattern__, function(match){ return text.replace(that.__macro__pattern__, function(match){
var m = that.parseElem(match, macro) var m = that.parseElem(match, macro)
// found a macro... // found a macro...
return m.name in macro ? return m.name in macro ?
macro[m.name].call(that, m.args, m.text, slots, filters) macro[m.name].call(that, context, m.args, m.text, state)
// found a tag -> look inside... // found a tag -> look inside...
: m.elem && m.text != ''? : m.elem && m.text != ''?
m.elem.html(_parse(m.text, macro))[0].outerHTML m.elem.html(_parse(context, m.text, macro))[0].outerHTML
// else nothing changed... // else nothing changed...
: match : match
}) })
} }
// macro stage 1... // macro stage 1...
text = _parse(text, this.macro) text = _parse(context, text, this.macro)
// macro stage 2... // macro stage 2...
text = _parse(text, this.macro2) text = _parse(context, text, this.macro2)
// filter stage.... // filter stage....
filters state.filters
.concat(this.__filters__) .concat(this.__filters__)
// unique -- leave last occurance.. // unique -- leave last occurance..
.filter(function(k, i, lst){ .filter(function(k, i, lst){
@ -234,17 +247,28 @@ var macro = {
// unique -- leave first occurance.. // unique -- leave first occurance..
//.filter(function(k, i, lst){ return lst.slice(0, i).indexOf(k) == -1 }) //.filter(function(k, i, lst){ return lst.slice(0, i).indexOf(k) == -1 })
// apply the filters... // apply the filters...
.forEach(function(k){ .forEach(function(f){
var k = f
// get filter aliases... // get filter aliases...
var seen = [] var seen = []
while(typeof(k) == typeof('str') && seen.indexOf(k) == -1){ while(typeof(k) == typeof('str') && seen.indexOf(k) == -1){
seen.push(k) seen.push(k)
k = that.filter[k] k = that.filter[k]
} }
// call the filter // could not find the filter...
text = k.call(that, text) if(!k){
console.warn('Unknown filter:', f)
return
}
// use the filter...
text = k.call(that, context, text)
}) })
// merge includes...
text = text.replace(RegExp(this.__include_marker__, 'g'), function(){
return state.include.shift()
})
return text return text
}, },
} }
@ -608,6 +632,8 @@ var Wiki = {
// XXX take .raw, parse macros and apply filters... // XXX take .raw, parse macros and apply filters...
get text(){ return this.raw }, get text(){ return this.raw },
get _text(){ return macro.parse(this, this.raw) },
// NOTE: this is set by setting .text // NOTE: this is set by setting .text
get links(){ get links(){