lots of tweaks and cleanup...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-08-15 14:29:45 +03:00
parent 128b4276f7
commit 6befa05d33
9 changed files with 156 additions and 48 deletions

View File

@ -57,8 +57,8 @@ pwiki.store.update('@pouch', {
// XXX // XXX
typeof(Bootstrap) != 'undefined' //typeof(Bootstrap) != 'undefined'
&& pwiki.store.load(Bootstrap) // && pwiki.store.load(Bootstrap)

View File

@ -10,7 +10,7 @@
var WIKIWORD_PATTERN = var WIKIWORD_PATTERN =
RegExp('('+[ RegExp('('+[
// /some/path | ./some/path | ../some/path | >>/some/path // /some/path | ./some/path | ../some/path | >>/some/path
'(?:^|\\s)(|\\.|\\.\\.|>>)[\\/\\\\][^\\s]+', '(?<=^|\\s)(|\\.|\\.\\.|>>)[\\/\\\\][^\\s]+',
// [path] // [path]
'\\\\?\\[[^\\]]+\\]', '\\\\?\\[[^\\]]+\\]',
// WikiWord // WikiWord

View File

@ -22,6 +22,8 @@ base.Filter(
tables: true, tables: true,
tasklists: true, tasklists: true,
}) })
// XXX the problem here is that any string gets nested into a
// paragraph -- this messes up partial filtering...
return converter.makeHtml(source) }) return converter.makeHtml(source) })
module.quoteMarkdown = module.quoteMarkdown =

View File

