-
Notifications
You must be signed in to change notification settings - Fork 0
client dom
Use this module to define HTML layouts in a reactive manner: every element automatically creates a new observer scope (see obs.observe
), re-rendering the subtree whenever a change occurs in an observed value. This is the only way to create DOM layouts, access to functions such as document.createElement
is prohibited.
Dom = require 'dom'
Obs = require 'obs'
{tr} = require 'i18n'
counter = Obs.value(0)
Dom.div !->
Dom.text tr("the counter is at %1", counter())
Dom.style {background: 'red'}
Dom.prop 'tabindex', 3
Dom.onTap !->
(counter counter()+1)
Take a look at the obs
module for more observable examples and semantics.
The dom
module is never supposed to "leak" native HTMLNode
or Event
objects to its users, because it would allow plugins to effectively break out of their sandboxing environment (for instance, they could follow parent nodes outside the plugin container). HTML nodes and events returned by the API are therefor always wrapped by NodeWrapper
and EventWrapper
prototypes, respectively. Read more about the sandbox.
Where htmlTag
is a valid HTML5 tag such as div
, span
, input
, etc.
Creates new element and append to the current scope. content
should be a function. It is run every time the element needs to be re-rendered. It can define properties, event handlers, text content or sub-elements.
Returns nothing, use the get()
or last()
functions to get a (wrapped) reference to the element.
Example:
Dom.section !->
Dom = require 'dom'
Dom.h3 "A lovely title"
Dom.p "Some text as to demonstrate things"
Dom.div !->
Dom.style
background: "#555"
color: "#FFF"
Dom.span "Just send a function to rescope and make children"
Dom.small "small children"
Create a HTML text node and append in the current scope.
Example:
Dom = require 'dom'
Dom.section !->
Dom.text "Adding plain text."
Dom.text "This does not add a line break."
Dom.text "And neither does this: \n."
Dom.text "Mind you that the <b> text is escaped </b> so HTML tags <br> come out as <span>strings</span>."
Similar to text(text)
, but it also accepts functions.
Example:
Dom = require 'dom'
Dom.section !->
Dom.content "Random Avenger: "
Dom.content ->
a = ["Iron Man", "Captain America", "Hulk", "Thor", "Black Widow", "Hawkeye"]
a[Math.floor(Math.random() * a.length)]
This has roughly the same functionality as text(text)
, but the content is parsed to add a few more features.
- \n is replaced with a functioning
<br>
, so you can add newlines. - Asterisk can be used emphasize text.
- Double asterisk can be used to make text strong.
- Urls are formatted and functional
Because of this, it is useful as output for user inputted messages.
Example:
Dom = require 'dom'
Dom.section !->
Dom.userText "For one, you can add \n newlines."
Dom.userText "*italic* text, **bold** it, or ***both*** \n"
Dom.userText "urls: www.xkcd.com are formatted.\n"
Dom.userText "emoji are supported: \u23f3"
options
is an object that can disable these features.
Per default, they are all enabled.
options = {
br = false, #disable line breaks
rich = false, #disable bold and italic styling
urls = false, #disable URL formatting
emoji = false, #disable emoji parsing.
}
Short for userText(text, {urls:false,br:false})
Short for userText(text, {urls:false})
Convert HTML to a (series of) node(s) and append in the current scope.
Register event callback in the current scope. Cleaned up when the scope is torn down.
Exposed observable hash with properties height
and width
that indicate viewport size. Although page.width and page.height are more convenient.
Returns a NodeWrapper
instance of currently in-scope element.
Example:
Dom = require 'dom'
Obs = require 'obs'
out = Obs.create("empty")
Dom.section !->
Dom.text out.get()
Dom.input !->
inputE = Dom.get()
Dom.on 'change', !->
out.set(inputE.value())
Returns a NodeWrapper
instance of the last-created element.
Example:
Dom = require 'dom'
Ui = require 'ui'
Dom.section !->
Dom.div !->
Dom.h2 "An element"
el = Dom.last() # gets the h2 element
Ui.button "Click me", !->
el.setText "This element is happening"
Add dedicated css. Similar to the usage of separate <style></style> tags. Like Dom.style, it accepts an hash which should be a javascript object with camelcased css properties as keys. Prefix a key with _
to add vendor-prefix before the css property. Postfix a key with _
to add a vendor-prefix before the css value. The usual pattern is to apply this to the current element using the Dom.style
shortcut:
Example:
Dom = require 'dom'
Dom.section !->
Dom.style
height: "2em"
Dom.div !->
Dom.text "Somebody to..."
Dom.span !->
Dom.addClass 'right'
Dom.text "Love"
Dom.css
'.right':
marginTop: "1em"
float: 'right'
Subscribes given function to an event associated to the current scoped element.
Example:
Dom = require 'dom'
Dom.section !->
Dom.input !->
inputE = Dom.get()
Dom.on 'change', !->
Modal.show "Text changed to " + inputE.value()
Makes an object interactive.
For a simple clickable:
Dom = require 'dom'
Dom.section !->
Dom.div !->
Dom.style
color: require('plugin').colors().highlight
Dom.text "Press me"
Dom.onTap !->
Modal.show "I'm tapped!"
Similar to window.requestAnimationFrame. Only you don't get the parameter send to the callback to describe the progress. It returns an animationFrame ID.
Example:
Dom = require 'dom'
UI = require 'ui'
i = 0
el = null
req = null
frame = (timestamp) !->
i++
el.setText "count " + (i%240)
req = Dom.animationFrame frame
Dom.section !->
Dom.div !->
Dom.text "count " + 1
el = Dom.last()
Ui.button 'Stop', !->
Dom.cancelAnimationFrame req
req = Dom.animationFrame frame
Like window.cancelAnimationFrame(id), this stoppes an animation. Example is above at animationFrame (func)
Returns the context. Used for drawing on a canvas:
Example:
Dom = require 'dom'
Dom.canvas !->
ctx = Dom.getContext '2d'
ctx.fillStyle = '#f0f'
ctx.fillRect(20,20,60,60);
Sets the overflow property to 'overlay'
An abstraction for touch and mouse events. In the cases where 'onTap()' is not enough.
You provide Dom.trackTouch with an callback function which receives an array of touches. In addition, you also need to provide a wrapped element from which the event is based.
AS parameter it will receive an object for each touch (multi-touch supportive). Each is an object with the following members:
- x : translated pixels from touch start
- y : translated pixels from touch start
- xc: translated pixels from origin of element
- yc: translated pixels from origin of element
- xo: start pixels from origin of element (doesn't change while dragging)
- yo: start pixels from origin of element (doesn't change while dragging)
- start: timestamp of the start of the thouch
- id: touch index?
- op: touch state, to be read as multiple flags in a byte, not as an integer:
-
touch.op&1
checks for the "touch start" state -
touch.op&2
checks for the "touch move" state -
touch.op&4
checks for the "touch end" state The return value of the callback function determines if the default touch behavior should be suppressed or not. Return eithertrue
orfalse
-
Draggable box example:
Dom = require 'dom'
exports.render = !->
element = null
Dom.div !->
Dom.style
width: '100px'
height: '100px'
backgroundColor: 'wheat'
Box: 'center middle'
Dom.text "Drag me"
element = Dom.get()
Dom.trackTouch (touch1, touch2) -> # you can also use 'touches...'
if touch1
color = 'wheat'
if touch1.op&1 then color = 'DarkKhaki' # touch start
if touch1.op&2 then color = 'DarkSalmon' # touch move
if touch1.op&4 then color = 'DarkSeaGreen' # touch end
log color
x = touch1.x + touch1.xo
y = touch1.y + touch1.yo - 50 - element.height()/2 # delta y - starty - top bar - half element's height
element.style _transform: "translate(#{x + 'px'}, #{y + 'px'})"
element.style backgroundColor: color
return false # disable native scrolling
, Dom.get()
All functions exposed in this prototype are also available directly on the dom
module, operating on the current element.
Apply .style to the element. hash
should be a javascript object with camelcased css properties as keys. Prefix a key with _
to add vendor-prefix before the css property. Postfix a key with _
to add a vendor-prefix before the css value. The usual pattern is to apply this to the current element using the Dom.style
shortcut:
Dom.div ->
Dom = require 'dom'
Dom.style
display_: 'box'
_boxAlign: 'center'
Dom.text "my box"
Reactively add css class.
Get style property.
Set style of the wrapped element.
Example:
Dom = require 'dom'
Dom.section !->
Dom.div !->
el = Dom.get()
el.style
'backgroundColor': '#F00'
Remove all syling of the element. External CSS is left untouched.
Return {x,y}
object representing actual webkit transformation.
Return offset x/y relative to parent element.
Get/set element property. Not all properties are allowed (e.g. parentNode
).
Short for .prop('value', newValue)
This sets the innerText of the element. Example:
Dom = require 'dom'
UI = require 'ui'
Plugin = require 'plugin'
Dom.section !->
Dom.div !->
el = Dom.get()
Dom.style
color: require('plugin').colors().highlight
Dom.text "Press me"
Dom.onTap !->
el.setText("Bunny!");
Adds a class to selected element.
Removes a class to selected element.
Applies stopPropagation and preventDefault on the event. Useful if you want to override the default behavior.
Returns the target of the event wrapped in a NodeWrapper.
Example:
Dom = require 'dom'
Plugin = require 'plugin'
el = null
Dom.section !->
Dom.div !->
Dom.style
color: require('plugin').colors().highlight
Dom.text "Press me"
el = Dom.get()
Dom.onTap (event) !->
target = event.getTarget()
target.setText "Touched"
Returns the X and Y position of the click/touch event relative to the given element.
Example:
Dom = require 'dom'
Plugin = require 'plugin'
el = null
Dom.section !->
Dom.div !->
Dom.style
color: require('plugin').colors().highlight
Dom.text "Press me"
el = Dom.get()
Dom.onTap (event) !->
xy = event.getTouchXY el
log xy
el.setText("touched: (" + xy.x.toFixed(2) + "; " + xy.y.toFixed(2) + ")")
Returns they keycode of the key pressed.
Example:
Dom = require 'dom'
Dov..section !->
Dom.div !->
Dom.text "Input:"
Dom.input !->
Dom.on 'keydown', (event) !->
log event.getKeyCode()
returns the value of one of the following keys:
- shiftKey
- ctrlKey
- altKey
- button
Example:
Dom = require 'dom'
Dov..section !->
Dom.div !->
Dom.text "Input:"
Dom.input !->
Dom.on 'keydown', (event) !->
log event.getKeyCode()
log event.prop('shiftKey')
log event.prop('ctrlKey')
log event.prop('altKey')
log event.prop('button')
- [How it works](How it works)
- [Your first plugin](Your first plugin)
- Submitting and distributing your plugin
- Using the Developer Tools
- Example plugins on Github
-
API Reference
- Client
- [client plugin](client plugin)
- [client dom](client dom)
- [client obs](client obs)
- [client db](client db)
- [client server](client server)
- [client page](client page)
- [client ui](client ui)
- [client form](client form)
- [client icon](client icon)
- [client modal](client modal)
- [client photo](client photo)
- [client photoview](client photoview)
- [client time](client time)
- [client share](client share)
- [client map](client map)
- [client geoloc](client geoloc)
- Server
- [server event](server event)
- [server plugin](server plugin)
- [server http](server http)
- [server db](server db)
- [server photo](server photo)
- [server time](server time)
- Client
- Example UI elements