diff --git a/pwiki/page.js b/pwiki/page.js
index f7306f4..dc8e6e3 100755
--- a/pwiki/page.js
+++ b/pwiki/page.js
@@ -505,7 +505,7 @@ object.Constructor('Page', BasePage, {
QUOTING_MACROS: ['quote'],
// templates used to render a page via .text
- PAGE_TEMPLATE: '_text',
+ PAGE_TEMPLATE: '_view',
// NOTE: comment this out to make the system fail when nothing is
// resolved, not even the System/NotFound page...
@@ -658,6 +658,7 @@ object.Constructor('Page', BasePage, {
// the context, this potentially can lead to false positives.
//
// XXX should this be lazy???
+ // XXX should we use .__parser__.expand(..) instead of .parse(..) ???
include: Macro(
['src', 'recursive', 'join', ['isolated']],
async function(args, body, state, key='included', handler){
@@ -758,6 +759,7 @@ object.Constructor('Page', BasePage, {
// XXX need to handle pattern paths (like include: join=...)
// XXX need a way to escape macros -- i.e. include in a quoted text...
quote: Macro(
+ //['src', 'filter', 'text', 'join'],
['src', 'filter', 'text'],
async function(args, body, state){
var src = args.src //|| args[0]
@@ -866,12 +868,18 @@ object.Constructor('Page', BasePage, {
// show first instance...
: name in slots)
- slots[name] = [...await this.__parser__.expand(this, text, state)]
+ // NOTE: we prioritize the nested slots over the current...
+ delete slots[name]
+ var slot = await this.__parser__.expand(this, text, state)
+ slots[name] =
+ slots[name]
+ ?? slot
return hidden ?
''
: function(state){
return state.slots[name] } }),
+ 'slot-content': ['slot'],
//
// > ..
@@ -969,7 +977,7 @@ object.Constructor('Page', BasePage, {
&& (text || args['else'])){
var else_block = _getBlock('else')
return else_block ?
- [...await this.__parser__.expand(this, else_block, state)]
+ await this.__parser__.expand(this, else_block, state)
: undefined }
// sort pages...
@@ -980,15 +988,13 @@ object.Constructor('Page', BasePage, {
var join_block = _getBlock('join')
// apply macro text...
- var res = await pages
- .map(function(page, i){
+ var res = pages
+ .map(function(page){
return that.__parser__.expand(page, text, state) })
return join_block ?
- res.between(await that.__parser__.expand(
+ res.between(
// render join block relative to the path before the first '*'...
- that.get(that.path.split(/\*/).shift()),
- join_block,
- state))
+ await that.__parser__.expand(base, join_block, state))
: res } }),
// nesting rules...
@@ -1200,10 +1206,10 @@ module.System = {
// These are used to control how a page is rendered.
//
// pWiki has to have a template appended to any path, if one is not
- // given then "_text" is used internally.
+ // given then "_view" is used internally.
//
// A template is rendered in the context of the parent page, e.g.
- // for /path/to/page, the actual rendered template is /path/to/page/_text
+ // for /path/to/page, the actual rendered template is /path/to/page/_view
// and it is rendered from /path/to/page.
//
// A template is any page named starting with an underscore ("_")
@@ -1217,10 +1223,10 @@ module.System = {
//
// XXX all of these should support pattern pages...
_text: {
- //text: '@include(. isolated join="@source(file-separator)")' },
- // XXX problem: the show slot
+ text: '@include(. isolated join="@source(file-separator)")' },
+ _view: {
text: object.doc`
- @source(./path)/_edit
+ /list @source(./path)/_edit
@@ -1239,7 +1245,22 @@ module.System = {
''
+'
'
+''},
- // XXX can we reuse _text here???
+ /* XXX can we reuse _view here???
+ _edit: {
+ text:
+ '@include(PageTemplate)'
+ +'@source(./path)'
+ +''
+ +''
+ +''
+ +'
'
+ +'
'
+ +''
+ +''},
+ /*/
_edit: {
text:
'@source(./path)'
@@ -1252,13 +1273,30 @@ module.System = {
+'
'
+''
+''},
+ //*/
+ edit: {
+ text:
+ //'@include(PageTemplate)'
+ '@include(_view)'
+ +'@source(../path)'
+ +''
+ // XXX for some reason this is not called...
+ +''
+ +''
+ +'
'
+ +'
'
+ +''
+ +''},
// XXX this does not yet work...
// XXX "_test" breaks differently than "test"
//_test: {
test: {
text: object.doc`
- @source(_text)
+ @source(_view)
HEADER
CONTENT
FOOTER `},
@@ -1269,68 +1307,41 @@ module.System = {
list: {
- text: `@source(.)` },
+ text: object.doc`
+
+ /list
+ ⇑
+ @source(../path)
+
+
+ ↳
+ @source(./name)
+ ×
+ ` },
// XXX this is really slow...
- // XXX for some reason replacing both @quote(..) with @source(..) in
- // the links will break macro parsing...
- // XXX should this be all or tree???
tree: {
text: object.doc`
` },
-
- // XXX this is somewhat broken...
+ all: {
+ text: `@include(../**/path join="
")`},
info: {
text: object.doc`
- # @source(./path)
-
- - Render root: @source(./renderer)
- - Render root: @source(./renderer)
-
- ` },
-
- // XXX tests...
- //
- test_page: function(){
- console.log('--- RENDERER:', this.render_root)
- console.log('--- PATH: ', this.path)
- console.log('--- REFERRER:', this.referrer)
- console.log('--- PAGE:', this)
- return this.path },
- test_list: function(){
- return 'abcdef'.split('') },
- // XXX problem: it appears that we can't fill a slot from within a slot...
- // ...the "content" slot below does not override the content slot in _text
- test_base_slots: {
- text: object.doc`OUTER
- HEADER
- CONTENT
- FOOTER `},
- // XXX does not work yet...
- test_slots: {
- text: object.doc`
- Sequential:
- unfilled
- filled
- refilled
-
- Nested:
-
- unfilled
-
- filled
-
- refilled
-
-
- ` },
+ Path: @source(../path)
+ Resolved path: @source(../resolved)
+ Referrer: @source(../referrer)
+ Renderer: @source(../renderer)
+ ctime: @source(../ctime)
+ mtime: @source(../mtime)
+
+
` },
// page parts...
//
@@ -1348,15 +1359,24 @@ module.System = {
DeletingPage: {
text: 'Deleting: @source(../path)' },
+ PageTemplate: {
+ text: object.doc`
+ @source(./path)/_edit
+
+
+
+ ` },
+
// page actions...
//
-
// metadata...
//
renderer: function(){
return (this.render_root || {}).path },
+ referrer: function(){
+ return this.referrer || this.path },
path: function(){
return this.get('..').path },
location: function(){
@@ -1366,9 +1386,9 @@ module.System = {
name: function(){
return this.get('..').name },
ctime: function(){
- return this.get('..').data.ctime },
+ return this.get('..').data.ctime ?? '' },
mtime: function(){
- return this.get('..').data.mtime },
+ return this.get('..').data.mtime ?? '' },
// XXX this can be a list for pattern paths...
resolved: function(){
@@ -1412,6 +1432,11 @@ module.System = {
// XXX System/forward
// XXX System/sort
// XXX System/reverse
+
+
+ // XXX broken...
+ test_list: function(){
+ return 'abcdef'.split('') },
}
var Settings =
diff --git a/pwiki/parser.js b/pwiki/parser.js
index 55942ff..8e6ddc0 100755
--- a/pwiki/parser.js
+++ b/pwiki/parser.js
@@ -387,18 +387,13 @@ module.BaseParser = {
// Expand macros...
//
+ // ::= [ - , .. ]
//
- ::=
- //
- // // returned by .macros.filter(..)
- // | {
- // // XXX is this still relevant...
- // filters: [
- // ''
- // | '-',
- // ...
- // ],
- // data: [
- , .. ],
- // }
+ //
+ // |
+ // |
+ // | { data: }
+ // |
//
// XXX macros: we are mixing up ast state and parse state...
// one should only be used for parsing and be forgotten after
@@ -440,13 +435,37 @@ module.BaseParser = {
} else {
yield res } } },
+ // recursively resolve and enumerate the ast...
+ //
+ // ::= [
- , .. ]
+ //
- ::=
+ //
+ // | { data: }
+ //
+ // XXX should this also resolve e.data???
+ resolve: async function*(page, ast, state={}){
+ // NOTE: we need to await for ast here as we need stage 2 of
+ // parsing to happen AFTER everything else completes...
+ for(var e of await ast){
+ e = typeof(e) == 'function' ?
+ e.call(page, state)
+ : e
+
+ if(e instanceof Array){
+ yield* this.resolve(page, e, state)
+ } else if(e instanceof Object && 'data' in e){
+ yield { data: await this.resolve(page, e.data, state) }
+ } else {
+ yield e } } },
+
// Fully parse a page...
//
// This runs in two stages:
- // - expand the page
+ // - resolve the page
// - lex the page -- .lex(..)
// - group block elements -- .group(..)
// - expand macros -- .expand(..)
+ // - resolve ast -- .resolve(..)
// - apply filters
//
// NOTE: this has to synchronize everything between stage 1 (up to
@@ -458,7 +477,6 @@ module.BaseParser = {
// them on demand rather than on encounter (as is now), e.g.
// a slot when loaded will replace the prior occurrences...
//
- // XXX this should be recursive....
// XXX add a special filter to clear pending filters... (???)
parse: async function(page, ast, state={}){
var that = this
@@ -468,17 +486,7 @@ module.BaseParser = {
this.expand(page, ast, state)
: ast
- // NOTE: we need to await for ast here as we need stage 2 of
- // parsing to happen AFTER everything else completes...
- return await Promise.iter((await ast)
- .flat()
- // post handlers...
- .map(function(section){
- return typeof(section) == 'function' ?
- // NOTE: this can produce promises...
- section.call(page, state)
- : section }))
- .flat()
+ return await this.resolve(page, ast, state)
// filters...
.map(function(section){
return (
diff --git a/pwiki/store/base.js b/pwiki/store/base.js
index 9944891..58e7990 100755
--- a/pwiki/store/base.js
+++ b/pwiki/store/base.js
@@ -165,7 +165,7 @@ module.BaseStore = {
.replace(/^\/|\/$/g, '')
.replace(/\//g, '\\/')
.replace(/\*\*/g, '.*')
- .replace(/\*/g, '[^\\/]*')
+ .replace(/(?<=^|[\\\/]+|[^.])\*/g, '[^\\/]*')
}(?=[\\\\\/]|$)`)
return [...(await this.paths())
// NOTE: we are not using .filter(..) here as wee
diff --git a/pwiki2-test.js b/pwiki2-test.js
index 82c6923..f383afa 100755
--- a/pwiki2-test.js
+++ b/pwiki2-test.js
@@ -179,11 +179,9 @@ pwiki.pwiki
text: object.doc`
Sequential:
unfilled
-
filled
-
refilled
-
+
Nested:
unfilled
@@ -194,6 +192,18 @@ pwiki.pwiki
`, })
+ .update({
+ location: '/test/nesting',
+ text: object.doc`
+ Quote in macro:
+
+
+
+
+ Quote in slot:
+
+
+ ` })
.update({
location: '/test/a',
text: 'a',
diff --git a/pwiki2.js b/pwiki2.js
index 70274a6..5638bb2 100755
--- a/pwiki2.js
+++ b/pwiki2.js
@@ -1,33 +1,17 @@
/**********************************************************************
*
*
-* XXX nested slots do not seem to work...
-* XXX BUG: /** /paths -- does not work...
+* XXX might be a good idea for slots to support getting previous slot
+* content, e.g.:
+* new text
* XXX BUG?: markdown: when parsing chunks each chunk gets an open/closed
* inserted at start/end -- this breaks stuff returned by macros...
* ...there are two ways to dance around this:
* - make filters run a bit more globaly -- per block...
* - find a local parser...
-* XXX BUG?: empty stores do not appear to show up in listings...
-* ...this is expected but not intuitive...
-* might be a good idea to add a special path like /Stores to list
-* sub-stores...
+* XXX add something like /stores to list store info...
* XXX OPTIMIZE: /tree is really slow...
* ...is the problem purely in the async/await playing ping-pong???
-* XXX might be a good idea to make things optionally sync via a .sync()
-* method, or request a specific set of data (in the parser, after
-* collecting all the stuff needed and fetching it in one go)...
-* XXX might be a good idea to add page caching (state.page_cache) relative
-* to a path on parsing, to avoid re-matching the same page over and
-* over again from the same context
-* format:
-* {
-* : {
-* : ,
-* ...
-* },
-* ...
-* }
* XXX BUG: FF: conflict between object.run and PouchDB...
* XXX BUG: browser: .get('/*').raw hangs in the browser context...
* XXX BUG?: /_tree for some reason does not show anything on lower levels...