@ -324,7 +324,8 @@ object.Constructor('BasePage', {
location: path, location: path,
...data, ...data,
referrer: data.referrer referrer: data.referrer
?? this.location, //?? this.location,
?? this.referrer,
strict, strict,
}) }, }) },
@ -343,10 +344,11 @@ object.Constructor('BasePage', {
: paths instanceof Promise ? : paths instanceof Promise ?
await paths await paths
: [paths] : [paths]
// XXX MATCH /*/ XXX MATCH
paths = paths.length == 0 ? paths = paths.length == 0 ?
[await this.find(path)] [await this.find(path)]
: paths : paths
//*/
for(var path of paths){ for(var path of paths){
yield this.get('/'+ path) } }, yield this.get('/'+ path) } },
@ -424,6 +426,8 @@ object.Constructor('BasePage', {
// this will make all the non-shadowed attrs set on the // this will make all the non-shadowed attrs set on the
// root visible to all sub-pages. // root visible to all sub-pages.
: Object.create(src), : Object.create(src),
// XXX
//{...this},
{ {
root: this.root ?? this, root: this.root ?? this,
location: this.location, location: this.location,
@ -695,21 +699,15 @@ object.Constructor('Page', BasePage, {
if(typeof(args) == 'string'){ if(typeof(args) == 'string'){
var [macro, args, body, state, key, handler] = arguments var [macro, args, body, state, key, handler] = arguments
key = key ?? 'included' } key = key ?? 'included' }
// positional args... var base = this.get(this.path.split(/\*/).shift())
var src = args.src var src = args.src
&& await this.parse(args.src, state) && await base.parse(args.src, state)
if(!src){ if(!src){
return } return }
var recursive = args.recursive || body var recursive = args.recursive || body
var isolated = args.isolated var isolated = args.isolated
var join = args.join var join = args.join
&& await this && await base.parse(args.join, state)
// render join block relative to the path before the first '*'...
.get(this.path.split(/\*/).shift())
.parse(args.join, state)
// parse arg values...
var base = this.get(src).path
handler = handler handler = handler
?? async function(src){ ?? async function(src){
@ -734,9 +732,9 @@ object.Constructor('Page', BasePage, {
//if(seen.includes(full) || full == base){ //if(seen.includes(full) || full == base){
if(seen.includes(full)){ if(seen.includes(full)){
if(!recursive){ if(!recursive){
return page.parse(page.get('./'+page.RECURSION_ERROR).raw) } return base.parse(page.get('./'+page.RECURSION_ERROR).raw) }
// have the 'recursive' arg... // have the 'recursive' arg...
return page.parse(recursive, state) } return base.parse(recursive, state) }
seen.push(full) seen.push(full)
// load the included page... // load the included page...
@ -787,12 +785,13 @@ object.Constructor('Page', BasePage, {
['src', 'filter', 'text'], ['src', 'filter', 'text'],
async function(args, body, state){ async function(args, body, state){
var src = args.src //|| args[0] var src = args.src //|| args[0]
var base = this.get(this.path.split(/\*/).shift())
var text = args.text var text = args.text
?? body ?? body
?? [] ?? []
// parse arg values... // parse arg values...
src = src ? src = src ?
await this.parse(src, state) await base.parse(src, state)
: src : src
text = src ? text = src ?
// source page... // source page...
@ -935,6 +934,7 @@ object.Constructor('Page', BasePage, {
var that = this var that = this
var name = args.name //?? args[0] var name = args.name //?? args[0]
var src = args.src var src = args.src
var base = this.get(this.path.split(/\*/).shift())
var sort = (args.sort ?? '') var sort = (args.sort ?? '')
.split(/\s+/g) .split(/\s+/g)
.filter(function(e){ .filter(function(e){
@ -970,7 +970,7 @@ object.Constructor('Page', BasePage, {
return block } return block }
if(name){ if(name){
name = await this.parse(name, state) name = await base.parse(name, state)
// define new named macro... // define new named macro...
if(text){ if(text){
;(state.macros = state.macros ?? {})[name] = text ;(state.macros = state.macros ?? {})[name] = text
@ -980,7 +980,7 @@ object.Constructor('Page', BasePage, {
text = state.macros[name] } } text = state.macros[name] } }
if(src){ if(src){
src = await this.parse(src, state) src = await base.parse(src, state)
var pages = this.get(src, strict) var pages = this.get(src, strict)
pages = await pages.isArray ? pages = await pages.isArray ?
// XXX should we wrap this in pages... // XXX should we wrap this in pages...
@ -1113,12 +1113,20 @@ object.Constructor('Page', BasePage, {
if(!tpl){ if(!tpl){
throw new Error('UNKNOWN RENDER TEMPLATE: '+ tpl_name) } throw new Error('UNKNOWN RENDER TEMPLATE: '+ tpl_name) }
var data = {
render_root: this,
}
// render template in context of page... // render template in context of page...
return this.get(path) return this.get(path, data)
.parse(await this.get(tpl).raw) }).call(this) }, .parse(await this.get(tpl, data).raw) }).call(this) },
set text(value){ set text(value){
this.__update__({text: value}) }, this.__update__({text: value}) },
//this.onTextUpdate(value) }, //this.onTextUpdate(value) },
clone: function(data={}, ...args){
this.render_root
&& (data = {render_root: this.render_root, ...data})
return object.parentCall(Page.prototype.clone, this, data, ...args) },
}) })
@ -1244,7 +1252,7 @@ module.System = {
'<macro src="." join="@source(file-separator)">' '<macro src="." join="@source(file-separator)">'
+'<pre wikiwords="no"><quote filter="quote-tags" src="."/></pre>' +'<pre wikiwords="no"><quote filter="quote-tags" src="."/></pre>'
+'</macro>'}, +'</macro>'},
_ed: { _edit: {
//_edit: { //_edit: {
text: text:
'<macro src="." join="@source(file-separator)">' '<macro src="." join="@source(file-separator)">'
@ -1256,8 +1264,50 @@ module.System = {
+'</pre>' +'</pre>'
+'</macro>'}, +'</macro>'},
paths: {
text: '<macro src="../*/path" join=" ">@source(.)</macro>' }, // XXX debug...
_path: {text: '@source(./path join=" ")'},
list: {
text: '<macro src="../*/path" join="@source(line-separator)">@source(.)</macro>' },
// 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`
<macro src="../*">
<div>
<a href="#@quote(./path)">@source(./name)</a>
<a href="#@quote(./path)/delete">&times;</a>
<div style="padding-left: 30px">
@source(./tree)
</div>
</div>
</macro>` },
// XXX this is somewhat broken...
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('') },
// page parts... // page parts...
// //
@ -1272,17 +1322,18 @@ module.System = {
NotFoundError: { NotFoundError: {
text: 'NOT FOUND ERROR: @quote(./path)' }, text: 'NOT FOUND ERROR: @quote(./path)' },
DeletingPage: {
text: 'Deleting: @source(../path)' },
// page actions... // page actions...
// //
// XXX tests...
test_list: function(){
return 'abcdef'.split('') },
// metadata... // metadata...
// //
renderer: function(){
return (this.render_root || {}).path },
path: function(){ path: function(){
return this.get('..').path }, return this.get('..').path },
location: function(){ location: function(){
@ -1324,9 +1375,16 @@ module.System = {
// actions... // actions...
// //
delete: function(){ delete: function(){
this.location = '..' var target = this.get('..')
this.delete()
return this.text }, target.delete()
// redirect...
this.render_root
&& (this.render_root.location = this.referrer)
// show info about the delete operation...
return target.get('./DeletingPage').text },
// XXX System/back // XXX System/back
// XXX System/forward // XXX System/forward
// XXX System/sort // XXX System/sort

View File

@ -500,7 +500,6 @@ module.BaseParser = {
// will have no effect on the result... // will have no effect on the result...
return page.filters[filter].call(page, res) return page.filters[filter].call(page, res)
?? res }, section) ?? res }, section)
//*/
// no global filters... // no global filters...
: section ) }) : section ) })
.flat() .flat()

View File

@ -58,9 +58,10 @@ module = {
var root = path[0] == '' var root = path[0] == ''
|| path[0] == '/' || path[0] == '/'
path = (path instanceof Array ? path = (path instanceof Array ?
path path.join('/')
// NOTE: this will also trim the path elements... : path)
: path.split(/\s*[\\\/]+\s*/)) // NOTE: this will also trim the path elements...
.split(/\s*[\\\/]+\s*/)
.reduce(function(res, e, i, L){ .reduce(function(res, e, i, L){
// special case: leading '..' / '.' // special case: leading '..' / '.'
if(res.length == 0 if(res.length == 0
@ -94,8 +95,7 @@ module = {
return this.normalize( return this.normalize(
(parts[0] instanceof Array ? (parts[0] instanceof Array ?
parts[0] parts[0]
: parts) : parts),
.join('/'),
'string') }, 'string') },
basename: function(path){ basename: function(path){
path = this.split(path) path = this.split(path)

View File

@ -68,6 +68,7 @@ module.BaseStore = {
// XXX might be a good idea to cache this... // XXX might be a good idea to cache this...
__paths__: async function(){ __paths__: async function(){
return Object.keys(this.data) }, return Object.keys(this.data) },
//* XXX uncached...
paths: async function(local=false){ paths: async function(local=false){
return this.__paths__() return this.__paths__()
.iter() .iter()
@ -75,6 +76,25 @@ module.BaseStore = {
.concat((!local && (this.next || {}).paths) ? .concat((!local && (this.next || {}).paths) ?
this.next.paths() this.next.paths()
: []) }, : []) },
/*/
__paths_cache_timeout: 1000,
__paths_cache_timer: undefined,
__paths_cache: undefined,
paths: async function(local=false){
this.__paths_cache_timer =
this.__paths_cache_timer
?? setTimeout(function(){
delete this.__paths_cache_timer
delete this.__paths_cache
}.bind(this), this.__paths_cache_timeout ?? 1000)
return this.__paths_cache
|| this.__paths__()
.iter()
// XXX NEXT
.concat((!local && (this.next || {}).paths) ?
this.next.paths()
: []) },
//*/
// //
// .exists(<path>) // .exists(<path>)
@ -364,7 +384,7 @@ module.BaseStore = {
res[path] = page } } } res[path] = page } } }
return (stringify return (stringify
&& typeof(res) != 'string') ? && typeof(res) != 'string') ?
JSON.stringify(res) JSON.stringify(res, options.replacer, options.space)
: res }, : res },
// XXX NEXT EXPERIMENTAL... // XXX NEXT EXPERIMENTAL...

View File

@ -58,6 +58,22 @@ pwiki.store.update('@pouch', {
// XXX TEST... // XXX TEST...
// XXX add filter tests... // XXX add filter tests...
pwiki.pwiki pwiki.pwiki
// XXX BUG: the second @source(..) includes the current page again
// for some reason....
.update({
location: '/test/macros',
text: object.doc`
some text with inline @source(./path) macros...
<div wikiwords=false>
now @source(./path) inside a div...
</div>` })
.update({
location: '/test/markdown',
text: object.doc`
some text with inline @source(./path) macros...
@filter(markdown)` })
.update({ .update({
location: '/test/sort/*', location: '/test/sort/*',
order: ['a', 'c', 'b'], }) order: ['a', 'c', 'b'], })

View File

@ -1,11 +1,11 @@
/********************************************************************** /**********************************************************************
* *
* *
* XXX BUG: join block gets repeated three times per page... *
* await p.pwiki.get('/test/sort/*').text * XXX BUG: pwiki2-test.js: /test/macros -- broken parser...
* essentially this is the culprit: * XXX BUG?: markdown: when parsing chunks each chunk gets an open/closed
* await p.pwiki.get('/test/sort/*').parse('@source(file-separator)') * <p> inserted at start/end -- this breaks stuff returned by macros...
* XXX BUG: browser: .get('/*').raw hangs in the browser context... * XXX OPTIMIZE: /_tree is really slow...
* XXX might be a good idea to add page caching (state.page_cache) relative * 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 * to a path on parsing, to avoid re-matching the same page over and
* over again from the same context * over again from the same context
@ -17,6 +17,13 @@
* }, * },
* ... * ...
* } * }
* XXX BUG: browser: .get('/*').raw hangs in the browser context...
* XXX BUG?: /_tree for some reason does not show anything on lower levels...
* ...renaming _tree -> all fixed the issue
* ...might be a problem with how rendering templates are handled in
* <page>.text...
* ...if this is not fixable need to document that rendering templates
* are not to be recursive...
* XXX add action to reset overloaded (bootstrap) pages... * XXX add action to reset overloaded (bootstrap) pages...
* - per page * - per page
* - global * - global
@ -32,24 +39,30 @@
* - render page -- DONE * - render page -- DONE
* - navigation -- DONE * - navigation -- DONE
* - hash/anchor -- DONE * - hash/anchor -- DONE
* - action redirects (see: System/delete) -- DONE
* - basic editor and interactivity -- DONE * - basic editor and interactivity -- DONE
* - export * - export
* - json -- DONE * - json -- DONE
* - zip (json/tree) * - zip (json/tree) --
* - migrate bootstrap * - page actions
* - store topology * - delete -- DONE
* - sync and sync conf * - move/rename --
* - migrate bootstrap --
* - store topology --
* - sync and sync conf --
* - markdown -- DONE * - markdown -- DONE
* - WikiWord -- DONE * - WikiWord -- DONE
* - dom filter mechanics -- DONE * - dom filter mechanics -- DONE
* - filters / dom filters: * - filters / dom filters:
* - markdown??
* - wikiword (control) * - wikiword (control)
* this can be done in one of two ways: * this can be done in one of two ways:
* - wrapping blocks in elemens * - wrapping blocks in elemens
* ...requires negative filter calls, either on -wikiword * ...requires negative filter calls, either on -wikiword
* or a different filter like nowikiwords... * or a different filter like nowikiwords...
* - tags (current) * - tags (current)
* - raw / code * - raw / code -- DONE?
* - all (tree) -- DONE
* - nl2br * - nl2br
* - path2link (wikiword?) -- DONE * - path2link (wikiword?) -- DONE
* - editor * - editor