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 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...
|
||||
var pWikiFeatures =
|
||||
module.pWikiFeatures = new features.FeatureSet()
|
||||
|
||||
/*
|
||||
// base pWiki object...
|
||||
var pWiki =
|
||||
module.pWiki = object.makeConstructor('pWiki', actions.MetaActions)
|
||||
|
||||
// base instance constructor...
|
||||
pWikiFeatures.__actions__ =
|
||||
function(){ return actions.Actions(pWiki()) }
|
||||
//*/
|
||||
|
||||
|
||||
|
||||
@ -140,11 +144,13 @@ module.pWikiData = {
|
||||
// XXX should this overwrite or expand???
|
||||
// XXX should from be pattern compatible???
|
||||
data: function(path, value){
|
||||
// get the data...
|
||||
if(value == null){
|
||||
return this.__data ?
|
||||
JSON.parse(JSON.stringify(this.__data[path]))
|
||||
JSON.parse(JSON.stringify(this.__data[path] || {}))
|
||||
: null
|
||||
|
||||
// set the data...
|
||||
} else {
|
||||
this.__data = this.__data || {}
|
||||
this.__data[path] = JSON.parse(JSON.stringify(value))
|
||||
@ -189,9 +195,10 @@ module.pWikiData = {
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// XXX need a startup sequence...
|
||||
var pWikiPageActions =
|
||||
module.pWikiPageActions = actions.Actions({
|
||||
// Base pWiki page API...
|
||||
//
|
||||
var pWikiBase =
|
||||
module.pWikiBase = actions.Actions({
|
||||
config: {
|
||||
'home-page': 'WikiHome',
|
||||
'default-page': 'EmptyPage',
|
||||
@ -205,6 +212,11 @@ module.pWikiPageActions = actions.Actions({
|
||||
'post-acquesition-order': [],
|
||||
|
||||
'order-unsorted-first': false,
|
||||
|
||||
// sorting...
|
||||
'default-sort-methods': [
|
||||
'path',
|
||||
],
|
||||
},
|
||||
|
||||
// pWikiData...
|
||||
@ -383,7 +395,10 @@ module.pWikiPageActions = actions.Actions({
|
||||
var d = this.data()
|
||||
// get...
|
||||
if(arguments.length == 1){
|
||||
return d[name]
|
||||
return d[name] === undefined ?
|
||||
// force returning undefined...
|
||||
actions.UNDEFINED
|
||||
: d[name]
|
||||
|
||||
// clear...
|
||||
} else if(value === undefined){
|
||||
@ -393,6 +408,8 @@ module.pWikiPageActions = actions.Actions({
|
||||
} else {
|
||||
d[name] = value
|
||||
}
|
||||
|
||||
// write the data...
|
||||
// XXX is it good to write the whole thing???
|
||||
this.data(d)
|
||||
}],
|
||||
@ -648,7 +665,6 @@ module.pWikiPageActions = actions.Actions({
|
||||
}
|
||||
}],
|
||||
|
||||
__default_sort_methods__: ['path'],
|
||||
__sort_methods__: {
|
||||
title: function(a, b){
|
||||
return a.page.title() < b.page.title() ? -1
|
||||
@ -718,8 +734,7 @@ module.pWikiPageActions = actions.Actions({
|
||||
: [].slice.call(arguments)
|
||||
|
||||
res.__order_by = methods = methods.length == 0 ?
|
||||
(this.__default_sort_methods__
|
||||
|| pWikiPage.__default_sort_methods__)
|
||||
(this.config['default-sort-methods'] || ['path'])
|
||||
: methods
|
||||
|
||||
res.update()
|
||||
@ -754,11 +769,11 @@ module.pWikiPageActions = actions.Actions({
|
||||
var reverse = false
|
||||
|
||||
var sort_methods = this.__sort_methods__
|
||||
|| pWikiPage.__sort_methods__
|
||||
|| pWikiBase.__sort_methods__
|
||||
|
||||
var methods = (this.__order_by
|
||||
|| this.__default_sort_methods__
|
||||
|| pWikiPage.__default_sort_methods__)
|
||||
|| this.config['default-sort-methods']
|
||||
|| ['path'])
|
||||
.map(function(m){
|
||||
var reversed = m[0] == '-'
|
||||
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)
|
||||
wiki.__data = Object.create(module._test_data)
|
||||
|
||||
var w = pWikiPageActions.clone()
|
||||
var w = pWikiPage.clone()
|
||||
w.wiki = wiki
|
||||
return w
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user