diff --git a/pwiki2.js b/pwiki2.js index 6f1c824..d7e413e 100755 --- a/pwiki2.js +++ b/pwiki2.js @@ -681,12 +681,14 @@ function*(lex, to=false, macros){ var Page = module.Page = object.Constructor('Page', BasePage, { - SKIP_FILTERS: 'nofilters', + //NO_FILTERS: 'nofilters', + ISOLATED_FILTERS: 'isolated', // XXX might be a good idea to fix filter order... filters: { // if this is used all other filters will be skipped (placeholder) nofilters: function(source){ return source }, + isolated: function(source){ return source }, // XXX move to docs... test: function(source){ @@ -698,6 +700,7 @@ object.Constructor('Page', BasePage, { markdown: function(source){ return source }, }, + macros: { // XXX move to docs... test: function*(args, body, state){ @@ -715,24 +718,28 @@ object.Constructor('Page', BasePage, { now: function(){ return ''+ Date.now() }, - // XXX local filters??? - // Example 1: - // ... - // Example 2: - // - // ... - // @filter(markdown) - // - // XXX need to nest filter namespaces -- currently parent_filters - // does not see filters defined after the block... + // + // @filter() + // /> + // + // > + // ... + // + // + // ::= + // + // | - + // + // XXX support .NO_FILTERS ... filter: function*(args, body, state){ var filters = state.filters = - state.filters ?? [] - // local filter... + state.filters + ?? [] + // local filters... if(body){ var parent_filters = state.filters filters = state.filters = - [] } + [parent_filters] } // populate filters... Object.values(args) .forEach(function(filter){ @@ -748,20 +755,24 @@ object.Constructor('Page', BasePage, { && filters.push(filter) }) // local filters... if(body){ + // isolate from parent... + state.filters.includes(this.ISOLATED_FILTERS) + && state.filters[0] instanceof Array + && state.filters.shift() // serialize the block for later processing... var res = { filters: state.filters, - // XXX might be a good idea to simply ref the parent - // context here -- i.e. link filters into a chain... - parent_filters, data: [...this.expand(body, state)], } // restore global filters... state.filters = parent_filters yield res } return }, + source: function(args, body, state){ + return args.src ? + this.get(src).render(state) + : '' }, include: function(){}, - source: function(){}, quote: function(){}, macro: function(){}, slot: function(){}, @@ -804,38 +815,52 @@ object.Constructor('Page', BasePage, { yield* res } else { yield res } } }, - // XXX add a special filter to clear pending filters... - // XXX skip nested pre-filtered blocks... + // XXX add a special filter to clear pending filters... (???) + // XXX rename and use this instead of render... postProcess: function(ast, state={}){ var that = this + ast = ast + ?? this.expand(null, state) + + var _normalize = function(filters){ + var skip = new Set() + return filters + .flat() + .tailUnique() + .filter(function(filter){ + filter[0] == '-' + && skip.add(filter.slice(1)) + return filter[0] != '-' }) + .filter(function(filter){ + return !skip.has(filter) })} + return [...ast] .map(function(section){ var filters = state.filters - // local filters... + // nested filters... if(typeof(section) != 'string'){ - // XXX also need to hanlde nested filters (no longer flat)... - // XXX merge this with .parent_filters... - filters = section.filters - section = [...that.postProcess(section.data, state)] + state.filters = _normalize(section.filters) + var res = [...that.postProcess(section.data, state)] .flat() - .join('') } - return (filters - // if this.SKIP_FILTERS is set and used then all other - // filters will be skipped... - && (!this.SKIP_FILTERS - || !filters.inculdes(this.SKIP_FILTERS))) ? - // filter... - filters - .reduce(function(res, filter){ - if(filter[0] == '-'){ - return res } - if(that.filters[filter] == null){ - throw new Error('.postProcess(..): unsupported filter: '+ filter) } - return that.filters[filter].call(that, res) }, section) - : section }) + .join('') + state.filters = filters + return res + // local filters... + } else { + return filters ? + _normalize(filters) + .reduce(function(res, filter){ + if(that.filters[filter] == null){ + throw new Error( + '.postProcess(..): unsupported filter: '+ filter) } + return that.filters[filter].call(that, res) }, section) + : section } }) .flat() .join('') }, + render: function(state={}){ + return this.postProcess(null, state) }, + // raw page text... // @@ -857,10 +882,7 @@ object.Constructor('Page', BasePage, { // XXX FUNC handle functions as pages... // XXX need to support pattern pages... get text(){ - var state = {} - return this.postProcess( - this.expand(null, state), - state) }, + return this.render() }, set text(value){ this.store.update(this.location, {text: value}) },