neft
Version:
Universal Platform
283 lines (209 loc) • 7.97 kB
text/coffeescript
# Element
'use strict'
utils = require 'src/utils'
assert = require 'src/assert'
signal = require 'src/signal'
{isArray} = Array
{Emitter} = signal
{emitSignal} = Emitter
assert = assert.scope 'View.Element'
class Element extends Emitter
= 'Element'
= 'File.Element'
= []
JSON_CTOR_ID = = .push(Element) - 1
i = 1
JSON_VISIBLE = i++
JSON_ARGS_LENGTH = = i
## *Element* Element.fromHTML(*String* html)
= (html) ->
assert.isString html
unless process.env.NEFT_PLATFORM is 'node'
throw new Error 'Creating Views from HTML files is allowed only on a server'
Element.parser.parse html
## *Element* Element.fromJSON(*Array*|*String* json)
= (json) ->
if typeof json is 'string'
json = JSON.parse json
assert.isArray json
Element.JSON_CTORS[json[0]]._fromJSON json
= (arr, obj = new Element) ->
obj._visible = arr[JSON_VISIBLE] is 1
obj
= require('./element/text') Element
= Tag = require('./element/tag') Element
## *Element* Element::constructor()
constructor: ->
Emitter.call @
= null
= null
= null
= null
= null
= true
= null
= null
= 0
`//<development>`
if is Element
Object.seal @
`//</development>`
## *Integer* Element::index
opts = utils.CONFIGURABLE
utils.defineProperty @::, 'index', opts, ->
?.children.indexOf(@) or 0
, (val) ->
assert.instanceOf , Element
assert.isInteger val
assert.operator val, '>=', 0
parent =
if not parent
return false
{index} = @
children = parent.children
if val > children.length
val = children.length
if index is val or index is val - 1
return false
# current siblings
?._nextSibling =
?._previousSibling =
# children array
children.splice index, 1
if val > index
val--
children.splice val, 0, @
# new siblings
= children[val - 1] or null
= children[val + 1] or null
?._nextSibling = @
?._previousSibling = @
assert.is , val
assert.is children[val], @
assert.is , children[val - 1] or null
assert.is , children[val + 1] or null
true
## *Element* Element::nextSibling
opts = utils.CONFIGURABLE
utils.defineProperty @::, 'nextSibling', opts, ->
, null
## *Element* Element::previousSibling
opts = utils.CONFIGURABLE
utils.defineProperty @::, 'previousSibling', opts, ->
, null
## *Element* Element::parent
opts = utils.CONFIGURABLE
utils.defineProperty @::, 'parent', opts, ->
, (val) ->
assert.instanceOf @, Element
assert.instanceOf val, Element if val?
assert.isNot @, val
old =
if old is val
return false
# remove element
if
oldChildren = .children
assert.ok utils.has(oldChildren, @)
if not
assert.ok oldChildren[oldChildren.length - 1] is @
oldChildren.pop()
else if not
assert.ok oldChildren[0] is @
oldChildren.shift()
else
index = oldChildren.indexOf @
oldChildren.splice index, 1
emitSignal , 'onChildrenChange', null, @
?._nextSibling =
?._previousSibling =
= null
= null
= parent = val
# append element
if parent
assert.notOk utils.has(.children, @)
newChildren = .children
index = newChildren.push(@) - 1
emitSignal parent, 'onChildrenChange', @
if index is 0
= null
else
= newChildren[index - 1]
._nextSibling = @
assert.is , val
assert.is , null
assert.is , val?.children[val.children.length - 2] or null
if
assert.is ._nextSibling, @
# trigger signal
emitSignal @, 'onParentChange', old
Tag.query.checkWatchersDeeply @, old
Tag.query.checkWatchersDeeply @
true
## *Signal* Element::onParentChange(*Element* oldValue)
signal.Emitter.createSignal @, 'onParentChange'
## *Renderer.Item* Element::style
opts = utils.CONFIGURABLE
utils.defineProperty @::, 'style', opts, ->
, (val) ->
old =
if old is val
return false
= val
# trigger signal
emitSignal @, 'onStyleChange', old, val
true
## *Signal* Element::onStyleChange(*Renderer.Item* oldValue)
signal.Emitter.createSignal @, 'onStyleChange'
## *Boolean* Element::visible
opts = utils.CONFIGURABLE
utils.defineProperty @::, 'visible', opts, ->
, (val) ->
assert.isBoolean val
old =
if old is val
return false
= val
# trigger signal
emitSignal @, 'onVisibleChange', old
true
## *Signal* Element::onVisibleChange(*Boolean* oldValue)
signal.Emitter.createSignal @, 'onVisibleChange'
## *Array* Element::queryAllParents(*String* query)
queryAllParents: Tag.query.queryAllParents
## *Element* Element::queryParents(*String* query)
queryParents: Tag.query.queryParents
## *Array* Element::getAccessPath([*Tag* toParent])
getAccessPath: (toParent) ->
if toParent?
assert.instanceOf toParent, Tag
arr = []
i = 0
elem = @
parent = @
while parent = elem._parent
arr.push parent.children.indexOf(elem)
elem = parent
if parent is toParent
break
arr
## *Element* Element::clone()
clone: (clone = new Element) ->
clone._visible =
clone
## *Array* Element::toJSON()
toJSON: (arr) ->
unless arr
arr = new Array JSON_ARGS_LENGTH
arr[0] = JSON_CTOR_ID
arr[JSON_VISIBLE] = if then 1 else 0
arr
if process.env.NEFT_PLATFORM is 'node'
= require('./element/parser') Element
module.exports = Element