diff --git a/framer/LayerStates.coffee b/framer/LayerStates.coffee index d14d5bd6e..5c77f08e6 100644 --- a/framer/LayerStates.coffee +++ b/framer/LayerStates.coffee @@ -57,12 +57,6 @@ class exports.LayerStates extends BaseClass # Switches to a specific state. If animationOptions are # given use those, otherwise the default options. - # We actually do want to allow this. A state can be set to something - # that does not equal the property values for that state. - - # if stateName is @_currentState - # return - if not @_states.hasOwnProperty(stateName) throw Error "No such state: '#{stateName}'" @@ -84,7 +78,9 @@ class exports.LayerStates extends BaseClass continue # Allow dynamic properties as functions - value = value.call(@layer, @layer, propertyName, stateName) if _.isFunction(value) + if _.isFunction(value) + value = value.call(@layer, @layer, propertyName, stateName) + # Set the new value properties[propertyName] = value @@ -93,40 +89,45 @@ class exports.LayerStates extends BaseClass animatablePropertyKeys = [] for k, v of properties + + # We can animate numbers if _.isNumber(v) animatablePropertyKeys.push(k) + + # We can animate colors else if Color.isColorObject(v) animatablePropertyKeys.push(k) - else if v == null - animatablePropertyKeys.push(k) + # If we don't have any animatable properties, we always switch instant if animatablePropertyKeys.length == 0 instant = true - if instant is true - # We want to switch immediately without animation + if instant @layer.props = properties - @emit Events.StateDidSwitch, _.last(@_previousStates), @_currentState, @ + @emit(Events.StateDidSwitch, _.last(@_previousStates), @_currentState, @) + return + + # If there are, we start the animation here + animationOptions ?= @animationOptions + animationOptions.properties = properties - else - # Start the animation and update the state when finished - animationOptions ?= @animationOptions - animationOptions.properties = properties + @_animation?.stop() + @_animation = @layer.animate(animationOptions) - @_animation?.stop() - @_animation = @layer.animate animationOptions - @_animation.once "stop", => + # Once the animation is done, we set all the keys that we could not animate + @_animation.once "stop", => - # Set all the values for keys that we couldn't animate - for k, v of properties - @layer[k] = v unless _.isNumber(v) or Color.isColorObject(v) + for k, v of properties + @layer[k] = v if v not in animatablePropertyKeys - @emit(Events.StateDidSwitch, _.last(@_previousStates), @_currentState, @) unless _.last(@_previousStates) is stateName + # If we changed the state, we send the event that we did + if _.last(@_previousStates) isnt stateName + @emit(Events.StateDidSwitch, _.last(@_previousStates), @_currentState, @) switchInstant: (stateName) -> - @switch stateName, null, true + @switch(stateName, null, true) @define "state", get: -> @_currentState @define "current", get: -> @_currentState @@ -138,7 +139,7 @@ class exports.LayerStates extends BaseClass animatingKeys: -> - # Get a list of all the propeties controlled by states + # Get a list of all the properties controlled by states keys = [] @@ -177,11 +178,31 @@ class exports.LayerStates extends BaseClass # TODO: Maybe we want to support advanced data structures like objects in the future too. for k, v of properties - # We check if the property name ends with color, because we don't want - # to convert every string that looks like a Color, like the html property containing "add" - if _.isString(v) and _.endsWith(k.toLowerCase(),"color") and Color.isColorString(v) + + if @_isValidColor(k, v) stateProperties[k] = new Color(v) - else if _.isNumber(v) or _.isFunction(v) or _.isBoolean(v) or _.isString(v) or Color.isColorObject(v) or v == null + continue + + if @_isValidProperty(k, v) stateProperties[k] = v return stateProperties + + @_isValidColor: (k, v) -> + + # We check if the property name ends with color, because we don't want + # to convert every string that looks like a Color, like the html property containing "add" + if _.endsWith(k.toLowerCase(), "color") and _.isString(v) and Color.isColorString(v) + return true + + return false + + @_isValidProperty: (k, v) -> + return true if _.isNumber(v) + return true if _.isFunction(v) + return true if _.isBoolean(v) + return true if _.isString(v) + return true if Color.isColorObject(v) + return true if v is null + return true if v?.constructor?.name is "Layer" + return false diff --git a/test/tests/LayerStatesTest.coffee b/test/tests/LayerStatesTest.coffee index bee21e120..4de6b75d6 100644 --- a/test/tests/LayerStatesTest.coffee +++ b/test/tests/LayerStatesTest.coffee @@ -1,3 +1,5 @@ +assert = require "assert" + describe "LayerStates", -> describe "Events", -> @@ -179,3 +181,21 @@ describe "LayerStates", -> layer.states.switchInstant "default" layer.x.should.equal 0 + + it "should set the parent", -> + + layerA = new Layer + layerB = new Layer + parent: layerA + + layerB.states.add + stateA: + parent: null + + assert.equal(layerB.parent, layerA) + + layerB.states.switchInstant "stateA" + assert.equal(layerB.parent, null) + + layerB.states.switchInstant "default" + # assert.equal(layerB.parent, layerA)