mirror of
https://github.com/flynx/pWiki.git
synced 2025-12-17 08:31:38 +00:00
split off the macros, still not ready but already working...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
56065a128c
commit
b5e0355886
682
macro.js
Executable file
682
macro.js
Executable file
@ -0,0 +1,682 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
||||||
|
(function(require){ var module={} // make module AMD/node compatible...
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
|
||||||
|
function Macro(doc, args, func){
|
||||||
|
func.doc = doc
|
||||||
|
func.macro_args = args
|
||||||
|
return func
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// XXX should inline macros support named args???
|
||||||
|
var macro =
|
||||||
|
module = {
|
||||||
|
|
||||||
|
__include_marker__: '{{{INCLUDE-MARKER}}}',
|
||||||
|
|
||||||
|
// Abstract macro syntax:
|
||||||
|
// Inline macro:
|
||||||
|
// @macro(arg ..)
|
||||||
|
//
|
||||||
|
// HTML-like:
|
||||||
|
// <macro arg=value ../>
|
||||||
|
//
|
||||||
|
// HTML-like with body:
|
||||||
|
// <macro arg=value ..>
|
||||||
|
// ..text..
|
||||||
|
// </macro>
|
||||||
|
//
|
||||||
|
// XXX should inline macros support named args???
|
||||||
|
__macro__pattern__:
|
||||||
|
[[
|
||||||
|
// @macro(arg ..)
|
||||||
|
'\\\\?@([a-zA-Z-_]+)\\(([^)]*)\\)'
|
||||||
|
].join('|'), 'mg'],
|
||||||
|
|
||||||
|
// default filters...
|
||||||
|
//
|
||||||
|
// NOTE: these are added AFTER the user defined filters...
|
||||||
|
__filters__: [
|
||||||
|
'wikiword',
|
||||||
|
'noscript',
|
||||||
|
],
|
||||||
|
__post_filters__: [
|
||||||
|
//'noscript',
|
||||||
|
'title',
|
||||||
|
'editor',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Macros...
|
||||||
|
//
|
||||||
|
// XXX add support for sort and reverse attrs in all relavant macros
|
||||||
|
// (see: macro for details)
|
||||||
|
macro: {
|
||||||
|
"pwiki-comment": Macro('hide in pWiki',
|
||||||
|
[],
|
||||||
|
function(context, elem, state){
|
||||||
|
return ''
|
||||||
|
}),
|
||||||
|
now: Macro('Create a now id',
|
||||||
|
[],
|
||||||
|
function(context, elem, state){ return ''+Date.now() }),
|
||||||
|
// select filter to post-process text...
|
||||||
|
filter: Macro('Filter to post-process text',
|
||||||
|
['name'],
|
||||||
|
function(context, elem, state){
|
||||||
|
var filter = $(elem).attr('name')
|
||||||
|
|
||||||
|
filter[0] == '-' ?
|
||||||
|
// disabled -- keep at head of list...
|
||||||
|
state.filters.unshift(filter)
|
||||||
|
// normal -- tail...
|
||||||
|
: state.filters.push(filter)
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}),
|
||||||
|
|
||||||
|
// include page/slot...
|
||||||
|
//
|
||||||
|
// NOTE: this will render the page in the caller's context.
|
||||||
|
// NOTE: included pages are rendered completely independently
|
||||||
|
// from the including page.
|
||||||
|
include: Macro('Include page',
|
||||||
|
['src', 'isolated', 'text'],
|
||||||
|
function(context, elem, state){
|
||||||
|
var path = $(elem).attr('src')
|
||||||
|
|
||||||
|
// get and prepare the included page...
|
||||||
|
state.include
|
||||||
|
.push([elem, context.get(path)])
|
||||||
|
|
||||||
|
// return the marker...
|
||||||
|
return this.__include_marker__
|
||||||
|
}),
|
||||||
|
|
||||||
|
// NOTE: this is similar to include, the difference is that this
|
||||||
|
// includes the page source to the current context while
|
||||||
|
// include works in an isolated context
|
||||||
|
source: Macro('Include page source (without parsing)',
|
||||||
|
['src'],
|
||||||
|
function(context, elem, state){
|
||||||
|
var path = $(elem).attr('src')
|
||||||
|
|
||||||
|
return context.get(path)
|
||||||
|
.map(function(page){ return page.raw })
|
||||||
|
.join('\n')
|
||||||
|
}),
|
||||||
|
|
||||||
|
quote: Macro('Include quoted page source (without parsing)',
|
||||||
|
['src'],
|
||||||
|
function(context, elem, state){
|
||||||
|
elem = $(elem)
|
||||||
|
var path = elem.attr('src')
|
||||||
|
|
||||||
|
return $(context.get(path)
|
||||||
|
.map(function(page){
|
||||||
|
return elem
|
||||||
|
.clone()
|
||||||
|
.attr('src', page.path)
|
||||||
|
.text(page.raw)[0]
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
|
||||||
|
/*
|
||||||
|
// fill/define slot (stage 1)...
|
||||||
|
//
|
||||||
|
// XXX which should have priority the arg text or the content???
|
||||||
|
_slot: Macro('Define/fill slot',
|
||||||
|
['name', 'text'],
|
||||||
|
function(context, elem, state, parse){
|
||||||
|
var name = $(elem).attr('name')
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
text = $(elem).html()
|
||||||
|
text = text == '' ? $(elem).attr('text') : text
|
||||||
|
text = this.parse(context, text, state, true)
|
||||||
|
//text = parse(elem)
|
||||||
|
|
||||||
|
if(state.slots[name] == null){
|
||||||
|
state.slots[name] = text
|
||||||
|
// return a slot macro parsable by stage 2...
|
||||||
|
//return '<_slot name="'+name+'">'+ text +'</slot>'
|
||||||
|
return elem
|
||||||
|
|
||||||
|
} else if(name in state.slots){
|
||||||
|
state.slots[name] = text
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
//*/
|
||||||
|
// convert @ macro to html-like + parse content...
|
||||||
|
slot: Macro('Define/fill slot',
|
||||||
|
['name', 'text'],
|
||||||
|
function(context, elem, state, parse){
|
||||||
|
elem = $(elem)
|
||||||
|
var name = elem.attr('name')
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
text = elem.html()
|
||||||
|
text = text.trim() == '' ?
|
||||||
|
elem.html(elem.attr('text') || '').html()
|
||||||
|
: text
|
||||||
|
text = parse(elem)
|
||||||
|
|
||||||
|
elem.attr('text', null)
|
||||||
|
//elem.html(text)
|
||||||
|
|
||||||
|
return elem
|
||||||
|
}),
|
||||||
|
|
||||||
|
// XXX revise macro definition rules -- see inside...
|
||||||
|
// XXX do we need macro namespaces or context isolation (for inculdes)???
|
||||||
|
macro: Macro('Define/fill macro',
|
||||||
|
['name', 'src', 'sort'],
|
||||||
|
function(context, elem, state, parse){
|
||||||
|
elem = $(elem)
|
||||||
|
var name = elem.attr('name')
|
||||||
|
var path = elem.attr('src')
|
||||||
|
var sort = elem.attr('sort')
|
||||||
|
|
||||||
|
state.templates = state.templates || {}
|
||||||
|
|
||||||
|
// get named macro...
|
||||||
|
if(name){
|
||||||
|
// XXX not sure which definition rules to use for macros...
|
||||||
|
// - first define -- implemented now
|
||||||
|
// - last define -- as in slots
|
||||||
|
// - first contenr -- original
|
||||||
|
//if(elem.html().trim() != ''){
|
||||||
|
if(elem.html().trim() != ''
|
||||||
|
// do not redefine...
|
||||||
|
&& state.templates[name] == null){
|
||||||
|
state.templates[name] = elem.clone()
|
||||||
|
|
||||||
|
} else if(name in state.templates) {
|
||||||
|
elem = state.templates[name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill macro...
|
||||||
|
if(path){
|
||||||
|
var pages = context.get(path)
|
||||||
|
|
||||||
|
// no matching pages -- show the else block or nothing...
|
||||||
|
if(pages.length == 0){
|
||||||
|
var e = elem
|
||||||
|
.find('else').first().clone()
|
||||||
|
.attr('src', path)
|
||||||
|
parse(e, context)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if we need to overload attrs...
|
||||||
|
sort = sort == null ? (elem.attr('sort') || '') : sort
|
||||||
|
sort = sort
|
||||||
|
.split(/\s+/g)
|
||||||
|
.filter(function(e){ return e && e != '' })
|
||||||
|
|
||||||
|
// do the sorting...
|
||||||
|
pages = sort.length > 0 ? pages.sort(sort) : pages
|
||||||
|
|
||||||
|
// fill with pages...
|
||||||
|
elem = elem.clone()
|
||||||
|
.find('else')
|
||||||
|
.remove()
|
||||||
|
.end()
|
||||||
|
return $(pages
|
||||||
|
.map(function(page){
|
||||||
|
var e = elem.clone()
|
||||||
|
.attr('src', page.path)
|
||||||
|
parse(e, page)
|
||||||
|
return e[0]
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// Post macros...
|
||||||
|
//
|
||||||
|
// XXX this is disabled for now, see end of .parse(..)
|
||||||
|
post_macro: {
|
||||||
|
'*': Macro('cleanup...',
|
||||||
|
[],
|
||||||
|
function(context, elem, state, parse, match){
|
||||||
|
if(match != null){
|
||||||
|
return match[0] == '\\' ? match.slice(1) : match
|
||||||
|
}
|
||||||
|
return elem
|
||||||
|
}),
|
||||||
|
/*
|
||||||
|
_slot: Macro('',
|
||||||
|
['name'],
|
||||||
|
function(context, elem, state){
|
||||||
|
var name = $(elem).attr('name')
|
||||||
|
|
||||||
|
if(state.slots[name] == null){
|
||||||
|
return $(elem).html()
|
||||||
|
|
||||||
|
} else if(name in state.slots){
|
||||||
|
return state.slots[name]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
//*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// XXX rename to post-include and post-quote
|
||||||
|
'page-text': Macro('',
|
||||||
|
['src'],
|
||||||
|
function(context, elem, state){
|
||||||
|
elem = $(elem)
|
||||||
|
|
||||||
|
return elem.html(context.get(elem.attr('src')).text)
|
||||||
|
}),
|
||||||
|
'page-raw': Macro('',
|
||||||
|
['src'],
|
||||||
|
function(context, elem, state){
|
||||||
|
elem = $(elem)
|
||||||
|
|
||||||
|
return elem.text(context.get(elem.attr('src')).text)
|
||||||
|
}),
|
||||||
|
//*/
|
||||||
|
},
|
||||||
|
|
||||||
|
// Filters...
|
||||||
|
//
|
||||||
|
// Signature:
|
||||||
|
// filter(text) -> html
|
||||||
|
//
|
||||||
|
filter: {
|
||||||
|
default: 'html',
|
||||||
|
|
||||||
|
html: function(context, elem){ return $(elem) },
|
||||||
|
|
||||||
|
text: function(context, elem){ return $('<span>')
|
||||||
|
.append($('<pre>')
|
||||||
|
.html($(elem).html())) },
|
||||||
|
// XXX expperimental...
|
||||||
|
json: function(context, elem){ return $('<span>')
|
||||||
|
.html($(elem).text()
|
||||||
|
// remove JS comments...
|
||||||
|
.replace(/\s*\/\/.*$|\s*\/\*(.|[\n\r])*?\*\/\s*/mg, '')) },
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
nl2br: function(context, elem){
|
||||||
|
return $('<div>').html($(elem).html().replace(/\n/g, '<br>\n')) },
|
||||||
|
|
||||||
|
wikiword: function(context, elem){
|
||||||
|
return $('<span>')
|
||||||
|
.html(setWikiWords($(elem).html(), true, this.__include_marker__)) },
|
||||||
|
// XXX need to remove all on* event handlers...
|
||||||
|
noscript: function(context, elem){
|
||||||
|
return $(elem)
|
||||||
|
// remove script tags...
|
||||||
|
.find('script')
|
||||||
|
.remove()
|
||||||
|
.end()
|
||||||
|
// remove js links...
|
||||||
|
.find('[href]')
|
||||||
|
.filter(function(i, e){ return /javascript:/i.test($(e).attr('href')) })
|
||||||
|
.attr('href', '#')
|
||||||
|
.end()
|
||||||
|
.end()
|
||||||
|
// remove event handlers...
|
||||||
|
// XXX .off() will not work here as we need to remove on* handlers...
|
||||||
|
},
|
||||||
|
|
||||||
|
// XXX move this to a plugin...
|
||||||
|
markdown: function(context, elem){
|
||||||
|
var converter = new showdown.Converter({
|
||||||
|
strikethrough: true,
|
||||||
|
tables: true,
|
||||||
|
tasklists: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return $('<span>')
|
||||||
|
.html(converter.makeHtml($(elem).html()))
|
||||||
|
// XXX add click handling to checkboxes...
|
||||||
|
.find('[checked]')
|
||||||
|
.parent()
|
||||||
|
.addClass('checked')
|
||||||
|
.end()
|
||||||
|
.end()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// Post-filters...
|
||||||
|
//
|
||||||
|
// These are run on the final page.
|
||||||
|
//
|
||||||
|
// The main goal is to setup editors and other active stuff that the
|
||||||
|
// user should not have direct access to, but that should be
|
||||||
|
// configurable per instance...
|
||||||
|
//
|
||||||
|
// for tech and other details see .filter
|
||||||
|
//
|
||||||
|
post_filter: {
|
||||||
|
noscript: function(context, elem){
|
||||||
|
// XXX
|
||||||
|
return elem
|
||||||
|
},
|
||||||
|
|
||||||
|
// Setup the page title and .title element...
|
||||||
|
//
|
||||||
|
// Use the text from:
|
||||||
|
// 1) set it H1 if it is the first tag in .text
|
||||||
|
// 2) set it to .location
|
||||||
|
//
|
||||||
|
title: function(context, elem){
|
||||||
|
elem = $(elem)
|
||||||
|
var title = elem.find('.text h1').first()
|
||||||
|
|
||||||
|
// show first H1 as title...
|
||||||
|
if(elem.find('.text').text().trim().indexOf(title.text().trim()) == 0){
|
||||||
|
title.detach()
|
||||||
|
elem.find('.title').html(title.html())
|
||||||
|
$('title').html(title.text())
|
||||||
|
|
||||||
|
// show location...
|
||||||
|
} else {
|
||||||
|
$('title').text(context.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
return elem
|
||||||
|
},
|
||||||
|
// XXX this needs save/reload...
|
||||||
|
editor: function(context, elem){
|
||||||
|
// XXX title
|
||||||
|
// - on focus set it to .title
|
||||||
|
// XXX text
|
||||||
|
// XXX raw
|
||||||
|
// XXX checkbox
|
||||||
|
|
||||||
|
return elem
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing:
|
||||||
|
// 1) expand macros
|
||||||
|
// 2) apply filters
|
||||||
|
// 3) merge and parse included pages:
|
||||||
|
// 1) expand macros
|
||||||
|
// 2) apply filters
|
||||||
|
// 4) fill slots
|
||||||
|
// 5) expand post-macros
|
||||||
|
//
|
||||||
|
// NOTE: stage 4 parsing is executed on the final merged page only
|
||||||
|
// once. i.e. it is not performed on the included pages.
|
||||||
|
// NOTE: included pages are parsed in their own context.
|
||||||
|
// NOTE: slots are parsed in the context of their containing page
|
||||||
|
// and not in the location they are being placed.
|
||||||
|
//
|
||||||
|
// XXX support quoted text...
|
||||||
|
// XXX need to quote regexp chars of .__include_marker__...
|
||||||
|
// XXX include recursion is detected but path recursion is not at
|
||||||
|
// this point...
|
||||||
|
// e.g. the folowing paths resolve to the same page:
|
||||||
|
// /SomePage
|
||||||
|
// /SomePage/SomePage
|
||||||
|
// or any path matching:
|
||||||
|
// /\/(SomePage\/)+/
|
||||||
|
parse: function(context, text, state, skip_post, pattern){
|
||||||
|
var that = this
|
||||||
|
|
||||||
|
state = state || {}
|
||||||
|
state.filters = state.filters || []
|
||||||
|
//state.slots = state.slots || {}
|
||||||
|
state.include = state.include || []
|
||||||
|
state.seen = state.seen || []
|
||||||
|
|
||||||
|
//pattern = pattern || RegExp('@([a-zA-Z-_]+)\\(([^)]*)\\)', 'mg')
|
||||||
|
pattern = pattern || RegExp.apply(null, this.__macro__pattern__)
|
||||||
|
|
||||||
|
// XXX need to quote regexp chars...
|
||||||
|
var include_marker = RegExp(this.__include_marker__, 'g')
|
||||||
|
|
||||||
|
var parsed = typeof(text) == typeof('str') ?
|
||||||
|
$('<span>').html(text)
|
||||||
|
: text
|
||||||
|
|
||||||
|
var _parseText = function(context, text, macro){
|
||||||
|
return text.replace(pattern, function(match){
|
||||||
|
// quoted macro...
|
||||||
|
if(match[0] == '\\' && macro['*'] == null){
|
||||||
|
return match.slice(1)
|
||||||
|
//return match
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX parse match...
|
||||||
|
var d = match.match(/@([a-zA-Z-_:]*)\(([^)]*)\)/)
|
||||||
|
|
||||||
|
var name = d[1]
|
||||||
|
|
||||||
|
if(name in macro || '*' in macro){
|
||||||
|
var elem = $('<'+name+'/>')
|
||||||
|
|
||||||
|
name = name in macro ? name : '*'
|
||||||
|
|
||||||
|
// format positional args....
|
||||||
|
var a = d[2]
|
||||||
|
.split(/((['"]).*?\2)|\s+/g)
|
||||||
|
// cleanup...
|
||||||
|
.filter(function(e){ return e && e != '' && !/^['"]$/.test(e)})
|
||||||
|
// remove quotes...
|
||||||
|
.map(function(e){ return /^(['"]).*\1$/.test(e) ? e.slice(1, -1) : e })
|
||||||
|
|
||||||
|
// add the attrs to the element...
|
||||||
|
name != '*'
|
||||||
|
&& a.forEach(function(e, i){
|
||||||
|
var k = ((macro[name] || {}).macro_args || [])[i]
|
||||||
|
k && elem.attr(k, e)
|
||||||
|
})
|
||||||
|
|
||||||
|
// call macro...
|
||||||
|
var res = macro[name]
|
||||||
|
.call(that, context, elem, state,
|
||||||
|
function(elem, c){
|
||||||
|
return _parse(c || context, elem, macro) },
|
||||||
|
match)
|
||||||
|
|
||||||
|
return res instanceof jQuery ?
|
||||||
|
// merge html of the returned set of elements...
|
||||||
|
res.map(function(i, e){ return e.outerHTML })
|
||||||
|
.toArray()
|
||||||
|
.join('\n')
|
||||||
|
: typeof(res) != typeof('str') ? res.outerHTML
|
||||||
|
: res
|
||||||
|
}
|
||||||
|
|
||||||
|
return match
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// NOTE: this modifies parsed in-place...
|
||||||
|
var _parse = function(context, parsed, macro){
|
||||||
|
$(parsed).contents().each(function(_, e){
|
||||||
|
// #text / comment node -> parse the @... macros...
|
||||||
|
if(e.nodeType == e.TEXT_NODE || e.nodeType == e.COMMENT_NODE){
|
||||||
|
// get actual element content...
|
||||||
|
var text = $('<div>').append($(e).clone()).html()
|
||||||
|
|
||||||
|
// conditional comment...
|
||||||
|
if(e.nodeType == e.COMMENT_NODE
|
||||||
|
&& /^<!--\s*\[pWiki\[(.|\n)*\]\]\s*-->$/.test(text)){
|
||||||
|
text = text
|
||||||
|
.replace(/^<!--\s*\[pWiki\[/, '')
|
||||||
|
.replace(/\]\]\s*-->$/, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
$(e).replaceWith(_parseText(context, text, macro))
|
||||||
|
|
||||||
|
// node -> html-style + attrs...
|
||||||
|
} else {
|
||||||
|
var name = e.nodeName.toLowerCase()
|
||||||
|
|
||||||
|
// parse attr values...
|
||||||
|
for(var i=0; i < e.attributes.length; i++){
|
||||||
|
var attr = e.attributes[i]
|
||||||
|
|
||||||
|
attr.value = _parseText(context, attr.value, macro)
|
||||||
|
}
|
||||||
|
|
||||||
|
// macro match -> call macro...
|
||||||
|
if(name in macro){
|
||||||
|
$(e).replaceWith(macro[name]
|
||||||
|
.call(that, context, e, state,
|
||||||
|
function(elem, c){
|
||||||
|
return _parse(c || context, elem, macro) }))
|
||||||
|
|
||||||
|
// normal tag -> sub-tree...
|
||||||
|
} else {
|
||||||
|
_parse(context, e, macro)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
var _filter = function(lst, filters){
|
||||||
|
lst
|
||||||
|
// unique -- leave last occurance..
|
||||||
|
.filter(function(k, i, lst){
|
||||||
|
return k[0] != '-'
|
||||||
|
// filter dupplicates...
|
||||||
|
&& lst.slice(i+1).indexOf(k) == -1
|
||||||
|
// filter disabled...
|
||||||
|
&& lst.slice(0, i).indexOf('-' + k) == -1
|
||||||
|
})
|
||||||
|
// unique -- leave first occurance..
|
||||||
|
//.filter(function(k, i, lst){ return lst.slice(0, i).indexOf(k) == -1 })
|
||||||
|
// apply the filters...
|
||||||
|
.forEach(function(f){
|
||||||
|
var k = f
|
||||||
|
// get filter aliases...
|
||||||
|
var seen = []
|
||||||
|
while(typeof(k) == typeof('str') && seen.indexOf(k) == -1){
|
||||||
|
seen.push(k)
|
||||||
|
k = filters[k]
|
||||||
|
}
|
||||||
|
// could not find the filter...
|
||||||
|
if(!k){
|
||||||
|
//console.warn('Unknown filter:', f)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// use the filter...
|
||||||
|
parsed = k.call(that, context, parsed)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// macro stage...
|
||||||
|
_parse(context, parsed, this.macro)
|
||||||
|
|
||||||
|
// filter stage...
|
||||||
|
_filter(state.filters.concat(this.__filters__), this.filter)
|
||||||
|
|
||||||
|
// merge includes...
|
||||||
|
parsed
|
||||||
|
.html(parsed.html().replace(include_marker, function(){
|
||||||
|
var page = state.include.shift()
|
||||||
|
var elem = $(page.shift())
|
||||||
|
page = page.pop()
|
||||||
|
var isolated = elem.attr('isolated') == 'true'
|
||||||
|
|
||||||
|
var seen = state.seen.slice()
|
||||||
|
if(seen.indexOf(page.path) >= 0){
|
||||||
|
return elem.html()
|
||||||
|
}
|
||||||
|
seen.push(page.path)
|
||||||
|
|
||||||
|
return page.map(function(page){
|
||||||
|
return $('<div>')
|
||||||
|
.append(elem
|
||||||
|
.clone()
|
||||||
|
.attr('src', page.path)
|
||||||
|
.append(that
|
||||||
|
.parse(page,
|
||||||
|
page.raw,
|
||||||
|
{
|
||||||
|
//slots: !isolated ? state.slots : {},
|
||||||
|
templates: state.templates,
|
||||||
|
seen: seen,
|
||||||
|
},
|
||||||
|
!isolated)))
|
||||||
|
//true)))
|
||||||
|
.html()
|
||||||
|
}).join('\n')
|
||||||
|
}))
|
||||||
|
|
||||||
|
// post processing...
|
||||||
|
if(!skip_post){
|
||||||
|
// fill slots...
|
||||||
|
// XXX need to prevent this from processing slots in editable
|
||||||
|
// elements...
|
||||||
|
slots = {}
|
||||||
|
// get slots...
|
||||||
|
parsed.find('slot')
|
||||||
|
.each(function(i, e){
|
||||||
|
e = $(e)
|
||||||
|
|
||||||
|
// XXX not sure about this...
|
||||||
|
// ...check if it prevents correct slot parsing
|
||||||
|
// within an isolated include...
|
||||||
|
if(e.parents('[isolated="true"]').length > 0){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var n = e.attr('name')
|
||||||
|
|
||||||
|
n in slots && e.detach()
|
||||||
|
|
||||||
|
slots[n] = e
|
||||||
|
})
|
||||||
|
// place slots...
|
||||||
|
parsed.find('slot')
|
||||||
|
.each(function(i, e){
|
||||||
|
e = $(e)
|
||||||
|
|
||||||
|
// XXX not sure about this...
|
||||||
|
// ...check if it prevents correct slot parsing
|
||||||
|
// within an isolated include...
|
||||||
|
if(e.parents('[isolated="true"]').length > 0){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var n = e.attr('name')
|
||||||
|
|
||||||
|
e.replaceWith(slots[n])
|
||||||
|
})
|
||||||
|
|
||||||
|
// post-macro...
|
||||||
|
// XXX for some odd reason this clears the backslash from
|
||||||
|
// quoted macros in raw fields...
|
||||||
|
//this.post_macro
|
||||||
|
// && _parse(context, parsed, this.post_macro)
|
||||||
|
}
|
||||||
|
|
||||||
|
// post-filter stage...
|
||||||
|
// XXX get list from context.config...
|
||||||
|
_filter(this.__post_filters__, this.post_filter)
|
||||||
|
|
||||||
|
// XXX shuld we get rid of the root span???
|
||||||
|
return parsed.contents()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* vim:set ts=4 sw=4 : */ return module })
|
||||||
113
pwiki.js
113
pwiki.js
@ -11,6 +11,8 @@ var object = require('lib/object')
|
|||||||
var actions = require('lib/actions')
|
var actions = require('lib/actions')
|
||||||
var features = require('lib/features')
|
var features = require('lib/features')
|
||||||
|
|
||||||
|
var macro = require('macro')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
@ -81,17 +83,19 @@ module.path2re = function(path){
|
|||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
|
||||||
// base pWiki object...
|
|
||||||
var pWiki =
|
|
||||||
module.pWiki = object.makeConstructor('pWiki', actions.MetaActions)
|
|
||||||
|
|
||||||
// pWiki featureset...
|
// pWiki featureset...
|
||||||
var pWikiFeatures =
|
var pWikiFeatures =
|
||||||
module.pWikiFeatures = new features.FeatureSet()
|
module.pWikiFeatures = new features.FeatureSet()
|
||||||
|
|
||||||
|
/*
|
||||||
|
// base pWiki object...
|
||||||
|
var pWiki =
|
||||||
|
module.pWiki = object.makeConstructor('pWiki', actions.MetaActions)
|
||||||
|
|
||||||
// base instance constructor...
|
// base instance constructor...
|
||||||
pWikiFeatures.__actions__ =
|
pWikiFeatures.__actions__ =
|
||||||
function(){ return actions.Actions(pWiki()) }
|
function(){ return actions.Actions(pWiki()) }
|
||||||
|
//*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -140,11 +144,13 @@ module.pWikiData = {
|
|||||||
// XXX should this overwrite or expand???
|
// XXX should this overwrite or expand???
|
||||||
// XXX should from be pattern compatible???
|
// XXX should from be pattern compatible???
|
||||||
data: function(path, value){
|
data: function(path, value){
|
||||||
|
// get the data...
|
||||||
if(value == null){
|
if(value == null){
|
||||||
return this.__data ?
|
return this.__data ?
|
||||||
JSON.parse(JSON.stringify(this.__data[path]))
|
JSON.parse(JSON.stringify(this.__data[path] || {}))
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
// set the data...
|
||||||
} else {
|
} else {
|
||||||
this.__data = this.__data || {}
|
this.__data = this.__data || {}
|
||||||
this.__data[path] = JSON.parse(JSON.stringify(value))
|
this.__data[path] = JSON.parse(JSON.stringify(value))
|
||||||
@ -189,9 +195,10 @@ module.pWikiData = {
|
|||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
|
||||||
// XXX need a startup sequence...
|
// Base pWiki page API...
|
||||||
var pWikiPageActions =
|
//
|
||||||
module.pWikiPageActions = actions.Actions({
|
var pWikiBase =
|
||||||
|
module.pWikiBase = actions.Actions({
|
||||||
config: {
|
config: {
|
||||||
'home-page': 'WikiHome',
|
'home-page': 'WikiHome',
|
||||||
'default-page': 'EmptyPage',
|
'default-page': 'EmptyPage',
|
||||||
@ -205,6 +212,11 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
'post-acquesition-order': [],
|
'post-acquesition-order': [],
|
||||||
|
|
||||||
'order-unsorted-first': false,
|
'order-unsorted-first': false,
|
||||||
|
|
||||||
|
// sorting...
|
||||||
|
'default-sort-methods': [
|
||||||
|
'path',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// pWikiData...
|
// pWikiData...
|
||||||
@ -383,7 +395,10 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
var d = this.data()
|
var d = this.data()
|
||||||
// get...
|
// get...
|
||||||
if(arguments.length == 1){
|
if(arguments.length == 1){
|
||||||
return d[name]
|
return d[name] === undefined ?
|
||||||
|
// force returning undefined...
|
||||||
|
actions.UNDEFINED
|
||||||
|
: d[name]
|
||||||
|
|
||||||
// clear...
|
// clear...
|
||||||
} else if(value === undefined){
|
} else if(value === undefined){
|
||||||
@ -393,6 +408,8 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
} else {
|
} else {
|
||||||
d[name] = value
|
d[name] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write the data...
|
||||||
// XXX is it good to write the whole thing???
|
// XXX is it good to write the whole thing???
|
||||||
this.data(d)
|
this.data(d)
|
||||||
}],
|
}],
|
||||||
@ -648,7 +665,6 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
|
|
||||||
__default_sort_methods__: ['path'],
|
|
||||||
__sort_methods__: {
|
__sort_methods__: {
|
||||||
title: function(a, b){
|
title: function(a, b){
|
||||||
return a.page.title() < b.page.title() ? -1
|
return a.page.title() < b.page.title() ? -1
|
||||||
@ -718,8 +734,7 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
: [].slice.call(arguments)
|
: [].slice.call(arguments)
|
||||||
|
|
||||||
res.__order_by = methods = methods.length == 0 ?
|
res.__order_by = methods = methods.length == 0 ?
|
||||||
(this.__default_sort_methods__
|
(this.config['default-sort-methods'] || ['path'])
|
||||||
|| pWikiPage.__default_sort_methods__)
|
|
||||||
: methods
|
: methods
|
||||||
|
|
||||||
res.update()
|
res.update()
|
||||||
@ -754,11 +769,11 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
var reverse = false
|
var reverse = false
|
||||||
|
|
||||||
var sort_methods = this.__sort_methods__
|
var sort_methods = this.__sort_methods__
|
||||||
|| pWikiPage.__sort_methods__
|
|| pWikiBase.__sort_methods__
|
||||||
|
|
||||||
var methods = (this.__order_by
|
var methods = (this.__order_by
|
||||||
|| this.__default_sort_methods__
|
|| this.config['default-sort-methods']
|
||||||
|| pWikiPage.__default_sort_methods__)
|
|| ['path'])
|
||||||
.map(function(m){
|
.map(function(m){
|
||||||
var reversed = m[0] == '-'
|
var reversed = m[0] == '-'
|
||||||
m = reversed ? m.slice(1) : m
|
m = reversed ? m.slice(1) : m
|
||||||
@ -813,14 +828,72 @@ module.pWikiPageActions = actions.Actions({
|
|||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
|
|
||||||
var pWikiPage = pWikiFeatures.Feature({
|
|
||||||
title: '',
|
|
||||||
tag: 'page',
|
|
||||||
|
|
||||||
actions: pWikiPageActions,
|
// Basic data sort-hands...
|
||||||
|
//
|
||||||
|
var pWikiContent =
|
||||||
|
module.pWikiContent = actions.Actions(pWikiBase, {
|
||||||
|
config: {
|
||||||
|
},
|
||||||
|
|
||||||
|
raw: ['Page/',
|
||||||
|
function(value){
|
||||||
|
return arguments.length == 0 ?
|
||||||
|
(this.attr('text') || '')
|
||||||
|
: this.attr('text', value) }],
|
||||||
|
|
||||||
|
checked: ['Page/',
|
||||||
|
function(value){
|
||||||
|
return arguments.length == 0 ?
|
||||||
|
!!this.attr('checked')
|
||||||
|
: this.attr('checked', value || undefined) }],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// Data processing and macros...
|
||||||
|
//
|
||||||
|
var pWikiMacros =
|
||||||
|
module.pWikiMacros = actions.Actions(pWikiContent, {
|
||||||
|
__macro_parser__: macro,
|
||||||
|
|
||||||
|
config: {
|
||||||
|
},
|
||||||
|
|
||||||
|
text: ['Page/',
|
||||||
|
function(value){
|
||||||
|
return arguments.length == 0 ?
|
||||||
|
(this.title() == 'raw' ?
|
||||||
|
(this.raw() || '')
|
||||||
|
: pWikiMacros.__macro_parser__.parse(this, this.raw()))
|
||||||
|
: this.raw(value) }],
|
||||||
|
code: ['Page/',
|
||||||
|
function(value){
|
||||||
|
return arguments.length == 0 ?
|
||||||
|
this.text().text()
|
||||||
|
// XXX should we un-encode here???
|
||||||
|
: this.text(value) }],
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
links: ['Page/',
|
||||||
|
function(){
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// pWiki Page...
|
||||||
|
//
|
||||||
|
// NOTE: looks like multiple inheritance, feels like multiple inheritance
|
||||||
|
// but sadly is not multiple inheritance...
|
||||||
|
// ...though, functionally, this is 90% there, about as far as we
|
||||||
|
// can get using native JS lookup mechanisms, or at least the
|
||||||
|
// farthest I've pushed it so far...
|
||||||
|
var pWikiPage =
|
||||||
|
module.pWikiPage = actions.mix(
|
||||||
|
pWikiBase,
|
||||||
|
pWikiContent,
|
||||||
|
pWikiMacros)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
|
|
||||||
@ -922,7 +995,7 @@ module._test = function(){
|
|||||||
var wiki = Object.create(pWikiData)
|
var wiki = Object.create(pWikiData)
|
||||||
wiki.__data = Object.create(module._test_data)
|
wiki.__data = Object.create(module._test_data)
|
||||||
|
|
||||||
var w = pWikiPageActions.clone()
|
var w = pWikiPage.clone()
|
||||||
w.wiki = wiki
|
w.wiki = wiki
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user