mirror of
https://github.com/flynx/pWiki.git
synced 2026-10-03 04:41:39 +00:00
Compare commits
5 Commits
0acb5a223a
...
85cf87813b
| Author | SHA1 | Date | |
|---|---|---|---|
| 85cf87813b | |||
| b879049346 | |||
| acf37a4832 | |||
| 84880015f7 | |||
| 70e44f5a6f |
@ -7,6 +7,8 @@ Any macro can be used in any of the two forms, either _inline_ or _HTML-like_.
|
|||||||
Inline:
|
Inline:
|
||||||
```
|
```
|
||||||
@macro-name(value)
|
@macro-name(value)
|
||||||
|
|
||||||
|
@macro-name(value text=" ...text... ")
|
||||||
```
|
```
|
||||||
|
|
||||||
HTML-style:
|
HTML-style:
|
||||||
@ -27,6 +29,54 @@ The two forms exist to fill two distinct functions:
|
|||||||
- html-like: element-like, simpler when dealing with html
|
- html-like: element-like, simpler when dealing with html
|
||||||
|
|
||||||
|
|
||||||
|
### Positional and keyword attributes
|
||||||
|
|
||||||
|
Attributes (arguments) can be set sequentially by value, as they are
|
||||||
|
defined or by name in any order.
|
||||||
|
|
||||||
|
The following are equivalent:
|
||||||
|
```
|
||||||
|
<slot abc "some text"/>
|
||||||
|
<slot name=abc text="some text"/>
|
||||||
|
<slot "some text" name=abc/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Keyword attributes are special attributes that are given by name rather
|
||||||
|
than by value by default and if no value is set explicitly it defaults
|
||||||
|
to `true` if passed, and to false if omitted.
|
||||||
|
|
||||||
|
The following are equivalent:
|
||||||
|
```
|
||||||
|
<slot some-name hidden/>
|
||||||
|
<slot some-name hidden=true/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Special attributes
|
||||||
|
|
||||||
|
Two special attributes are handled differently: `text` and `body`, these
|
||||||
|
are equivalent, the two names exist to make the semantics of macros simpler.
|
||||||
|
|
||||||
|
If both attributes are defined `body` takes precedence over `text` and
|
||||||
|
both are overriden by a non-empty body, e.g. the following:
|
||||||
|
```
|
||||||
|
<slot slot text=text-attr body=body-attr>body</slot>
|
||||||
|
```
|
||||||
|
will resolve to `body`.
|
||||||
|
|
||||||
|
The main difference from normal attributes is that the value of these is
|
||||||
|
parsed in the same way as the element's body is. Thus, the following are
|
||||||
|
identical:
|
||||||
|
```
|
||||||
|
<macro-name text="body text"/>
|
||||||
|
|
||||||
|
<macro-name body="body text"/>
|
||||||
|
|
||||||
|
<macro-name>body text</macro-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
The values are parsed lazily, i.e. only the final value is parsed, the
|
||||||
|
overridden values are ignored.
|
||||||
|
|
||||||
|
|
||||||
### Escaping macros
|
### Escaping macros
|
||||||
|
|
||||||
@ -82,10 +132,15 @@ This will enable writing documents (mainly in _markdown_) that are usable
|
|||||||
bot from within pWiki as well as outside.
|
bot from within pWiki as well as outside.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Macros
|
## Macros
|
||||||
|
|
||||||
### now ()
|
### now ()
|
||||||
|
|
||||||
|
```
|
||||||
|
\@now()
|
||||||
|
```
|
||||||
|
|
||||||
Get current date in seconds since epoch, this is equivalet Javascript's
|
Get current date in seconds since epoch, this is equivalet Javascript's
|
||||||
`Date.now()`.
|
`Date.now()`.
|
||||||
|
|
||||||
@ -96,17 +151,87 @@ the date once per page load, i.e. the date changes on page load, while
|
|||||||
`$NOW` is set every time the path is used, i.e. on every click or script
|
`$NOW` is set every time the path is used, i.e. on every click or script
|
||||||
use.
|
use.
|
||||||
|
|
||||||
**Example:**
|
|
||||||
```
|
|
||||||
\@now()
|
|
||||||
```
|
|
||||||
|
|
||||||
<pwiki-comment>Will produce: `1471389217848`</pwiki-comment>
|
<pwiki-comment>Will produce: `1471389217848`</pwiki-comment>
|
||||||
|
|
||||||
<!--[pWiki[ Will produce: `@now()` ]]-->
|
<!--[pWiki[ Will produce: `@now()` ]]-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### slot (<name> <text> shown|hidden) / content
|
||||||
|
|
||||||
|
```
|
||||||
|
@slot(<name>)
|
||||||
|
@slot(<name> <text>)
|
||||||
|
@slot(<name> <text> hidden)
|
||||||
|
@slot(<name> <text> shown)
|
||||||
|
|
||||||
|
<slot <name> ...>
|
||||||
|
...
|
||||||
|
<content/>
|
||||||
|
...
|
||||||
|
</slot>
|
||||||
|
```
|
||||||
|
|
||||||
|
Define or fill a slot.
|
||||||
|
|
||||||
|
First occurrence of a slot `name` will _define_ a slot and set its value
|
||||||
|
(fill it) with `text` if given.
|
||||||
|
Each new occurrence of a slot with the same name will override slot content.
|
||||||
|
|
||||||
|
Only the first occurance of the `name` slot macro is displayed by default.
|
||||||
|
|
||||||
|
Slot display can be explicitly controlled via the `hidden` and `shown`
|
||||||
|
keywords, if both are given `hidden` has precedence. All _shown_ slots of
|
||||||
|
the same name will display the same value.
|
||||||
|
|
||||||
|
Nested slots are processed in order of occurrence, i.e. a nested slot can
|
||||||
|
override it's parent's value.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```
|
||||||
|
<slot X>
|
||||||
|
some text
|
||||||
|
<slot X "new text"/>
|
||||||
|
</slot>
|
||||||
|
```
|
||||||
|
Will resolve to: `new text`
|
||||||
|
|
||||||
|
`<content/>` / `@content()` if encountered will be replaced with previous
|
||||||
|
slot value.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```
|
||||||
|
This is: <slot X text="some text"/>
|
||||||
|
|
||||||
|
<slot X>[[ <content/> ]]</slot>
|
||||||
|
```
|
||||||
|
Will resolve to `This is: [[ some text ]]`
|
||||||
|
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
<pwiki-comment>
|
||||||
|
- [bootstrap view](/bootstrap/Templates/_view.html)
|
||||||
|
- [bootstrap edit](/bootstrap/Templates/_edit.html)
|
||||||
|
</pwiki-comment>
|
||||||
|
|
||||||
|
<!--[pWiki[
|
||||||
|
[Templates/\_view] / [bootstrap view](bootstrap/Templates/_view.html):
|
||||||
|
```
|
||||||
|
@source(Templates/_view)
|
||||||
|
```
|
||||||
|
|
||||||
|
[Templates/\_edit] / [bootstrap edit](bootstrap/Templates/_edit.html):
|
||||||
|
```
|
||||||
|
@source(Templates/_edit)
|
||||||
|
```
|
||||||
|
]]-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### filter (name)
|
### filter (name)
|
||||||
|
|
||||||
Enable or disable a page filter.
|
Enable or disable a page filter.
|
||||||
@ -181,33 +306,6 @@ Arguments:
|
|||||||
]]-->
|
]]-->
|
||||||
|
|
||||||
|
|
||||||
### slot (name text)
|
|
||||||
|
|
||||||
Define or fill a slot.
|
|
||||||
|
|
||||||
First occurrence of a `name` will _define_ a slot and fill it with `text`.
|
|
||||||
Each new occurrence of a name will change slot content.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
<pwiki-comment>
|
|
||||||
- [bootstrap view](/bootstrap/Templates/_view.html)
|
|
||||||
- [bootstrap edit](/bootstrap/Templates/_edit.html)
|
|
||||||
</pwiki-comment>
|
|
||||||
|
|
||||||
<!--[pWiki[
|
|
||||||
[Templates/\_view] / [bootstrap view](bootstrap/Templates/_view.html):
|
|
||||||
```
|
|
||||||
@source(Templates/_view)
|
|
||||||
```
|
|
||||||
|
|
||||||
[Templates/\_edit] / [bootstrap edit](bootstrap/Templates/_edit.html):
|
|
||||||
```
|
|
||||||
@source(Templates/_edit)
|
|
||||||
```
|
|
||||||
]]-->
|
|
||||||
|
|
||||||
|
|
||||||
### macro (name src sort) / else ()
|
### macro (name src sort) / else ()
|
||||||
|
|
||||||
Apply macro to source page and include the result.
|
Apply macro to source page and include the result.
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
var object = require('ig-object')
|
var object = require('ig-object')
|
||||||
var types = require('ig-types')
|
var types = require('ig-types')
|
||||||
|
var serialize = require('ig-serialize')
|
||||||
|
|
||||||
var pwpath = require('./path')
|
var pwpath = require('./path')
|
||||||
|
|
||||||
@ -219,19 +220,34 @@ module.BaseParser = {
|
|||||||
(res[e] = true)
|
(res[e] = true)
|
||||||
: (res[order.shift()] = e) })
|
: (res[order.shift()] = e) })
|
||||||
return res },
|
return res },
|
||||||
|
// NOTE: this unifies the body, body argument and text argument (in
|
||||||
|
// order of priority) and passes the value in the body macro
|
||||||
|
// handler argument.
|
||||||
callMacro: function(page, macro, args, body, state, ...rest){
|
callMacro: function(page, macro, args, body, state, ...rest){
|
||||||
do {
|
do {
|
||||||
macro = this.macros[macro]
|
macro = this.macros[macro]
|
||||||
} while(typeof(macro) == 'string')
|
} while(typeof(macro) == 'string')
|
||||||
|
var args =
|
||||||
|
this.parseArgs(
|
||||||
|
macro.arg_spec
|
||||||
|
?? [],
|
||||||
|
args)
|
||||||
|
body = body == '' ?
|
||||||
|
undefined
|
||||||
|
: body
|
||||||
|
if(args.body
|
||||||
|
|| args.text
|
||||||
|
|| body){
|
||||||
|
body =
|
||||||
|
args.body =
|
||||||
|
args.text =
|
||||||
|
body
|
||||||
|
?? args.body
|
||||||
|
?? args.text }
|
||||||
return macro.call(page,
|
return macro.call(page,
|
||||||
this,
|
this,
|
||||||
this.parseArgs(
|
args,
|
||||||
macro.arg_spec
|
body,
|
||||||
?? [],
|
|
||||||
args),
|
|
||||||
// XXX
|
|
||||||
body
|
|
||||||
?? args.body,
|
|
||||||
state,
|
state,
|
||||||
...rest) },
|
...rest) },
|
||||||
|
|
||||||
@ -342,10 +358,6 @@ module.BaseParser = {
|
|||||||
?? groups.unnamedArg)
|
?? groups.unnamedArg)
|
||||||
.replace(/\\(["'])/g, '$1') }
|
.replace(/\\(["'])/g, '$1') }
|
||||||
|
|
||||||
// special case: .body arg -> lex...
|
|
||||||
if(args.body){
|
|
||||||
args.body = [...this.lex(page, args.body)] }
|
|
||||||
|
|
||||||
// macro-spec...
|
// macro-spec...
|
||||||
yield {
|
yield {
|
||||||
name: (cur.nameInline
|
name: (cur.nameInline
|
||||||
@ -393,12 +405,18 @@ module.BaseParser = {
|
|||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// Special arguments:
|
||||||
|
// .args.body | .args.text
|
||||||
|
// - if .body is given both arges are ignored and dropped
|
||||||
|
// - if .body is empty and one of the args is present it's
|
||||||
|
// content will be set as .body and grouped while the rest
|
||||||
|
// is dropped
|
||||||
|
// - priority order:
|
||||||
|
// .body -> .args.body -> .args.text
|
||||||
|
//
|
||||||
// NOTE: this internaly uses .macros to check for propper nesting
|
// NOTE: this internaly uses .macros to check for propper nesting
|
||||||
//group: function*(page, lex, to=false){
|
//group: function*(page, lex, to=false){
|
||||||
group: function*(page, lex, to=false, parent, context){
|
group: function*(page, lex, to=false, parent, context){
|
||||||
// XXX we can't get .raw from the page without going async...
|
|
||||||
//lex = lex
|
|
||||||
// ?? this.lex(page)
|
|
||||||
lex = typeof(lex) != 'object' ?
|
lex = typeof(lex) != 'object' ?
|
||||||
this.lex(page, lex)
|
this.lex(page, lex)
|
||||||
: lex
|
: lex
|
||||||
@ -432,16 +450,6 @@ module.BaseParser = {
|
|||||||
: value.match ) }
|
: value.match ) }
|
||||||
continue }
|
continue }
|
||||||
|
|
||||||
// special case: .body argument -> group...
|
|
||||||
if((value.args ?? {}).body){
|
|
||||||
value.args.body =
|
|
||||||
[...this.group(
|
|
||||||
page,
|
|
||||||
value.args.body.iter(),
|
|
||||||
false,
|
|
||||||
parent,
|
|
||||||
value.name)] }
|
|
||||||
|
|
||||||
// assert nesting rules...
|
// assert nesting rules...
|
||||||
// NOTE: we only check for direct nesting...
|
// NOTE: we only check for direct nesting...
|
||||||
// XXX might be a good idea to link nested block to the parent...
|
// XXX might be a good idea to link nested block to the parent...
|
||||||
@ -459,17 +467,37 @@ module.BaseParser = {
|
|||||||
+(to ?
|
+(to ?
|
||||||
' in <'+to+'>'
|
' in <'+to+'>'
|
||||||
: '')) }
|
: '')) }
|
||||||
|
|
||||||
// open block...
|
// open block...
|
||||||
if(value.type == 'opening'){
|
if(value.type == 'opening'){
|
||||||
//value.body = [...this.group(page, lex, value.name)]
|
//value.body = [...this.group(page, lex, value.name)]
|
||||||
value.body = [...this.group(page, lex, value.name, value)]
|
value.body = [...this.group(page, lex, value.name, value)]
|
||||||
value.type = 'block'
|
value.type = 'block'
|
||||||
|
|
||||||
|
// unify .body, .args.body and .args.text into .body...
|
||||||
|
// (first non-empty takes precedance, the rest are removed)
|
||||||
|
if(value.body.length == 0
|
||||||
|
&& (value.args.body
|
||||||
|
?? value.args.text)){
|
||||||
|
value.body =
|
||||||
|
[...this.group(
|
||||||
|
page,
|
||||||
|
value.args.body
|
||||||
|
?? value.args.text,
|
||||||
|
false,
|
||||||
|
parent,
|
||||||
|
value.name)] }
|
||||||
|
delete value.args.body
|
||||||
|
delete value.args.text
|
||||||
|
|
||||||
// close block...
|
// close block...
|
||||||
} else if(value.type == 'closing'){
|
} else if(value.type == 'closing'){
|
||||||
if(value.name != to){
|
if(value.name != to){
|
||||||
throw new Error('Unexpected </'+ value.name +'>') }
|
throw new Error('Unexpected </'+ value.name +'>') }
|
||||||
// NOTE: we are intentionally not yielding the value here...
|
// NOTE: we are intentionally not yielding the value here...
|
||||||
|
// ...this supports the above scan use-case.
|
||||||
return }
|
return }
|
||||||
|
|
||||||
// normal value...
|
// normal value...
|
||||||
yield value } },
|
yield value } },
|
||||||
|
|
||||||
@ -567,14 +595,21 @@ module.BaseParser = {
|
|||||||
// do not re-expand expanded elements...
|
// do not re-expand expanded elements...
|
||||||
if('value' in elem
|
if('value' in elem
|
||||||
&& !state.forceReExpand){
|
&& !state.forceReExpand){
|
||||||
elems.push({...elem})
|
elems.push(serialize.partialDeepCopy(elem))
|
||||||
continue }
|
continue }
|
||||||
|
|
||||||
|
// cleanup...
|
||||||
|
//elem = {...elem}
|
||||||
|
elem = serialize.partialDeepCopy(elem)
|
||||||
|
delete elem.error
|
||||||
|
delete elem.value
|
||||||
|
//delete elem.resolving
|
||||||
|
|
||||||
var {name, args, body} = elem
|
var {name, args, body} = elem
|
||||||
|
|
||||||
// nested macro -- skip...
|
// nested macro -- skip...
|
||||||
if(that.macros[name] instanceof Array){
|
if(that.macros[name] instanceof Array){
|
||||||
elems.push({...elem})
|
elems.push(elem)
|
||||||
continue }
|
continue }
|
||||||
// drop non-macros/aliases...
|
// drop non-macros/aliases...
|
||||||
if(typeof(that.macros[name]) != 'function'
|
if(typeof(that.macros[name]) != 'function'
|
||||||
@ -583,15 +618,8 @@ module.BaseParser = {
|
|||||||
|
|
||||||
// expand down...
|
// expand down...
|
||||||
body
|
body
|
||||||
|
&& !that.macros[name].lazy
|
||||||
&& (body = this.expand(page, body, state))
|
&& (body = this.expand(page, body, state))
|
||||||
;(args ?? {}).body
|
|
||||||
&& (args.body = this.expand(page, args.body, state))
|
|
||||||
|
|
||||||
// cleanup...
|
|
||||||
elem = {...elem}
|
|
||||||
delete elem.error
|
|
||||||
delete elem.value
|
|
||||||
//delete elem.resolving
|
|
||||||
|
|
||||||
// call macro...
|
// call macro...
|
||||||
var res = that.callMacro(page, name, args, body, state)
|
var res = that.callMacro(page, name, args, body, state)
|
||||||
@ -990,6 +1018,7 @@ module.BaseParser = {
|
|||||||
|
|
||||||
// XXX do we need anything else like .doc, attrs???
|
// XXX do we need anything else like .doc, attrs???
|
||||||
// XXX might be a good idea to offload arg value parsing to here...
|
// XXX might be a good idea to offload arg value parsing to here...
|
||||||
|
// XXX should macros be lazy by default???
|
||||||
var Macro =
|
var Macro =
|
||||||
module.Macro =
|
module.Macro =
|
||||||
function(spec, func){
|
function(spec, func){
|
||||||
@ -1005,9 +1034,15 @@ function(spec, func){
|
|||||||
|
|
||||||
var isolated =
|
var isolated =
|
||||||
module.isolated =
|
module.isolated =
|
||||||
function(func){
|
function(macro){
|
||||||
func.isolated = true
|
macro.isolated = true
|
||||||
return func }
|
return macro }
|
||||||
|
|
||||||
|
var lazy =
|
||||||
|
module.lazy =
|
||||||
|
function(macro){
|
||||||
|
macro.lazy = true
|
||||||
|
return macro }
|
||||||
|
|
||||||
|
|
||||||
// XXX RENAME...
|
// XXX RENAME...
|
||||||
@ -1274,32 +1309,41 @@ module.parser = {
|
|||||||
// ...
|
// ...
|
||||||
// </slot>
|
// </slot>
|
||||||
//
|
//
|
||||||
|
// Wrap previous value of slot
|
||||||
|
// <slot name=<name>>
|
||||||
|
// ...
|
||||||
|
// <content/>
|
||||||
|
// ...
|
||||||
|
// </slot>
|
||||||
|
//
|
||||||
// Force show a slot...
|
// Force show a slot...
|
||||||
// <slot shown ... />
|
// <slot shown ... />
|
||||||
//
|
//
|
||||||
// Force hide a slot...
|
// Force hide a slot...
|
||||||
// <slot hidden ... />
|
// <slot hidden ... />
|
||||||
//
|
//
|
||||||
// Insert previous slot content...
|
// NOTE: slots are expanded in order of occurance not in order
|
||||||
// <content/>
|
// of topology, thus nested can override slots they are
|
||||||
//
|
// nested in, e.g.:
|
||||||
//
|
// '<slot moo>[[ <slot moo "new value"> ]]</slot>'
|
||||||
|
// will resolve to:
|
||||||
|
// 'new value'
|
||||||
// NOTE: by default only the first slot with <name> is visible,
|
// NOTE: by default only the first slot with <name> is visible,
|
||||||
// all other slots with <name> will replace its content, unless
|
// all other slots with <name> will replace its content, unless
|
||||||
// explicit shown/hidden arguments are given.
|
// explicit shown/hidden arguments are given.
|
||||||
// NOTE: hidden has precedence over shown if both are given.
|
// NOTE: hidden has precedence over shown if both are given.
|
||||||
// XXX revise...
|
|
||||||
//
|
//
|
||||||
|
// XXX can there be a situation where not all <content/> elements
|
||||||
|
// are cleared???
|
||||||
// XXX revise the use of hidden/shown use mechanic and if it's
|
// XXX revise the use of hidden/shown use mechanic and if it's
|
||||||
// needed...
|
// needed...
|
||||||
// XXX do we need to guard from recursion???
|
|
||||||
// ...do not think it's possible -- everything is resolved
|
|
||||||
// once and just inseerted as-is (revise)
|
|
||||||
slot: Macro(
|
slot: Macro(
|
||||||
['name', 'text', ['shown', 'hidden']],
|
['name', 'text', ['shown', 'hidden']],
|
||||||
|
// NOTE: this is needed to be able to control the sequence of
|
||||||
|
// overrides in nesteed slots...
|
||||||
|
lazy(
|
||||||
function(parser, args, body, state){
|
function(parser, args, body, state){
|
||||||
var name = args.name
|
var name = args.name
|
||||||
var text = args.text
|
|
||||||
|
|
||||||
return Promise.awaitOrRun(
|
return Promise.awaitOrRun(
|
||||||
parser.parseNested(this, name, state),
|
parser.parseNested(this, name, state),
|
||||||
@ -1307,7 +1351,6 @@ module.parser = {
|
|||||||
var slots = state.slots ??= {}
|
var slots = state.slots ??= {}
|
||||||
|
|
||||||
//var hidden = name in slots
|
//var hidden = name in slots
|
||||||
// XXX EXPERIMENTAL
|
|
||||||
var hidden =
|
var hidden =
|
||||||
// 'hidden' has priority...
|
// 'hidden' has priority...
|
||||||
args.hidden
|
args.hidden
|
||||||
@ -1318,22 +1361,44 @@ module.parser = {
|
|||||||
: name in slots)
|
: name in slots)
|
||||||
|
|
||||||
// set slot value...
|
// set slot value...
|
||||||
text = text ?
|
//
|
||||||
parser.expand(this, text ?? [], state)
|
var slot = slots[name] ??= []
|
||||||
: text
|
// NOTE: the placeholder is a stand-in for our
|
||||||
if(body && text){
|
// current value that is still to be generated...
|
||||||
var slot = text
|
var placeholder = [...slot]
|
||||||
} else {
|
slot.splice(0, slot.length, placeholder)
|
||||||
var slot = body ?? text }
|
// expand body...
|
||||||
slots[name] = slot
|
body = body ?
|
||||||
|
parser.expand(this, body ?? [], state)
|
||||||
|
: body
|
||||||
|
// if slot not overriden, write our value...
|
||||||
|
if(slot[0] === placeholder){
|
||||||
|
slot.splice(0, slot.length,
|
||||||
|
...(body != null ?
|
||||||
|
[body]
|
||||||
|
: placeholder))
|
||||||
|
// placeholder -> <content/>
|
||||||
|
body = placeholder }
|
||||||
|
// <content/> -- handle slot's original value...
|
||||||
|
slot[0] =
|
||||||
|
body.flat().length > 0
|
||||||
|
&& slot[0] instanceof Array ?
|
||||||
|
slot[0]
|
||||||
|
.map(function(e){
|
||||||
|
if(e && e.name == 'content'){
|
||||||
|
return body }
|
||||||
|
return e })
|
||||||
|
: slot[0]
|
||||||
|
|
||||||
return hidden ?
|
return hidden ?
|
||||||
''
|
''
|
||||||
: Object.assign(
|
: Object.assign(
|
||||||
|
// stage II: place the latest slot value...
|
||||||
function(st){
|
function(st){
|
||||||
return ((st ?? state).slots ?? {})[name]
|
return ((st ?? state).slots ?? {})[name] },
|
||||||
?? slot },
|
{slot: name}) }) })),
|
||||||
{slot: name}) }) }),
|
// XXX do not like this name...
|
||||||
|
content: ['slot'],
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1432,9 +1497,14 @@ module.parser = {
|
|||||||
handler.call(that,
|
handler.call(that,
|
||||||
parser,
|
parser,
|
||||||
text,
|
text,
|
||||||
args.isolated ?
|
// isolated up -- will see all
|
||||||
// XXX clean (now), partial or derp-copy?
|
// the state but can have no
|
||||||
{}
|
// side-effects...
|
||||||
|
args.isolated == 'partial' ?
|
||||||
|
serialize.partialDeepCopy(state)
|
||||||
|
// fully isolated...
|
||||||
|
: args.isolated ?
|
||||||
|
{}
|
||||||
: state),
|
: state),
|
||||||
// join...
|
// join...
|
||||||
(args.join
|
(args.join
|
||||||
|
|||||||
@ -56,14 +56,7 @@ test.Setups({
|
|||||||
...ins.map(function(e){
|
...ins.map(function(e){
|
||||||
return e + '<slot slot>third</slot>' }),
|
return e + '<slot slot>third</slot>' }),
|
||||||
'third' ]} },
|
'third' ]} },
|
||||||
/* XXX not sure how...
|
// nested...
|
||||||
slot_recursion: function(assert){
|
|
||||||
return {code: [
|
|
||||||
'<slot slot> <slot slot.inner/> </slot> <slot slot.inner "@slot"/>',
|
|
||||||
'', ]} },
|
|
||||||
//*/
|
|
||||||
|
|
||||||
// XXX these are an alternative to <content/>...
|
|
||||||
slot_nested: function(assert){
|
slot_nested: function(assert){
|
||||||
return {code: [
|
return {code: [
|
||||||
'<slot slot>[[ <slot slot.content/> ]]</slot>@slot(slot.content value)',
|
'<slot slot>[[ <slot slot.content/> ]]</slot>@slot(slot.content value)',
|
||||||
@ -72,12 +65,42 @@ test.Setups({
|
|||||||
return {code: [
|
return {code: [
|
||||||
'<slot slot>[[ <slot slot.content/> ]]</slot>@slot(slot value)',
|
'<slot slot>[[ <slot slot.content/> ]]</slot>@slot(slot value)',
|
||||||
'value' ]} },
|
'value' ]} },
|
||||||
|
// nested-self...
|
||||||
// XXX should this work???
|
|
||||||
slot_nested_nested: function(assert){
|
slot_nested_nested: function(assert){
|
||||||
return {code: [
|
return {code: [
|
||||||
'<slot slot>[[ <slot slot value/> ]]</slot>',
|
'<slot slot>[[ <slot slot value/> ]]</slot>',
|
||||||
|
'<slot slot shown>[[ <slot slot value/> ]]</slot>',
|
||||||
'value' ]} },
|
'value' ]} },
|
||||||
|
slot_nested_shown_nested: function(assert){
|
||||||
|
return {code: [
|
||||||
|
'<slot slot>[[ <slot slot/> ]]</slot>',
|
||||||
|
'[[ ]]' ]} },
|
||||||
|
// slot content...
|
||||||
|
slot_content: function(assert){
|
||||||
|
return {code: [
|
||||||
|
'<slot slot>[[ <content/> ]]</slot>',
|
||||||
|
'[[ ]]' ]} },
|
||||||
|
slot_content_multi: function(assert){
|
||||||
|
return {code: [
|
||||||
|
'<slot slot "moo"/><slot slot>[[ <content/> <content/> <content/> ]]</slot>',
|
||||||
|
'[[ moo moo moo ]]' ]} },
|
||||||
|
slot_content_filled: function(assert){
|
||||||
|
var ins = this.slot_content(assert).code.slice(0, -1)
|
||||||
|
return {code: [
|
||||||
|
...ins.map(function(e){
|
||||||
|
return '<slot slot "content"/>' + e }),
|
||||||
|
'[[ content ]]' ]} },
|
||||||
|
slot_content_content_filled: function(assert){
|
||||||
|
var ins = this.slot_content_filled(assert).code
|
||||||
|
var res = ins.pop()
|
||||||
|
return {code: [
|
||||||
|
...ins.map(function(e){
|
||||||
|
return e +'<slot slot>(( <content/> ))</slot>' }),
|
||||||
|
'(( '+ res +' ))' ]} },
|
||||||
|
slot_content_nested: function(assert){
|
||||||
|
return {code: [
|
||||||
|
'<slot slot>moo<slot slot>[[ <content/> ]]</slot></slot>',
|
||||||
|
'[[ moo ]]' ]} },
|
||||||
|
|
||||||
/* XXX SHOWN_HIDDEN
|
/* XXX SHOWN_HIDDEN
|
||||||
// XXX these need to be revised...
|
// XXX these need to be revised...
|
||||||
@ -127,6 +150,24 @@ test.Modifiers({
|
|||||||
string: 'string',
|
string: 'string',
|
||||||
}
|
}
|
||||||
return state },
|
return state },
|
||||||
|
slot: function(assert, state){
|
||||||
|
state.code = [
|
||||||
|
...state.code
|
||||||
|
.slice(0, -1)
|
||||||
|
.map(function(e){
|
||||||
|
return `[[ <slot parent>${e}</slot> ]]` }),
|
||||||
|
`[[ ${state.code.at(-1)} ]]`,
|
||||||
|
]
|
||||||
|
return state },
|
||||||
|
slot_expand: function(assert, state){
|
||||||
|
state.code = [
|
||||||
|
...state.code
|
||||||
|
.slice(0, -1)
|
||||||
|
.map(function(e){
|
||||||
|
return `[[ <slot parent/> ]]<slot parent>${e}</slot>` }),
|
||||||
|
`[[ ${state.code.at(-1)} ]]`,
|
||||||
|
]
|
||||||
|
return state },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user