Comparing version 2.0.0-beta1 to 2.0.0-beta2
var BOOL_ATTR = ('allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,'+ | ||
'defaultchecked,defaultmuted,defaultselected,defer,disabled,draggable,enabled,formnovalidate,hidden,'+ | ||
'indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,'+ | ||
'pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,spellcheck,translate,truespeed,'+ | ||
'typemustmatch,visible').split(',') | ||
module.exports = function(input, opts) { | ||
@@ -47,5 +54,14 @@ | ||
// foo={ bar } --> foo="{ bar }" | ||
html = html.replace(/=(\{[^\}]+\})([\s\>])/g, '="$1"$2') | ||
/* | ||
quoted: value={ expr } --> value="{ expr }" | ||
boolean: checked={ expr } --> __checked={ expr } // IE8 looses boolean expressions | ||
test: <div href="joo{kama}" id="{ key }-page" fo={ bar } ka={ jou } class={ loading: is_loading }> | ||
*/ | ||
html = html.replace(/([\w\-]+)=["']?(\{[^\}]+\})(["'\s\>])/g, function(full, name, expr, end) { | ||
if (BOOL_ATTR.indexOf(name.toLowerCase()) >= 0) name = '__' + name | ||
if (/["']/.test(end)) end = '' | ||
return name + '="' + expr + '"' + end | ||
}) | ||
// escape single quotes | ||
@@ -52,0 +68,0 @@ html = html.replace(/'/g, "\\'") |
riot.tag('todo', '<h3>{ opts.title }</h3> <ul> <li each="{ items }"> <label class="{ completed: done }"> <input type="checkbox" checked="{ done }" onchange="{ parent.toggle }"> { title } </label> </li> </ul> <form onsubmit="{ add }"> <input name="input" oninput="{ edit }"> <button disabled="{ !text }">Add #{ items.length + 1 }</button> </form>', function(opts) { | ||
riot.tag('todo', '<h3>{ opts.title }</h3> <ul> <li each="{ items }"> <label class="{ completed: done }"> <input type="checkbox" __checked="{ done }" onclick="{ parent.toggle }"> { title } </label> </li> </ul> <form onsubmit="{ add }"> <input name="input" onkeyup="{ edit }"> <button __disabled="{ !text }">Add #{ items.length + 1 }</button> </form>', function(opts) { | ||
this.disabled = true | ||
@@ -12,11 +12,14 @@ | ||
this.add = function(e) { | ||
this.items.push({ title: this.text }) | ||
this.text = this.input.value = '' | ||
if (this.text) { | ||
this.items.push({ title: this.text }) | ||
this.text = this.input.value = '' | ||
} | ||
}.bind(this) | ||
this.toggle = function(e) { | ||
var item = e.data | ||
var item = e.item | ||
item.done = !item.done | ||
return true | ||
}.bind(this) | ||
}) |
#!/usr/bin/env node | ||
// For developers of Riot | ||
require('shelljs/global') | ||
@@ -8,2 +10,4 @@ | ||
// watch and build riot.js | ||
gaze('lib/*.js', function() { | ||
@@ -15,2 +19,4 @@ this.on('changed', function() { | ||
// watch and build tags.js for testing | ||
var tags = 'test/tag/*.tag' | ||
@@ -17,0 +23,0 @@ |
@@ -33,3 +33,3 @@ | ||
### el.on(events, callback) | ||
### el.on(events, callback) | #observable-on | ||
@@ -52,3 +52,3 @@ Listen to the given space separated list of `events` and execute the `callback` each time an event is triggered. | ||
### el.one(event, callback) | ||
### el.one(event, callback) | #observable-one | ||
@@ -64,3 +64,3 @@ Listen to the given `event` and execute the `callback` at most once. | ||
### el.off(events) | ||
### el.off(events) | #observable-off | ||
@@ -89,3 +89,3 @@ Removes the given space separated list of event listeners | ||
### el.trigger(event) | ||
### el.trigger(event) | #observable-trigger | ||
@@ -92,0 +92,0 @@ Execute all callback functions that listen to the given `event` |
@@ -13,3 +13,3 @@ | ||
### riot.route(callback) | ||
### riot.route(callback) | #riot-route | ||
@@ -39,3 +39,3 @@ Execute the given `callback` when the URL hash changes. For example | ||
### riot.route(to) | ||
### riot.route(to) | #riot-route-to | ||
@@ -48,3 +48,3 @@ Changes the browser URL and notifies all the listeners assigned with `riot.route(callback)`. For example: | ||
### riot.route.exec() | ||
### riot.route.exec() | #riot-route-exec | ||
@@ -51,0 +51,0 @@ Study the current hash "in place" without waiting for it to change. For example |
@@ -8,3 +8,3 @@ | ||
### riot.mount(selector, [opts]) | ||
### riot.mount(selector, [opts]) | #riot-mount | ||
@@ -35,3 +35,3 @@ Mounts (constructs) all custom tags on the document specified by `selector`. Optional `opts` object is passed to the tags for consumption. Examples: | ||
### riot.mountTo(domNode, tagName, [opts]) | ||
### riot.mountTo(domNode, tagName, [opts]) | #riot-mountto | ||
@@ -76,3 +76,3 @@ Mount a custom tag named `tagName` on a given `domNode` passing optional data with `opts`. For example: | ||
### this.update() | ||
### this.update() | #this-update | ||
@@ -104,3 +104,3 @@ Updates the expressions on the current tag instance. This method is automatically called every time an event handler is called when user interacts with the application. | ||
### this.update(data) | ||
### this.update(data) | #this-update-data | ||
@@ -161,7 +161,6 @@ Set values to the current instance and update the expressions. This is same as `this.update()` but allows you to set context data at the same time. So instead of this: | ||
### riot.tag(tagName, html, [constructor]) | ||
### riot.tag(tagName, html, [constructor]) | #riot-tag | ||
Creates a new custom tag named `tagName` and having `html` as the layout. `constructor` is called before the tag expressions are calculated and before the tag is mounted. The `html` layout can contain [expressions](/riotjs/guide/#expressions). For example: | ||
``` js | ||
@@ -173,15 +172,37 @@ riot.tag('tag-name', '<h3>{ opts.hello }</h3>', function(opts) { | ||
@returns: an array of [tag instances](#tag-instance) | ||
You can take advantage of `template` or `script` tags as follows: | ||
When using Riot [compiler](/riotjs/guide/#compiler) the above function call can be rewritten as | ||
``` | ||
<script type="tmpl" id="my_tmpl"> | ||
<h3>{ opts.hello }</h3> | ||
<p>And a paragraph</p> | ||
</script> | ||
<script> | ||
riot.tag('tag-name', my_tmpl.innerHTML, function(opts) { | ||
}) | ||
</script> | ||
``` | ||
<span class="tag red">Warning</span> When creating tags manually with `riot.tag` you cannot enjoy the advantages of compiler and following features are not supported: | ||
1. Self- closing tags | ||
2. Unquoted expressions. Write `value="{ val }"` instead of `value={ val }` | ||
3. Boolean attributes. Write `__checked="{ flag }"` instead of `checked={ flag }` | ||
4. ES6 method signatures. | ||
With the compiler the above tag definition becomes this: | ||
``` html | ||
<tag-name> | ||
<h3>{ opts.hello }</h3> | ||
<p>And a paragraph</p> | ||
</tag-name> | ||
``` | ||
@returns: an array of [tag instances](#tag-instance) | ||
### riot.update() | ||
### riot.update() | #riot-update | ||
Updates all the tags and their expressions on the page. |
@@ -18,7 +18,6 @@ | ||
``` sh | ||
open demo/index.html | ||
riot --watch demo | ||
riot --watch my/custom.tag | ||
``` | ||
This watches .tag file changes on the demo folder and generates .js files automatically. See [compiler guide](/riotjs/guide/#compiler) or run `riot --help` for more information. | ||
This detects changes on the .tag file and generates a .js files automatically. See [compiler guide](/riotjs/guide/#compiler) or run `riot --help` for more information. | ||
@@ -34,2 +33,3 @@ | ||
git clone git@github.com:muut/riotjs.git | ||
cd riotjs | ||
open demo/index.html | ||
@@ -42,6 +42,4 @@ make watch | ||
## Download | ||
## Direct download | ||
[demo.zip](/riotjs/dist/riot-{{ riot_version }}.zip) - Working demo with unminified version | ||
[riot.min.js](/riotjs/dist/riot-{{ riot_version }}.min.js) – For production. 5.5K minified / 2.5K gzipped | ||
@@ -51,2 +49,7 @@ | ||
[demo.zip](/riotjs/dist/riot-{{ riot_version }}.zip) - Working demo with unminified version | ||
[live demo](/riotjs/dist/demo/) | ||
## IE8 support | ||
@@ -60,3 +63,3 @@ | ||
<!--[if IE 8]> | ||
<!--[if lt IE 9]> | ||
<script src="es5-shim.js"></script> | ||
@@ -69,6 +72,4 @@ <script src="html5-shiv.js"></script> | ||
You can see a working example on the [demo.zip](/riotjs/dist/riot-{{ riot_version }}.zip). IE7 and below are not supported. | ||
You must tell IE8 what custom tags are being used on the page with `html5.addElements`. For example | ||
You also need to tell IE8 what custom tags are being used on the page as follows: | ||
``` html | ||
@@ -80,3 +81,5 @@ <script>html5.addElements('todo todo-item account plan')</script> | ||
See a [live demo](/riotjs/dist/demo/) or download the [demo.zip](/riotjs/dist/riot-{{ riot_version }}.zip). | ||
## Known issues | ||
@@ -87,2 +90,8 @@ | ||
## Media | ||
![](logo/riot60x.png | .no-retina ) | ||
![](logo/riot120x.png | .no-retina ) | ||
![](logo/riot240x.png | .no-retina ) | ||
![](logo/riot480x.png | .no-retina ) | ||
![](logo/riot960x.png | .no-retina ) |
@@ -32,4 +32,10 @@ | ||
### Why the use of evil `==` operator? | ||
The equality operator is good when you know how it works. We do this for example: | ||
`node.nodeValue = value == null ? '' : value` | ||
This causes `0` and `false` to be printed but `null` and `undefined` are printed as an empty string. Exactly what we want! | ||
### Can I use `<style>` tags on a .tag file? | ||
@@ -46,2 +52,10 @@ Yes. You can use CSS normally inside a tag. Web component standard also has a mechanism of encapsulating CSS. However it's unlikely that this improves the overall manageability of your CSS code. | ||
### Any future plans? | ||
Yes: | ||
1. Browser based compilation | ||
2. Server side HTML generation and "isomorphic" applications | ||
3. Bigger test suite with server side tests | ||
4. Tag option validation using HTML attributes | ||
@@ -20,3 +20,3 @@ | ||
<label class={ completed: done }> | ||
<input type="checkbox" checked={ done } onchange={ parent.toggle }> { title } | ||
<input type="checkbox" checked={ done } onclick={ parent.toggle }> { title } | ||
</label> | ||
@@ -27,3 +27,3 @@ </li> | ||
<form onsubmit={ add }> | ||
<input name="input" oninput={ edit }> | ||
<input name="input" onkeyup={ edit }> | ||
<button disabled={ !text }>Add #{ items.length + 1 }</button> | ||
@@ -41,9 +41,12 @@ </form> | ||
add(e) { | ||
this.items.push({ title: this.text }) | ||
this.text = this.input.value = '' | ||
if (this.text) { | ||
this.items.push({ title: this.text }) | ||
this.text = this.input.value = '' | ||
} | ||
} | ||
toggle(e) { | ||
var item = e.data | ||
var item = e.item | ||
item.done = !item.done | ||
return true | ||
} | ||
@@ -70,3 +73,3 @@ | ||
* Nested `<style>` tags are supported, but nested expressions are not evaluated | ||
* Standard HTML tags (`label`, `table`, `a` etc..) can also be customized with Riot tag syntax. | ||
* Standard HTML tags (`label`, `table`, `a` etc..) can also be customized, but not necessarily a wise thing to do. | ||
@@ -230,3 +233,3 @@ | ||
since only attribute- and nested text expressions are valid. | ||
since only attribute- and nested text expressions are valid. Riot detects 44 different boolean attributes. | ||
@@ -342,5 +345,14 @@ | ||
The default event behavior is automatically cancelled with `e.preventDefault()` because this is what you usually want. You can let the browser do the default behavior by returning `true` on the handler (for example: letting a link forward to the specified location). | ||
The default event handler behavior is *automatically cancelled*. This means that `e.preventDefault()` is already called for you, because this is what you usually want (or forget to do). You can let the browser do the default thing by returning `true` on the handler. | ||
For example, this submit handler will actually submit the form to the server: | ||
``` | ||
submit() { | ||
return true | ||
} | ||
``` | ||
### Event object | ||
@@ -353,3 +365,3 @@ | ||
- `e.which` is the key code on a keyboard event (`keypress`, `keyup` etc...) | ||
- `e.data` is the current element on a loop. See [loops](#loops) for more details. | ||
- `e.item` is the current item on th loop. See [loops](#loops) for more details. | ||
@@ -428,3 +440,3 @@ | ||
Event handlers can access individual items on a collection with `event.data`. Now let's implement the `remove` function: | ||
Event handlers can access individual items on a collection with `event.item`. Now let's implement the `remove` function: | ||
@@ -443,3 +455,3 @@ ``` | ||
// looped item | ||
var item = event.data | ||
var item = event.item | ||
@@ -561,20 +573,5 @@ // index on the collection | ||
Of course you can take advantage of `template` or `script` tags as follows: | ||
See [riot.tag](/riotjs/api/#riot-tag) API docs for more details. | ||
``` | ||
<script type="tmpl" id="my_tmpl"> | ||
<h3>{ opts.hello }</h3> | ||
<p>And a paragraph</p> | ||
</script> | ||
<script> | ||
riot.tag('tag-name', my_tmpl.innerHTML, function(opts) { | ||
}) | ||
</script> | ||
``` | ||
# Application architecture | ||
@@ -581,0 +578,0 @@ |
- firefox / safari tests | ||
- IE tests | ||
- check npm stuff | ||
- local /riotjs repository | ||
- merge LD fixes | ||
- /riot20 -> /riotjs | ||
- repository movement | ||
## v1.1 | ||
- cross browser oninput event | ||
- root attr (dynamic, non object) + mountNode attr (overrides) | ||
@@ -12,0 +13,0 @@ - option validation |
;(function(riot, doc) { | ||
var BOOL_ATTR = /^(checked|selected|disabled|readonly|multiple|autofocus|hidden)$/i, | ||
tmpl = riot._tmpl, | ||
var tmpl = riot._tmpl, | ||
all_tags = [], | ||
@@ -11,3 +10,3 @@ tag_impl = {} | ||
for (var i = 0; i < (nodes || []).length; i++) { | ||
fn(nodes[i], i) | ||
if (fn(nodes[i], i) === false) i-- | ||
} | ||
@@ -30,4 +29,3 @@ } | ||
function walk(dom, fn) { | ||
fn(dom) | ||
dom = dom.firstChild | ||
dom = fn(dom) === false ? dom.nextSibling : dom.firstChild | ||
@@ -74,11 +72,14 @@ while (dom) { | ||
if (value == null) value = '' | ||
// no change | ||
if (value && expr.value === value) return | ||
if (expr.value === value) return | ||
expr.value = value | ||
// text node | ||
if (!attr_name) return dom.nodeValue = (value == null ? '' : value) | ||
if (!attr_name) return dom.nodeValue = value | ||
// attribute | ||
if (!value || /obj|func/.test(typeof value)) remAttr(attr_name) | ||
if (!value && expr.bool || /obj|func/.test(typeof value)) remAttr(attr_name) | ||
@@ -93,5 +94,8 @@ // event handler | ||
e.target = e.target || e.srcElement | ||
e.data = instance.__data__ || instance | ||
e.currentTarget = dom | ||
// currently looped item | ||
e.item = instance.__item || instance | ||
// prevent default behaviour (by default) | ||
if (value.call(instance, e) !== true) { | ||
@@ -112,4 +116,8 @@ e.preventDefault && e.preventDefault() | ||
// normal attribute | ||
} else if (value) { | ||
if (BOOL_ATTR.test(attr_name)) value = attr_name | ||
} else { | ||
if (expr.bool) { | ||
if (!value) return | ||
value = attr_name | ||
} | ||
dom.setAttribute(attr_name, value) | ||
@@ -135,3 +143,3 @@ } | ||
function addExpr(value, data) { | ||
if (data || value.indexOf('{') >= 0) { | ||
if (value ? value.indexOf('{') >= 0 : data) { | ||
var expr = { dom: dom, expr: value } | ||
@@ -151,4 +159,8 @@ expressions.push(extend(expr, data || {})) | ||
value = dom.getAttribute('each') | ||
if (value) return addExpr(value, { loop: 1 }) | ||
if (value) { | ||
addExpr(value, { loop: 1 }) | ||
return false | ||
} | ||
// custom tag? | ||
@@ -166,4 +178,12 @@ var tag = tag_impl[dom.tagName.toLowerCase()] | ||
// expressions | ||
if (!tag) addExpr(value, { attr: name }) | ||
if (!tag) { | ||
var bool = name.split('__')[1] | ||
addExpr(value, { attr: bool || name, bool: bool }) | ||
if (bool) { | ||
dom.removeAttribute(name) | ||
return false | ||
} | ||
} | ||
}) | ||
@@ -190,3 +210,3 @@ | ||
ast = parse(dom), | ||
tag = { root: mountNode, opts: opts, parent: parent, __data__: conf.data }, | ||
tag = { root: mountNode, opts: opts, parent: parent, __item: conf.item }, | ||
attributes = {} | ||
@@ -229,3 +249,3 @@ | ||
extend(tag, data) | ||
extend(tag, tag.__data__) | ||
extend(tag, tag.__item) | ||
updateOpts() | ||
@@ -235,3 +255,3 @@ update(ast.expr, tag) | ||
// update parent | ||
!_system && conf.data && parent.update() | ||
!_system && tag.__item && parent.update() | ||
@@ -286,4 +306,7 @@ } else { | ||
instance.one('mount', function() { | ||
root = dom.parentNode | ||
root.removeChild(dom) | ||
var p = dom.parentNode | ||
if (p) { | ||
root = p | ||
root.removeChild(dom) | ||
} | ||
}) | ||
@@ -312,6 +335,6 @@ | ||
items = Object.keys(items).map(function(key, i) { | ||
var data = {} | ||
data[keys[0]] = key | ||
data[keys[1]] = items[key] | ||
return data | ||
var item = {} | ||
item[keys[0]] = key | ||
item[keys[1]] = items[key] | ||
return item | ||
}) | ||
@@ -322,4 +345,4 @@ | ||
// remove redundant | ||
diff(rendered, items).map(function(data) { | ||
var pos = rendered.indexOf(data) | ||
diff(rendered, items).map(function(item) { | ||
var pos = rendered.indexOf(item) | ||
root.removeChild(root.childNodes[startPos() + pos]) | ||
@@ -330,4 +353,4 @@ rendered.splice(pos, 1) | ||
// add new | ||
diff(items, rendered).map(function(data, i) { | ||
var pos = items.indexOf(data) | ||
diff(items, rendered).map(function(item, i) { | ||
var pos = items.indexOf(item) | ||
@@ -337,5 +360,5 @@ // string array | ||
var obj = {} | ||
obj[keys[0]] = data | ||
obj[keys[0]] = item | ||
obj[keys[1]] = i | ||
data = items[i] = obj | ||
item = items[i] = obj | ||
} | ||
@@ -347,3 +370,3 @@ | ||
tmpl: template, | ||
data: data, | ||
item: item, | ||
root: root | ||
@@ -350,0 +373,0 @@ }) |
{ | ||
"name": "riot", | ||
"version": "2.0.0-beta1", | ||
"version": "2.0.0-beta2", | ||
"description": "A React- like, 2.5K user interface library", | ||
@@ -10,8 +10,8 @@ "homepage": "https://muut.com/riotjs/", | ||
"keywords": [ | ||
"MVP", | ||
"MVC", | ||
"framework", | ||
"library", | ||
"riotjs", | ||
"riot.js" | ||
"Custom tags", | ||
"Web components", | ||
"Polymer", | ||
"React", | ||
"Minimal", | ||
"Client-side" | ||
], | ||
@@ -24,11 +24,10 @@ "preferGlobal": true, | ||
"dependencies": { | ||
"gaze": "^0.6.4", | ||
"minimist": "^1.1.0", | ||
"shelljs": "^0.3.0" | ||
"gaze": "~0.6.4", | ||
"minimist": "~1.1.0", | ||
"shelljs": "~0.3.0" | ||
}, | ||
"devDependencies": { | ||
"jshint": "latest", | ||
"uglify-js": "latest", | ||
"jsdom": "latest" | ||
"uglify-js": "latest" | ||
} | ||
} |
## Riot.js: A React- like, 2.5K user interface library | ||
## A React- like, 2.5K user interface library | ||
### Virtual DOM • Custom tags • IE8 • Full stack | ||
### Custom tags • Virtual DOM • Full stack • IE8 • Production ready | ||
Riot brings custom tags to all browsers starting from IE8. Think React + Polymer, but squeezed into 2.5K. | ||
![Riot logo](doc/logo/riot480x.png) | ||
#### Tag definition | ||
@@ -14,5 +17,10 @@ | ||
var timer = setInterval(function() { | ||
if (!self.update({ time: ++opts.time })) clearInterval(timer) | ||
self.update({ time: ++opts.time }) | ||
}, 1000) | ||
this.on('unmount', function() { | ||
clearInterval(timer) | ||
}) | ||
</timer> | ||
@@ -27,4 +35,6 @@ ``` | ||
#### Nested tags | ||
#### Nesting | ||
Custom tags lets you build complex views with HTML. | ||
``` html | ||
@@ -37,1 +47,21 @@ <timetable> | ||
``` | ||
HTML syntax is the de facto language on the web and it's designed for building user interfaces. The syntax is explicit, nesting is inherent to the language and attributes offer a clean way to provide options for custom tags. | ||
### Virtual DOM | ||
- Smallest possible amount of DOM updates and reflows. | ||
- All expressions are pre-compiled cached for high performance. | ||
- No extra HTML root elements or `data-` attributes. | ||
- No event loops or batching. | ||
### Close to standards | ||
- No proprietary event system. | ||
- Event normalization for IE8. | ||
- The rendered DOM can be freely manipulated with other tools. | ||
- Plays well with jQuery. | ||
https://muut.com/riotjs/ | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
160380
2
55
2395
65
1
+ Addedminimist@1.1.3(transitive)
- Removedminimist@1.2.8(transitive)
Updatedgaze@~0.6.4
Updatedminimist@~1.1.0
Updatedshelljs@~0.3.0