Skip to content

Commit

Permalink
refactor: use Pratt's parser for expressions in attributes
Browse files Browse the repository at this point in the history
Closes #288
  • Loading branch information
PK1A committed Sep 17, 2014
1 parent af878ff commit 8aea84a
Show file tree
Hide file tree
Showing 45 changed files with 208 additions and 851 deletions.
4 changes: 2 additions & 2 deletions docs/api/index.md
Expand Up @@ -310,7 +310,7 @@ The right one determines whether the result of the left one should be output or

---

#### CSS expressions `class="{'urgent':msg.urgency, msg.category}"` or compound expressions
#### CSS expressions `class="{msg.category} {{'urgent':msg.urgency}}"` or compound expressions

You can combine several expressions into one expression statement using the comma; note that there is only one pair of braces which is for the compound expression, subexpressions being delimited by commas.

Expand All @@ -319,7 +319,7 @@ The results of the expressions will be concatenated with a single white space be
Because of the space which always gets _inserted between the expressions_, it does not suit all use cases. However, this is perfect to define the `class` attribute of a HTML element for instance.

```cs
<div class="{'urgent':msg.urgency, msg.category}"></div>
<div class="{msg.category} {{'urgent':msg.urgency}}"></div>
```

## Modifiers
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Expand Up @@ -21,7 +21,7 @@ Hashspace turns static HTML pages into dynamic templates with the help of a few
{if tasklist.length > 0}
<ul>
{foreach task in tasklist}
<li class="{'done': task.completed, 'ongoing': !task.completed}">
<li class="{{'done': task.completed, 'ongoing': !task.completed}}">
{task.description}
</li>
{/foreach}
Expand Down
6 changes: 3 additions & 3 deletions docs/playground/layout.hsp
Expand Up @@ -46,7 +46,7 @@ var DescriptionCtrl = Class({
{export template mainLayout(data, playground)}
<#sampleList data="{data}" playground="{playground}"/>

<div class="{'hsp-sample', 'hsp-sample-full': data.navCollapsed}" onclick="{hideNavHover(event, data)}">
<div class="hsp-sample {{'hsp-sample-full': data.navCollapsed}}" onclick="{hideNavHover(event, data)}">
<!--div class="actions">
<a href="" title="Toggle code panel"><span class="icon icon-code icon-active"></span></a>
<a href="" title="Toggle description panel"><span class="icon icon-preview icon-active"></span></a>
Expand Down Expand Up @@ -102,7 +102,7 @@ function hideNavHover(event, data) {
}

{template sampleList(data, playground)}
<div class="{'samples-list', 'samples-list-collapsed': data.navCollapsed}"
<div class="samples-list {{'samples-list-collapsed': data.navCollapsed}}"
onclick="{hideNavHover(event, data)}">

<a href="" class="collapse" title="{data.navCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}" onclick="{collapseNav(event, data, playground)}"><span class="icon"></span></a>
Expand All @@ -120,7 +120,7 @@ function hideNavHover(event, data) {
{if sample.category}
<div class="category">{sample.category}</div>
{else}
<div class="{'item', 'selected': data.sampleIndex === index}">
<div class="item {{'selected': data.sampleIndex === index}}">
<a href="{'#' + sample.folder}">{sample.title}</a>
</div>
{/if}
Expand Down
2 changes: 1 addition & 1 deletion docs/playground/splitter.hsp
Expand Up @@ -75,7 +75,7 @@ var SplitterCtrl = Class({

{template splitter using controller:SplitterCtrl}
<div class="splitter" onmousedown="{controller.onMouseDown(event)}"></div>
<div class="{'splitter-proxy', 'splitter-proxy-hidden': !controller.active}"></div>
<div class="splitter-proxy {{'splitter-proxy-hidden': !controller.active}}"></div>
{/template}

module.exports = splitter;
2 changes: 1 addition & 1 deletion docs/samples/clock/clock.hsp
Expand Up @@ -51,7 +51,7 @@ var ClockController=klass({
// minute markers
{foreach idx,m in c.minuteMarkers}
// {foreach i in [1..60]} should be supported in a future version
<line class="{'major':m.major,'minor':!m.major}" y1="{m.major?35:42}"
<line class="{{'major':m.major,'minor':!m.major}}" y1="{m.major?35:42}"
y2="45" transform="rotate({360*idx/c.minuteMarkers.length})"/>
{/foreach}
// hour hand
Expand Down
2 changes: 1 addition & 1 deletion docs/samples/component2/nbrfield.hsp
Expand Up @@ -73,7 +73,7 @@ function getNumber(s) {
{export template nbrfield using c:NbrField}
<span class="nbrfield">
<input type="text" model="{c.internalValue}"
class="{'nbrfield', 'error': !c.isValid}"/>
class="nbrfield {{'error': !c.isValid}}"/>
<button onclick="{c.resetField()}">reset</button>
</span>
{/template}
Expand Down
6 changes: 3 additions & 3 deletions docs/samples/component3/pagination.hsp
Expand Up @@ -45,15 +45,15 @@ var Pagination=klass({

{template pagination using p:Pagination}
<ul class="pagination">
<li class="{'disabled':p.activepage===0}">
<li class="{{'disabled':p.activepage===0}}">
<a href="javascript:void(0)" onclick="{p.selectPage(p.activepage-1)}">Previous</a>
</li>
{foreach page in p.pages}
<li class="{'active':page==p.activepage}">
<li class="{{'active':page==p.activepage}}">
<a href="javascript:void(0)" onclick="{p.selectPage(page)}">{page + 1}</a>
</li>
{/foreach}
<li class="{'disabled':p.activepage>=p.noOfPages-1}">
<li class="{{'disabled':p.activepage>=p.noOfPages-1}}">
<a href="javascript:void(0)" onclick="{p.selectPage(p.activepage+1)}">Next</a>
</li>
</ul>
Expand Down
4 changes: 2 additions & 2 deletions docs/samples/cssclass/cssclass.hsp
Expand Up @@ -4,11 +4,11 @@
<a href="javascript:void(0)" onclick="{toggleUrgency()}">Change Urgency</a> -
<a href="javascript:void(0)" onclick="{setCategory('personal')}">Set "Personal"</a> -
<a href="javascript:void(0)" onclick="{setCategory('professional')}">Set "Professional"</a>
<div class="{'msg', 'urgent':msg.urgency, msg.category}">
<div class="msg {msg.category} {{'urgent':msg.urgency}}">
Message: {msg.text}
</div>
<div class="note">
Class value: "{'msg', 'urgent':msg.urgency, msg.category}"
Class value: "msg {msg.category} {msg.urgency ? 'urgent' : ''}"
</div>
</div>
{/template}
Expand Down
19 changes: 10 additions & 9 deletions docs/samples/cssclass/description.md
Expand Up @@ -3,12 +3,13 @@ This sample shows a special type of expression that is particularly convenient f

[#output]

As you can see in the example, this expression is structured as a comma-separated list of sub-expressions that can have the following forms:

+ either a **Hashspace expression** - a subset of the JavaScript expression syntax, such as
- a string - e.g. *"urgent"* - in this case this will be considered as a mandatory class element
- a path resolving to a string - e.g. *msg.category* to use dynamic class elements
- a more complex expression - e.g. *'type'+msg.urgency* to build a more dynamic class element
+ or a **pair of Hashspace expressions** separated by a colon - e.g. *'urgent' : msg.urgency===1*
- the first expression will be resolved as the class element that should be inserted (e.g. *'urgent'*)
- whereas the second expression should resolve to a boolean to tell if the class element should be inserted or not (e.g. *msg.urgency===1*)
As you can see in the example, you can combine static values and expressions inside the "class" attribute.
If an expression is used it can evaluate to either:

+ a string - e.g. *msg.category* - in this case it will be interpreted as class names to add
+ an object - e.g. *{'urgent' : msg.urgency===1}*
- each key in an object is interpreted as a class name that should be inserted (e.g. *'urgent'*)
- whereas the expression in the value part should resolve to a boolean to tell if the class element should be
inserted or not (e.g. *msg.urgency===1*)

You can use more complex expression - e.g. *'type'+msg.urgency* to build a more dynamic class element.
2 changes: 1 addition & 1 deletion docs/samples/list2/list.hsp
Expand Up @@ -49,7 +49,7 @@ var ListCtrl = klass({
{foreach idx,itm in lc.content}
{if itm.tagName==="@option"}
<li class="opt" onclick="{lc.select(itm.value)}">
<span class="{'item','highlight':itm.selected}"><#itm.label/></span>
<span class="item {{'highlight':itm.selected}}"><#itm.label/></span>
</li>
{else if itm.tagName==="@separator" && !itm_isfirst && !itm_islast}
<hr/>
Expand Down
2 changes: 1 addition & 1 deletion docs/samples/simplelist/simplelist.hsp
Expand Up @@ -2,7 +2,7 @@
<div class="msg">Click on a person to see more details:</div>
<ul class="noTextSelection">
{foreach p in d.people}
<li class="{'details':p.showdetails, 'special':p.name==='Bart'}"
<li class="{{'details':p.showdetails, 'special':p.name==='Bart'}}"
onclick="{toggleDetails(p)}">
{p.name}
{if p.showdetails}: {p.age} years old{/if}
Expand Down
2 changes: 1 addition & 1 deletion hsp/compiler/parser/hspblocks.pegjs
Expand Up @@ -209,7 +209,7 @@ HTMLAttribute
}

HTMLAttributeValue
= (HTMLAttributeText / ExpressionBlock)*
= (HTMLAttributeText / ExpressionTextBlock)*

HTMLAttributeText
= chars:HTMLAttributeChar+
Expand Down

0 comments on commit 8aea84a

Please sign in to comment.