Remove m.prop + m.withAttr (#2317)
* Remove `m.prop` + `m.withAttr` - For many uses, `m.withAttr` is *more* verbose than just directly using an event handler - If you're using it with a bound callback, you're literally wasting a single character in the human readable version (and you're *saving* them in the minified output). - It sometimes obscures your intent, if overused. - Functions are easier to compress than `m.withAttr`, resulting in slightly smaller bundles. - `m.withAttr` is overused anyways. - `m.prop` is basically useless without `m.withAttr`, and the API doesn't have the same benefits it had with 0.2.x. * Update changelog
This commit is contained in:
parent
86c16820f7
commit
26b8d994ce
18 changed files with 28 additions and 445 deletions
42
docs/api.md
42
docs/api.md
|
|
@ -121,48 +121,6 @@ var querystring = m.buildQueryString({a: "1", b: "2"})
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### m.withAttr(attrName, callback) - [docs](withAttr.md)
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var state = {
|
|
||||||
value: "",
|
|
||||||
setValue: function(v) {state.value = v}
|
|
||||||
}
|
|
||||||
|
|
||||||
var Component = {
|
|
||||||
view: function() {
|
|
||||||
return m("input", {
|
|
||||||
oninput: m.withAttr("value", state.setValue),
|
|
||||||
value: state.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mount(document.body, Component)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### m.prop(initial) - [docs](prop.md)
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var Component = {
|
|
||||||
oninit: function(vnode) {
|
|
||||||
vnode.state.current = m.prop("")
|
|
||||||
},
|
|
||||||
view: function(vnode) {
|
|
||||||
return m("input", {
|
|
||||||
oninput: function(ev) { vnode.state.current.set(ev.target.value) },
|
|
||||||
value: vnode.state.current.get(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mount(document.body, Component)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### m.trust(htmlString) - [docs](trust.md)
|
#### m.trust(htmlString) - [docs](trust.md)
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
- render: simplify component removal ([#2214](https://github.com/MithrilJS/mithril.js/pull/2214))
|
- render: simplify component removal ([#2214](https://github.com/MithrilJS/mithril.js/pull/2214))
|
||||||
- cast className using toString ([#2309](https://github.com/MithrilJS/mithril.js/pull/2309))
|
- cast className using toString ([#2309](https://github.com/MithrilJS/mithril.js/pull/2309))
|
||||||
- render: call attrs' hooks first, with express exception of `onbeforeupdate` to allow attrs to block components from even diffing ([#2297](https://github.com/MithrilJS/mithril.js/pull/2297))
|
- render: call attrs' hooks first, with express exception of `onbeforeupdate` to allow attrs to block components from even diffing ([#2297](https://github.com/MithrilJS/mithril.js/pull/2297))
|
||||||
|
- API: `m.withAttr` removed. ([#2317](https://github.com/MithrilJS/mithril.js/pull/2317))
|
||||||
|
|
||||||
#### News
|
#### News
|
||||||
|
|
||||||
|
|
@ -47,7 +48,6 @@
|
||||||
- API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097))
|
- API: add support for raw SVG in `m.trust()` string ([#2097](https://github.com/MithrilJS/mithril.js/pull/2097))
|
||||||
- render/core: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122))
|
- render/core: remove the DOM nodes recycling pool ([#2122](https://github.com/MithrilJS/mithril.js/pull/2122))
|
||||||
- render/core: revamp the core diff engine, and introduce a longest-increasing-subsequence-based logic to minimize DOM operations when re-ordering keyed nodes.
|
- render/core: revamp the core diff engine, and introduce a longest-increasing-subsequence-based logic to minimize DOM operations when re-ordering keyed nodes.
|
||||||
- API: Introduction of `m.prop()` ([#2268](https://github.com/MithrilJS/mithril.js/pull/2268))
|
|
||||||
- docs: Emphasize Closure Components for stateful components, use them for all stateful component examples.
|
- docs: Emphasize Closure Components for stateful components, use them for all stateful component examples.
|
||||||
- stream: Add `stream.lift` as a user-friendly alternative to `merge -> map` or `combine` [#1944](https://github.com/MithrilJS/mithril.js/issues/1944)
|
- stream: Add `stream.lift` as a user-friendly alternative to `merge -> map` or `combine` [#1944](https://github.com/MithrilJS/mithril.js/issues/1944)
|
||||||
- API: ES module bundles are now available for `mithril` and `mithril/stream` ([#2194](https://github.com/MithrilJS/mithril.js/pull/2194) [@porsager](https://github.com/porsager)).
|
- API: ES module bundles are now available for `mithril` and `mithril/stream` ([#2194](https://github.com/MithrilJS/mithril.js/pull/2194) [@porsager](https://github.com/porsager)).
|
||||||
|
|
|
||||||
|
|
@ -365,8 +365,14 @@ var Login = {
|
||||||
login: function() {/*...*/},
|
login: function() {/*...*/},
|
||||||
view: function() {
|
view: function() {
|
||||||
return m(".login", [
|
return m(".login", [
|
||||||
m("input[type=text]", {oninput: m.withAttr("value", this.setUsername.bind(this)), value: this.username}),
|
m("input[type=text]", {
|
||||||
m("input[type=password]", {oninput: m.withAttr("value", this.setPassword.bind(this)), value: this.password}),
|
oninput: function (e) { this.setUsername(e.target.value) },
|
||||||
|
value: this.username,
|
||||||
|
}),
|
||||||
|
m("input[type=password]", {
|
||||||
|
oninput: function (e) { this.setPassword(e.target.value) },
|
||||||
|
value: this.password,
|
||||||
|
}),
|
||||||
m("button", {disabled: !this.canSubmit(), onclick: this.login}, "Login"),
|
m("button", {disabled: !this.canSubmit(), onclick: this.login}, "Login"),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
@ -411,11 +417,11 @@ var Login = {
|
||||||
view: function() {
|
view: function() {
|
||||||
return m(".login", [
|
return m(".login", [
|
||||||
m("input[type=text]", {
|
m("input[type=text]", {
|
||||||
oninput: m.withAttr("value", Auth.setUsername),
|
oninput: function (e) { Auth.setUsername(e.target.value) },
|
||||||
value: Auth.username
|
value: Auth.username
|
||||||
}),
|
}),
|
||||||
m("input[type=password]", {
|
m("input[type=password]", {
|
||||||
oninput: m.withAttr("value", Auth.setPassword),
|
oninput: function (e) { Auth.setPassword(e.target.value) },
|
||||||
value: Auth.password
|
value: Auth.password
|
||||||
}),
|
}),
|
||||||
m("button", {
|
m("button", {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@
|
||||||
- [m.jsonp](jsonp.md)
|
- [m.jsonp](jsonp.md)
|
||||||
- [m.parseQueryString](parseQueryString.md)
|
- [m.parseQueryString](parseQueryString.md)
|
||||||
- [m.buildQueryString](buildQueryString.md)
|
- [m.buildQueryString](buildQueryString.md)
|
||||||
- [m.withAttr](withAttr.md)
|
|
||||||
- [m.prop](prop.md)
|
|
||||||
- [m.trust](trust.md)
|
- [m.trust](trust.md)
|
||||||
- [m.fragment](fragment.md)
|
- [m.fragment](fragment.md)
|
||||||
- [m.redraw](redraw.md)
|
- [m.redraw](redraw.md)
|
||||||
|
|
|
||||||
152
docs/prop.md
152
docs/prop.md
|
|
@ -1,152 +0,0 @@
|
||||||
# prop(attrName, callback)
|
|
||||||
|
|
||||||
- [Description](#description)
|
|
||||||
- [Signature](#signature)
|
|
||||||
- [How it works](#how-it-works)
|
|
||||||
- [Sending through requests](#sending-through-requests)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Description
|
|
||||||
|
|
||||||
Returns a simple getter/setter object.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var name = m.prop("John")
|
|
||||||
|
|
||||||
var oldName = name.get() // First, it's set to "John"
|
|
||||||
name.set("Mary") // Set the value to "Mary"
|
|
||||||
var newName = name.get() // Now it's "Mary", not "John"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Signature
|
|
||||||
|
|
||||||
`prop = m.prop(initial?)`
|
|
||||||
|
|
||||||
Argument | Type | Required | Description
|
|
||||||
----------- | ------ | -------- | ---
|
|
||||||
`initial` | `any` | No | The prop's initial value
|
|
||||||
**returns** | `Prop` | | A prop
|
|
||||||
|
|
||||||
`value = prop.get()`
|
|
||||||
|
|
||||||
Argument | Type | Required | Description
|
|
||||||
----------- | ----- | -------- | ---
|
|
||||||
**returns** | `any` | | The prop's current value
|
|
||||||
|
|
||||||
`newValue = prop.set(newValue)`
|
|
||||||
|
|
||||||
Argument | Type | Required | Description
|
|
||||||
----------- | ----- | -------- | ---
|
|
||||||
`newValue` | `any` | Yes | The value to set the prop to
|
|
||||||
**returns** | `any` | | The value you just set the prop to, for convenience
|
|
||||||
|
|
||||||
[How to read signatures](signatures.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### How it works
|
|
||||||
|
|
||||||
The `m.prop` method creates a prop, a getter/setter object wrapping a single mutable reference. You can get the current value with `prop.get()` and set it with `prop.set(value)`. Unlike [streams](stream.md), you can't observe them, so you can't do as much with them.
|
|
||||||
|
|
||||||
In conjunction with [`m.withAttr`](withAttr.md), you can emulate two-way binding pretty easily.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
function Component() {
|
|
||||||
var current = m.prop("")
|
|
||||||
return {
|
|
||||||
view: function(vnode) {
|
|
||||||
return m("input", {
|
|
||||||
oninput: m.withAttr("value", current.set),
|
|
||||||
value: current.get(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
They're also useful for making simpler models.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// With props
|
|
||||||
var Auth = {
|
|
||||||
username: m.prop(""),
|
|
||||||
password: m.prop(""),
|
|
||||||
canSubmit: function() {
|
|
||||||
return Auth.username.get() !== "" && Auth.password.get() !== ""
|
|
||||||
},
|
|
||||||
login: function() {
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Without props
|
|
||||||
var Auth = {
|
|
||||||
username: "",
|
|
||||||
password: "",
|
|
||||||
setUsername: function(value) {
|
|
||||||
Auth.username = value
|
|
||||||
}
|
|
||||||
setPassword: function(value) {
|
|
||||||
Auth.password = value
|
|
||||||
}
|
|
||||||
canSubmit: function() {
|
|
||||||
return Auth.username !== "" && Auth.password !== ""
|
|
||||||
},
|
|
||||||
login: function() {
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Sending through requests
|
|
||||||
|
|
||||||
For convenience, props define `.toJSON` as an alias for `.get`. This is so you can send them through `m.request` without serializing them manually.
|
|
||||||
|
|
||||||
We could also take this model and simplify it:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// How it's loaded
|
|
||||||
User.load = function(id) {
|
|
||||||
return m.request({
|
|
||||||
method: "GET",
|
|
||||||
url: "https://rem-rest-api.herokuapp.com/api/users/" + id,
|
|
||||||
withCredentials: true,
|
|
||||||
})
|
|
||||||
.then(function(result) {
|
|
||||||
User.current = {
|
|
||||||
id: result.id,
|
|
||||||
firstName: m.prop(result.firstName),
|
|
||||||
lastName: m.prop(result.lastName),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Original
|
|
||||||
User.save = function(user) {
|
|
||||||
return m.request({
|
|
||||||
method: "PUT",
|
|
||||||
url: "https://rem-rest-api.herokuapp.com/api/users/" + user.id,
|
|
||||||
data: {
|
|
||||||
id: user.id,
|
|
||||||
firstName: user.firstName.get(),
|
|
||||||
lastName: user.lastName.get(),
|
|
||||||
},
|
|
||||||
withCredentials: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simplified
|
|
||||||
User.save = function(user) {
|
|
||||||
return m.request({
|
|
||||||
method: "PUT",
|
|
||||||
url: "https://rem-rest-api.herokuapp.com/api/users/" + user.id,
|
|
||||||
data: user,
|
|
||||||
withCredentials: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -383,7 +383,10 @@ var Form = {
|
||||||
},
|
},
|
||||||
view: function() {
|
view: function() {
|
||||||
return m("form", [
|
return m("form", [
|
||||||
m("input[placeholder='Search']", {oninput: m.withAttr("value", function(v) {state.term = v}), value: state.term}),
|
m("input[placeholder='Search']", {
|
||||||
|
oninput: function (e) { state.term = e.target.value },
|
||||||
|
value: state.term
|
||||||
|
}),
|
||||||
m("button", {onclick: state.search}, "Search")
|
m("button", {onclick: state.search}, "Search")
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
@ -589,8 +592,14 @@ var Auth = {
|
||||||
var Login = {
|
var Login = {
|
||||||
view: function() {
|
view: function() {
|
||||||
return m("form", [
|
return m("form", [
|
||||||
m("input[type=text]", {oninput: m.withAttr("value", Auth.setUsername), value: Auth.username}),
|
m("input[type=text]", {
|
||||||
m("input[type=password]", {oninput: m.withAttr("value", Auth.setPassword), value: Auth.password}),
|
oninput: function (e) { Auth.setUsername(e.target.value) },
|
||||||
|
value: Auth.username
|
||||||
|
}),
|
||||||
|
m("input[type=password]", {
|
||||||
|
oninput: function (e) { Auth.setPassword(e.target.value) },
|
||||||
|
value: Auth.password
|
||||||
|
}),
|
||||||
m("button[type=button]", {onclick: Auth.login}, "Login")
|
m("button[type=button]", {onclick: Auth.login}, "Login")
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -471,12 +471,12 @@ module.exports = {
|
||||||
}, [
|
}, [
|
||||||
m("label.label", "First name"),
|
m("label.label", "First name"),
|
||||||
m("input.input[type=text][placeholder=First name]", {
|
m("input.input[type=text][placeholder=First name]", {
|
||||||
oninput: m.withAttr("value", function(value) {User.current.firstName = value}),
|
oninput: function (e) {User.current.firstName = e.target.value},
|
||||||
value: User.current.firstName
|
value: User.current.firstName
|
||||||
}),
|
}),
|
||||||
m("label.label", "Last name"),
|
m("label.label", "Last name"),
|
||||||
m("input.input[placeholder=Last name]", {
|
m("input.input[placeholder=Last name]", {
|
||||||
oninput: m.withAttr("value", function(value) {User.current.lastName = value}),
|
oninput: function (e) {User.current.lastName = e.target.value},
|
||||||
value: User.current.lastName
|
value: User.current.lastName
|
||||||
}),
|
}),
|
||||||
m("button.button[type=submit]", "Save"),
|
m("button.button[type=submit]", "Save"),
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,7 @@ In the example above, the `users` stream is populated with the response data whe
|
||||||
|
|
||||||
#### Bidirectional bindings
|
#### Bidirectional bindings
|
||||||
|
|
||||||
Streams can also be populated from other higher order functions, such as [`m.withAttr`](withAttr.md)
|
Streams can also be populated from event callbacks and similar.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// a stream
|
// a stream
|
||||||
|
|
@ -314,7 +314,7 @@ var user = stream("")
|
||||||
|
|
||||||
// a bi-directional binding to the stream
|
// a bi-directional binding to the stream
|
||||||
m("input", {
|
m("input", {
|
||||||
oninput: m.withAttr("value", user),
|
oninput: function (e) { user(e.target.value) },
|
||||||
value: user()
|
value: user()
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
|
||||||
136
docs/withAttr.md
136
docs/withAttr.md
|
|
@ -1,136 +0,0 @@
|
||||||
# withAttr(attrName, callback)
|
|
||||||
|
|
||||||
- [Description](#description)
|
|
||||||
- [Signature](#signature)
|
|
||||||
- [How it works](#how-it-works)
|
|
||||||
- [Predictable event target](#predictable-event-target)
|
|
||||||
- [Attributes and properties](#attributes-and-properties)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Description
|
|
||||||
|
|
||||||
Returns an event handler that runs `callback` with the value of the specified DOM attribute
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var state = {
|
|
||||||
value: "",
|
|
||||||
setValue: function(v) {state.value = v}
|
|
||||||
}
|
|
||||||
|
|
||||||
var Component = {
|
|
||||||
view: function() {
|
|
||||||
return m("input", {
|
|
||||||
oninput: m.withAttr("value", state.setValue),
|
|
||||||
value: state.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mount(document.body, Component)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Signature
|
|
||||||
|
|
||||||
`m.withAttr(attrName, callback, thisArg?)`
|
|
||||||
|
|
||||||
Argument | Type | Required | Description
|
|
||||||
----------- | -------------------- | -------- | ---
|
|
||||||
`attrName` | `String` | Yes | The name of the attribute or property whose value will be used
|
|
||||||
`callback` | `any -> undefined` | Yes | The callback
|
|
||||||
`thisArg` | `any` | No | An object to bind to the `this` keyword in the callback function
|
|
||||||
**returns** | `Event -> undefined` | | An event handler function
|
|
||||||
|
|
||||||
[How to read signatures](signatures.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### How it works
|
|
||||||
|
|
||||||
The `m.withAttr` method creates an event handler. The event handler takes the value of a DOM element's property and calls a function with it as the argument.
|
|
||||||
|
|
||||||
This helper function is provided to help decouple the browser's event model from application code.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// standalone usage
|
|
||||||
document.body.onclick = m.withAttr("title", function(value) {
|
|
||||||
console.log(value) // logs the title of the <body> element when clicked
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Typically, `m.withAttr()` can be used in Mithril component views to avoid polluting the data layer with DOM event model concerns:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var state = {
|
|
||||||
email: "",
|
|
||||||
setEmail: function(email) {
|
|
||||||
state.email = email.toLowerCase()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var MyComponent = {
|
|
||||||
view: function() {
|
|
||||||
return m("input", {
|
|
||||||
oninput: m.withAttr("value", state.setEmail),
|
|
||||||
value: state.email
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mount(document.body, MyComponent)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Predictable event target
|
|
||||||
|
|
||||||
The `m.withAttr()` helper reads the value of the element to which the event handler is bound, which is not necessarily the same as the element where the event originated.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var state = {
|
|
||||||
url: "",
|
|
||||||
setURL: function(url) {state.url = url}
|
|
||||||
}
|
|
||||||
|
|
||||||
var MyComponent = {
|
|
||||||
view: function() {
|
|
||||||
return m("a[href='/foo']", {onclick: m.withAttr("href", state.setURL)}, [
|
|
||||||
m("span", state.url)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mount(document.body, MyComponent)
|
|
||||||
```
|
|
||||||
|
|
||||||
In the example above, if the user clicks on the text within the link, `e.target` will point to the `<span>`, not the `<a>`.
|
|
||||||
|
|
||||||
While this behavior works as per its specs, it's not very intuitive or useful most of the time. Therefore, `m.withAttr` uses the value of `e.currentTarget` which does point to the `<a>`, as one would normally expect.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Attributes and properties
|
|
||||||
|
|
||||||
The first argument of `m.withAttr()` can be either an attribute or a property.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// reads from `select.selectedIndex` property
|
|
||||||
var state = {
|
|
||||||
index: 0,
|
|
||||||
setIndex: function(index) {state.index = index}
|
|
||||||
}
|
|
||||||
m("select", {onclick: m.withAttr("selectedIndex", state.setIndex)})
|
|
||||||
```
|
|
||||||
|
|
||||||
If a value can be both an attribute *and* a property, the property value is used.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// value is a boolean, because the `input.checked` property is boolean
|
|
||||||
var state = {
|
|
||||||
selected: false,
|
|
||||||
setSelected: function(selected) {state.selected = selected}
|
|
||||||
}
|
|
||||||
m("input[type=checkbox]", {onclick: m.withAttr("checked", state.setSelected)})
|
|
||||||
```
|
|
||||||
1
esm.js
1
esm.js
|
|
@ -19,7 +19,6 @@ var namedExports = [
|
||||||
"fragment",
|
"fragment",
|
||||||
"mount",
|
"mount",
|
||||||
"route",
|
"route",
|
||||||
"withAttr",
|
|
||||||
"render",
|
"render",
|
||||||
"redraw",
|
"redraw",
|
||||||
"request",
|
"request",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ var Editor = {
|
||||||
view: function() {
|
view: function() {
|
||||||
return [
|
return [
|
||||||
m("textarea.input", {
|
m("textarea.input", {
|
||||||
oninput: m.withAttr("value", state.update),
|
oninput: function (e) { state.update(e.traget.value) },
|
||||||
value: state.text
|
value: state.text
|
||||||
}),
|
}),
|
||||||
m(".preview", m.trust(marked(state.text))),
|
m(".preview", m.trust(marked(state.text))),
|
||||||
|
|
|
||||||
2
index.js
2
index.js
|
|
@ -13,8 +13,6 @@ requestService.setCompletionCallback(redrawService.redraw)
|
||||||
|
|
||||||
m.mount = require("./mount")
|
m.mount = require("./mount")
|
||||||
m.route = require("./route")
|
m.route = require("./route")
|
||||||
m.withAttr = require("./util/withAttr")
|
|
||||||
m.prop = require("./util/prop")
|
|
||||||
m.render = require("./render").render
|
m.render = require("./render").render
|
||||||
m.redraw = redrawService.redraw
|
m.redraw = redrawService.redraw
|
||||||
m.request = requestService.request
|
m.request = requestService.request
|
||||||
|
|
|
||||||
|
|
@ -45,16 +45,6 @@ o.spec("api", function() {
|
||||||
o(vnode.children[0].tag).equals("div")
|
o(vnode.children[0].tag).equals("div")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
o.spec("m.withAttr", function() {
|
|
||||||
o("works", function() {
|
|
||||||
var spy = o.spy()
|
|
||||||
var handler = m.withAttr("value", spy)
|
|
||||||
|
|
||||||
handler({currentTarget: {value: 10}})
|
|
||||||
|
|
||||||
o(spy.args[0]).equals(10)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
o.spec("m.parseQueryString", function() {
|
o.spec("m.parseQueryString", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var query = m.parseQueryString("?a=1&b=2")
|
var query = m.parseQueryString("?a=1&b=2")
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
"use strict"
|
|
||||||
|
|
||||||
module.exports = function (store) {
|
|
||||||
return {
|
|
||||||
get: function() { return store },
|
|
||||||
toJSON: function() { return store },
|
|
||||||
set: function(value) { return store = value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="../../module/module.js"></script>
|
|
||||||
<script src="../../ospec/ospec.js"></script>
|
|
||||||
|
|
||||||
<script src="../../util/withAttr.js"></script>
|
|
||||||
<script src="../../util/prop.js"></script>
|
|
||||||
<script src="test-withAttr.js"></script>
|
|
||||||
<script src="test-prop.js"></script>
|
|
||||||
|
|
||||||
<script>require("../../ospec/ospec").run()</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
"use strict"
|
|
||||||
|
|
||||||
var o = require("../../ospec/ospec")
|
|
||||||
var prop = require("../../util/prop")
|
|
||||||
|
|
||||||
o.spec("prop", function() {
|
|
||||||
o("works", function() {
|
|
||||||
var p = prop(1)
|
|
||||||
|
|
||||||
o(p.get()).equals(1)
|
|
||||||
o(p.toJSON()).equals(1)
|
|
||||||
o(p.set(2)).equals(2)
|
|
||||||
o(p.get()).equals(2)
|
|
||||||
o(p.toJSON()).equals(2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
"use strict"
|
|
||||||
|
|
||||||
var o = require("../../ospec/ospec")
|
|
||||||
var withAttr = require("../../util/withAttr")
|
|
||||||
|
|
||||||
o.spec("withAttr", function() {
|
|
||||||
o("works", function() {
|
|
||||||
var spy = o.spy()
|
|
||||||
var context = {
|
|
||||||
handler: withAttr("value", spy)
|
|
||||||
}
|
|
||||||
context.handler({currentTarget: {value: 1}})
|
|
||||||
|
|
||||||
o(spy.args).deepEquals([1])
|
|
||||||
o(spy.this).equals(context)
|
|
||||||
})
|
|
||||||
o("works with attribute", function() {
|
|
||||||
var target = {
|
|
||||||
getAttribute: function() {return "readonly"}
|
|
||||||
}
|
|
||||||
var spy = o.spy()
|
|
||||||
var context = {
|
|
||||||
handler: withAttr("readonly", spy)
|
|
||||||
}
|
|
||||||
context.handler({currentTarget: target})
|
|
||||||
|
|
||||||
o(spy.args).deepEquals(["readonly"])
|
|
||||||
o(spy.this).equals(context)
|
|
||||||
})
|
|
||||||
o("context arg works", function() {
|
|
||||||
var spy = o.spy()
|
|
||||||
var context = {}
|
|
||||||
var handler = withAttr("value", spy, context)
|
|
||||||
handler({currentTarget: {value: 1}})
|
|
||||||
|
|
||||||
o(spy.this).equals(context)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
"use strict"
|
|
||||||
|
|
||||||
module.exports = function(attrName, callback, context) {
|
|
||||||
return function(e) {
|
|
||||||
callback.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue