added @(..) as alias to @arg(..) + minor tweaks and fixes...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-08-31 18:49:59 +03:00
parent 819b665a87
commit 323eb39c1b
4 changed files with 67 additions and 65 deletions

View File

@ -618,10 +618,16 @@ object.Constructor('Page', BasePage, {
//
// XXX ASYNC make these support async page getters...
macros: {
//
// @(<name>[ <default>][ local])
// @(name=<name>[ default=<default>][ local])
//
// @arg(<name>[ <default>][ local])
// @arg(name=<name>[ default=<value>][ local])
//
// <arg <name>[ <default>][ local]/>
// <arg name=<name>[ default=<value>][ local]/>
//
arg: Macro(
['name', 'default', ['local']],
function(args){
@ -630,6 +636,11 @@ object.Constructor('Page', BasePage, {
&& this.root
&& this.root.args[args.name])
|| args.default }),
// alias to @arg(..)...
'': Macro(
['name', 'default', ['local']],
function(args){
return this.macros.arg.call(this, args) }),
//
// @filter(<filter-spec>)
// <filter <filter-spec>/>

View File

@ -33,24 +33,20 @@ module.BaseParser = {
// STOP -- '\\>' or ')'
// PREFIX -- 'inline' or 'elem'
//
// XXX quote escaping???
// /(?<quote>['"])(\\\k<quote>|[^\1])*\k<quote>/
// ...this will work but we'll also need to remove the \ in the
// final string...
MACRO_ARGS: ['(\\s*(',[
// arg='val' | arg="val" | arg=val
'(?<PREFIXArgName>[a-z-]+)\\s*=\\s*(?<PREFIXArgValue>'+([
// XXX CHROME/NODE BUG: this does not work yet...
//'\\s+(?<quote>[\'"])[^\\k<quote>]*\\k<quote>',
"'(?<PREFIXSingleQuotedValue>[^']*)'",
'"(?<PREFIXDoubleQuotedValue>[^"]*)"',
'"(?<PREFIXDoubleQuotedValue>(\\"|[^"])*?)"',
"'(?<PREFIXSingleQuotedValue>(\\'|[^'])*?)'",
'(?<PREFIXValue>[^\\sSTOP\'"]+)',
].join('|'))+')',
// "arg" | 'arg'
// XXX CHROME/NODE BUG: this does not work yet...
//'\\s+(?<quote>[\'"])[^\\k<quote>]*\\k<quote>',
'"(?<PREFIXDoubleQuotedArg>[^"]*)"',
"'(?<PREFIXSingleQuotedArg>[^']*)'",
'"(?<PREFIXDoubleQuotedArg>(\\"|[^"])*?)"',
"'(?<PREFIXSingleQuotedArg>(\\'|[^'])*?)'",
// arg
// NOTE: this is last because it could eat up parts of
// the above alternatives...
@ -77,15 +73,15 @@ module.BaseParser = {
//
// needs:
// MACROS
// INLINE_ARGS -- MACRO_ARGS.replace(/STOP/, ')')
// ARGS -- MACRO_ARGS.replace(/STOP/, '\\/>')
// INLINE_ARGS
// UNNAMED_ARGS
// ARGS
//
// XXX BUG: this fails to match inline macros with non-empty args @moo(a)
// ...the problem seems to be with the lack of whitespace
// between ( and the first arg -- @moo( a) is matched fine...
MACRO: '('+([
// @macro(arg ..)
'\\\\?@(?<nameInline>MACROS)\\((?<argsInline>INLINE_ARGS)\\)',
// @(arg ..)
'\\\\?@\\((?<argsUnnamed>UNNAMED_ARGS)\\)',
// <macro ..> | <macro ../>
'<\\s*(?<nameOpen>MACROS)(?<argsOpen>ARGS)?\\s*/?>',
// </macro>
@ -102,9 +98,15 @@ module.BaseParser = {
//
buildMacroPattern: function(macros=['MACROS'], regexp='smig'){
var pattern = this.MACRO
.replace(/MACROS/g, macros.join('|'))
.replace(/MACROS/g,
macros
.filter(function(m){
return m.length > 0 })
.join('|'))
.replace(/INLINE_ARGS/g,
this.buildArgsPattern('inline', ')', false) +'*')
.replace(/UNNAMED_ARGS/g,
this.buildArgsPattern('unnamed', ')', false) +'*')
.replace(/ARGS/g,
this.buildArgsPattern('elem', '\\/>', false) +'*')
return regexp ?
@ -264,30 +266,42 @@ module.BaseParser = {
var args = {}
var i = -1
for(var {groups}
of (cur.argsInline ?? cur.argsOpen ?? '')
of (cur.argsInline
?? cur.argsUnnamed
?? cur.argsOpen
?? '')
.matchAll(macro_args_pattern)){
i++
args[groups.elemArgName
?? groups.inlineArgName
?? groups.unnamedArgName
?? i] =
groups.elemSingleQuotedValue
?? groups.inlineSingleQuotedValue
?? groups.elemDoubleQuotedValue
?? groups.inlineDoubleQuotedValue
?? groups.elemValue
?? groups.inlineValue
?? groups.elemSingleQuotedArg
?? groups.inlineSingleQuotedArg
?? groups.elemDoubleQuotedArg
?? groups.inlineDoubleQuotedArg
?? groups.elemArg
?? groups.inlineArg }
(groups.elemSingleQuotedValue
?? groups.inlineSingleQuotedValue
?? groups.unnamedSingleQuotedValue
?? groups.elemDoubleQuotedValue
?? groups.inlineDoubleQuotedValue
?? groups.unnamedDoubleQuotedValue
?? groups.elemValue
?? groups.inlineValue
?? groups.unnamedValue
?? groups.elemSingleQuotedArg
?? groups.inlineSingleQuotedArg
?? groups.unnamedSingleQuotedArg
?? groups.elemDoubleQuotedArg
?? groups.inlineDoubleQuotedArg
?? groups.unnamedDoubleQuotedArg
?? groups.elemArg
?? groups.inlineArg
?? groups.unnamedArg)
.replace(/\\(["'])/g, '$1') }
// macro-spec...
yield {
name: (cur.nameInline
?? cur.nameOpen
?? cur.nameClose)
?? cur.nameClose
?? '')
.toLowerCase(),
type: match[0] == '@' ?
'inline'

View File

@ -106,7 +106,7 @@ require(['./browser'], function(browser){
// handle location.hash/history (both directions)
window.addEventListener('hashchange', function(evt){
evt.preventDefault()
var [path, hash] = location.hash.slice(1).split('#')
var [path, hash] = decodeURI(location.hash).slice(1).split('#')
path = path.trim() == '' ?
pwiki.location
//'/'
@ -142,7 +142,7 @@ require(['./browser'], function(browser){
// handle refresh...
// NOTE: we need to do this as hashchange is only triggered
// when the hash is actually changed...
for(var lnk of this.dom.querySelectorAll(`a[href="${window.location.hash}"]`)){
for(var lnk of this.dom.querySelectorAll(`a[href="${location.hash}"]`)){
lnk.addEventListener('click', function(evt){
that.refresh() }) } })
@ -150,7 +150,7 @@ require(['./browser'], function(browser){
browser.setup.then(function(){
// show current page...
pwiki.location = location.hash.slice(1)
pwiki.location = decodeURI(location.hash).slice(1)
}) })

View File

@ -1,40 +1,17 @@
/**********************************************************************
*
*
* XXX FEATURE add a uniform way to track some state in links in pwiki
* for things like paging and the like with simple user/macro
* access (???)...
* ...the simplest that comes to mind is to store in in path
* somehow:
* - <path>?<arg>=<value>&...
* traditional "query string"...
* - <path>/<arg>:<valu>/<arg>:<value>/.../<action>
* stack-style arguments...
* + simple to implement
* - goes through page search???
* - <path>:<value>:<name>=<value>:...
* - ...
* the general idea is to be:
* - flexible enough to allow the basics done
* - restrictive enough to prevent misuse
* ...the rest of the state can simply be stored in the root pwiki
* object in one of the following ways:
* - directly (attrs/dict)
* - a special page
* - virtual (path-specific)
* e.g.
* /some/path/@state/page -> 4
* ...might be fun to implement a basic json editor
* and viewer with this api...
* ...controlled via js
* ...or special actions:
* /some/path/@state/page/next (increment)
* /some/path/@state/page/prev (decrement)
* /some/path/@state/page=10 (assign)
* ...
* - session
* - stored (config)
* ...css selector as path....
* XXX FEATURE list macro paging...
* ...should this be macro level or handled in .each()
* what mode?
* - count + block-offset (preferred)
* - count + elem-offset
* - from + to
* XXX what should page caching use?
* - .path (current)
* - .location
* - .path + normalized .args
* ...should this be configurable???
* XXX FEATURE tags and accompanying API...
* - add tags to page -- macro/filter
* <page>.text -> <page>.tags (cached on .update(..))