/* This file contains proprietary software owned by Motorola Mobility, Inc.
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
*/ var Montage = require("montage/core/core").Montage; var Component = require("montage/ui/component").Component; var Collapser = require("js/panels/Timeline/Collapser").Collapser; var defaultEventManager = require("montage/core/event/event-manager").defaultEventManager; var TimelineTrack = exports.TimelineTrack = Montage.create(Component, { // ==== Begin Models _trackID:{ value:null }, trackID:{ serializable:true, get:function () { return this._trackID; }, set:function (value) { if (value !== this._trackID) { this._trackID = value; this.trackData.layerID = value; } } }, _tween:{ value:[] }, tween:{ serializable:true, get:function () { return this._tween; }, set:function (newVal) { this._tween = newVal; } }, positionPropertyTrack:{ value:null }, _isFirstDraw: { value: true }, _isVisible:{ value: true }, isVisible:{ get:function(){ return this._isVisible; }, set:function(value){ if (this._isVisible !== value) { this._isVisible = value; if (this.element !== null) { if (value === true) { this.element.classList.remove("layer-hidden"); } else { this.element.classList.add("layer-hidden"); } } } this.trackData.isVisible = value; } }, _bindingPoint : { value : {} }, bindingPoint: { get: function() { return this._bindingPoint; }, set: function(newVal) { if (newVal !== this._bindingPoint) { this._bindingPoint = newVal; this.setData(); } } }, _stageElement: { value: null }, stageElement: { get: function() { return this._stageElement; }, set: function(newVal) { this._stageElement = newVal; this.trackData.stageElement = newVal; } }, _isMainCollapsed:{ value: true }, isMainCollapsed:{ get:function () { return this._isMainCollapsed; }, set:function (newVal) { this._isMainCollapsed = newVal; this.trackData.isMainCollapsed = newVal; } }, _isPositionCollapsed:{ value:true }, isPositionCollapsed:{ get:function () { return this._isPositionCollapsed; }, set:function (newVal) { this._isPositionCollapsed = newVal; this.trackData.isPositionCollapsed = newVal; } }, _isStyleCollapsed:{ value:true }, isStyleCollapsed:{ get:function () { return this._isStyleCollapsed; }, set:function (newVal) { this._isStyleCollapsed = newVal; this.trackData.isStyleCollapsed = newVal; } }, _bypassAnimation : { value: false }, bypassAnimation : { serializable: true, get: function() { return this._bypassAnimation; }, set: function(newVal) { if (typeof(this.trackData) !== "undefined") { this._bypassAnimation = newVal; this.trackData.bypassAnimation = newVal; } } }, _arrStyleTracks : { value: [] }, arrStyleTracks: { serializable:true, get: function() { return this._arrStyleTracks; }, set: function(newVal) { this._arrStyleTracks = newVal; this.trackData.arrStyleTracks = newVal; } }, _styleTracksRepetition: { value: null }, styleTracksRepetition : { serializable:true, get: function() { return this._styleTracksRepetition; }, set: function(newVal) { this._styleTracksRepetition = newVal; } }, _arrPositionTracks : { value: [] }, arrPositionTracks: { serializable:true, get: function() { return this._arrPositionTracks; }, set: function(newVal) { this._arrPositionTracks = newVal; this.trackData.arrPositionTracks = newVal; } }, _positionTracksRepetition: { value: null }, positionTracksRepetition : { get: function() { return this._positionTracksRepetition; }, set: function(newVal) { this._positionTracksRepetition = newVal; } }, _tweens:{ value:[] }, tweens:{ serializable: true, get:function () { return this._tweens; }, set:function (newVal) { this._tweens = newVal; this.trackData.tweens = newVal; } }, _tweenRepetition:{ value:null }, tweenRepetition:{ get:function () { return this._tweenRepetition; }, set:function (newVal) { this._tweenRepetition = newVal; } }, _trackDuration:{ value:0 }, trackDuration:{ serializable:true, get:function () { return this._trackDuration; }, set:function (val) { this._trackDuration = val; if(this._trackDuration > this.application.ninja.timeline.masterDuration){ this.application.ninja.timeline.masterDuration = this._trackDuration; } this.trackData.trackDuration = val; } }, _trackPosition:{ value:0 }, trackPosition:{ serializable:true, get:function () { return this._trackPosition; }, set:function (val) { this._trackPosition = val; this.trackData.trackPosition = val; } }, _currentKeyframeRule:{ value:null }, currentKeyframeRule:{ serializable: true, get:function(){ return this._currentKeyframeRule; }, set:function(val){ this._currentKeyframeRule = val; this.trackData.currentKeyframeRule = val; } }, nextKeyframe:{ value:1 }, currentMillisecClicked:{ value:0 }, _isTrackAnimated:{ value:null }, isTrackAnimated:{ serializable: true, get:function(){ return this._isTrackAnimated; }, set:function(val){ this._isTrackAnimated = val; this.trackData.isTrackAnimated = val; } }, _animatedElement:{ value:null }, animatedElement:{ serializable:true, get:function () { return this._animatedElement; }, set:function (val) { this._animatedElement = val; this.trackData.animatedElement = val; } }, _animationName:{ value:null }, animationName:{ serializable:true, get:function () { return this._animationName; }, set:function (val) { this._animationName = val; this.trackData.animationName = val; } }, _ruleList:{ value:[] }, ruleList:{ get:function () { return this._ruleList; }, set:function (val) { this._ruleList = val; } }, animationNamesString:{ value:"" }, ninjaStylesContoller:{ value:null }, _positionCollapser:{ value:null }, positionCollapser:{ serializable:true, get:function(){ return this._positionCollapser; }, set:function(val){ this._positionCollapser = val; } }, _mainCollapser:{ value:null }, mainCollapser:{ serializable:true, get:function () { return this._mainCollapser; }, set:function (val) { this._mainCollapser = val; } }, _styleCollapser:{ value:null }, styleCollapser:{ serializable:true, get:function () { return this._styleCollapser; }, set:function (val) { this._styleCollapser = val; } }, _dragAndDropHelper : { value: false }, _dragAndDropHelperCoords: { value: false }, dragAndDropHelperCoords: { get: function() { return this._dragAndDropHelperCoords; }, set: function(newVal) { this._dragAndDropHelperCoords = newVal; } }, _draggingIndex: { value: false }, draggingIndex: { get: function() { return this._draggingIndex; }, set: function(newVal) { this._draggingIndex = newVal; } }, _dragAndDropHelperOffset : { value: false }, _appendHelper: { value: false }, _deleteHelper: { value: false }, _trackData:{ value: false }, trackData:{ serializable: true, get:function(){ return this._trackData; }, set:function(val){ this._trackData = val; if(this._trackData){ this.setData(); } } }, _setDataTimestamp : { value: false }, setData:{ value:function(){ if (typeof(this.trackData) === "undefined") { return; } this.bypassAnimation = this.trackData.bypassAnimation; this.trackID = this.trackData.layerID; this.tweens = this.trackData.tweens; this.arrPositionTracks = this.trackData.arrPositionTracks; this.animatedElement = this.trackData.animatedElement; this.arrStyleTracks = this.trackData.arrStyleTracks; this.isTrackAnimated = this.trackData.isTrackAnimated; this.trackDuration = this.trackData.trackDuration; this.animationName = this.trackData.animationName; this.currentKeyframeRule = this.trackData.currentKeyframeRule; this.isMainCollapsed = this.trackData.isMainCollapsed; this.isPositionCollapsed = this.trackData.isPositionCollapsed; this.isTransformCollapsed = this.trackData.isTransformCollapsed; this.isStyleCollapsed = this.trackData.isStyleCollapsed; this.trackPosition = this.trackData.trackPosition; this.isVisible = this.trackData.isVisible; this.stageElement = this.trackData.stageElement; this.trackEditorProperty = "master"; this.needsDraw = true; } }, // ==== End Models // ==== Begin Draw cycle methods prepareForDraw:{ value:function () { this.init(); this.ninjaStylesContoller = this.application.ninja.stylesController; this.element.addEventListener("click", this, false); this.eventManager.addEventListener("tlZoomSlider", this, false); // Drag and Drop event handlers this.element.addEventListener("dragstart", this.handleKeyframeDragstart.bind(this), false); this.element.addEventListener("dragend", this.handleKeyframeDragend.bind(this), false); } }, draw:{ value:function () { this.ninjaStylesContoller = this.application.ninja.stylesController; var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID); if (selectedIndex !== false) { if(this.application.ninja.timeline.arrLayers[selectedIndex].layerData.stageElement){ this.animatedElement = this.application.ninja.timeline.arrLayers[selectedIndex].layerData.stageElement; } } // Drag and Drop: if (this._appendHelper === true) { this.track_lanes.appendChild(this._dragAndDropHelper); this._appendHelper = false; } if (this._dragAndDropHelperCoords !== false) { if (this._dragAndDropHelper !== null) { if (typeof(this._dragAndDropHelper.style) !== "undefined") { this._dragAndDropHelper.style.left = this._dragAndDropHelperCoords; } } this._dragAndDropHelperCoords = false; } if (this._deleteHelper === true) { if (this._dragAndDropHelper === null) { var myHelper = this.element.querySelector(".track-dnd-helper"); if (myHelper != null) { this._dragAndDropHelper = myHelper; } } if (this._dragAndDropHelper !== null) { if (this._dragAndDropHelper && this._dragAndDropHelper.parentNode === this.track_lanes) { this.track_lanes.removeChild(this._dragAndDropHelper); this._dragAndDropHelper = null; this._deleteHelper = false; } } } } }, didDraw:{ value:function () { if ((!this.application.ninja.documentController.creatingNewFile)||(!this.application.ninja.currentDocument.setLevel)) { if (this.application.ninja.currentDocument.model.documentRoot.children[0]) { var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID); if (selectedIndex !== false) { if (!this.application.ninja.timeline.arrLayers[selectedIndex].layerData.created) { this.retrieveStoredTweens(); } } } } if (this._isFirstDraw === true) { if (this.isMainCollapsed === false) { this._mainCollapser.myContent.style.height = "auto"; this._mainCollapser.myContent.classList.remove(this._mainCollapser.collapsedClass); this._mainCollapser.clicker.classList.remove(this._mainCollapser.collapsedClass); } if (this.isPositionCollapsed === false) { this._positionCollapser.myContent.style.height = "auto"; this._positionCollapser.myContent.classList.remove(this._positionCollapser.collapsedClass); this._positionCollapser.clicker.classList.remove(this._positionCollapser.collapsedClass); } if (this.isStyleCollapsed === false) { this._styleCollapser.myContent.style.height = "auto"; this._styleCollapser.myContent.classList.remove(this._styleCollapser.collapsedClass); this._styleCollapser.clicker.classList.remove(this._styleCollapser.collapsedClass); } this._isFirstDraw = false; } } }, // ==== End Draw cycle methods // ==== Begin Event handlers handleTlZoomSlider: { value: function(event) { var currentMilliSecPerPixel , currentMilliSec , clickPos,thingToPush; var i = 0, tweensLength = this.tweens.length; for (i = 0; i < tweensLength; i++) { if (i === 0) { // Exception: 0th item does not depend on anything // If 0th tween is draggable, this will need to be fixed. this.tweens[i].tweenData.spanWidth=0; this.tweens[i].tweenData.spanPosition=0; this.tweens[i].tweenData.keyFramePosition=0; this.tweens[i].tweenData.keyFrameMillisec=0; } else { var prevKeyFramePosition = this.tweens[i - 1].tweenData.keyFramePosition, myObj = {}, thing = {}; currentMilliSecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80); currentMilliSec = this.tweens[i].tweenData.keyFrameMillisec; clickPos = currentMilliSec / currentMilliSecPerPixel; for (thing in this.tweens[i].tweenData) { myObj[thing] = this.tweens[i].tweenData[thing]; } myObj.spanWidth = clickPos - prevKeyFramePosition; myObj.keyFramePosition = clickPos; myObj.spanPosition = clickPos - (clickPos - prevKeyFramePosition); this.tweens[i].tweenData = myObj; } } } }, handleClick:{ value:function (ev) { var targetElementOffset = this.findXOffset(ev.currentTarget), position = (event.pageX - targetElementOffset) - 18; this.application.ninja.timeline.playheadmarker.style.left = position + "px"; var currentMillisecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80); var currentMillisec = currentMillisecPerPixel * position; this.application.ninja.timeline.updateTimeText(currentMillisec); if (ev.shiftKey) { var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID); this.application.ninja.timeline.selectLayer(selectedIndex, true); if (this.tweens.length < 1) { this.insertTween(0); this.addAnimationRuleToElement(ev); this.updateKeyframeRule(); } else { if (ev.target.className === "tracklane") { this.handleNewTween(ev); this.updateKeyframeRule(); } else if (ev.target.className === "tween_span_bar" && ev.target.parentElement.parentElement.parentElement.className === "tracklane") { this.handleNewTween(ev); this.updateKeyframeRule(); } } } } }, handleKeyboardShortcut:{ value:function (ev) { if (ev.actionType == "insert") { if (this.tweens.length < 1) { this.insertTween(0); this.addAnimationRuleToElement(ev); this.updateKeyframeRule(); } else { this.handleNewTween(ev); this.updateKeyframeRule(); } } else if (ev.actionType == "remove") { this.removeTween(); this.updateKeyframeRule(); } } }, // Drag and drop event handlers handleKeyframeDragstart:{ value:function (event) { var dragIcon = document.createElement("img"), minPosition = 0, maxPosition = 100000000000; event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('Text', this.identifier); dragIcon.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAA1JREFUGFdj+P//PwMACPwC/ohfBuAAAAAASUVORK5CYII=" dragIcon.width = 1; event.dataTransfer.setDragImage(dragIcon, 0, 0); // Clone the element we're dragging this._dragAndDropHelper = event.target.cloneNode(true); this._dragAndDropHelper.style.opacity = 0.8; this._dragAndDropHelper.style.position = "absolute"; this._dragAndDropHelper.style.top = "5px"; this._dragAndDropHelper.style.left = "0px"; this._dragAndDropHelper.style.zIndex = 700; this._dragAndDropHelper.classList.add("keyframeSelected"); this._dragAndDropHelper.classList.add("track-dnd-helper"); if (this.draggingIndex < (this.tweens.length - 1)) { maxPosition = this.tweenRepetition.childComponents[this.draggingIndex + 1].keyFramePosition; } if (this.draggingIndex > 1) { minPosition = this.tweenRepetition.childComponents[this.draggingIndex - 1].keyFramePosition; } this._keyframeMinPosition = minPosition + 2; this._keyframeMaxPosition = maxPosition - 9; this._appendHelper = true; this._deleteHelper = false; var i = 0, arrLayersLength = this.parentComponent.parentComponent.arrLayers.length, myId = null; for (i = 0; i < arrLayersLength; i++) { var currUuid = this.parentComponent.parentComponent.trackRepetition.childComponents[i].uuid; if (currUuid === this.uuid) { myId = i; } } this.parentComponent.parentComponent.draggingTrackId = myId; this.parentComponent.parentComponent.draggingType = "keyframe"; } }, handleKeyframeDragend:{ value:function (event) { if (this.parentComponent.parentComponent.draggingType !== "keyframe") { return; } this._deleteHelper = true; this.needsDraw = true; } }, handleNewTween:{ value:function (ev) { if (ev.offsetX > this.tweens[this.tweens.length - 1].tweenData.keyFramePosition) { var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID); this.application.ninja.timeline.selectLayer(selectedIndex, false); this.insertTween(ev.offsetX); } else { if (typeof(ev.currentTarget) === "undefined") { this.splitTweenAt(ev.offsetX); } else { var targetElementOffset = this.findXOffset(ev.currentTarget), position = event.pageX - targetElementOffset; this.splitTweenAt(position-18); } } } }, handleLayerEvent:{ value:function (layerEvent) { if (layerEvent.layerID !== this.trackID) { return; } if (layerEvent.layerEventType === "newStyle") { var newStyleTrack = {}; newStyleTrack.propTrackData = {}; newStyleTrack.propTrackData.styleSelection = layerEvent.styleSelection; newStyleTrack.propTrackData.propTweens = []; newStyleTrack.propTrackData.trackType = "style"; newStyleTrack.propTrackData.trackEditorProperty = ""; newStyleTrack.propTrackData.styleIndex = layerEvent.styleIndex; newStyleTrack.propTrackData.existingRule = ""; this.arrStyleTracks.push(newStyleTrack); } else if (layerEvent.layerEventType === "restoreStyle") { var restoredStyleTrack = {}; restoredStyleTrack.propTrackData = {}; restoredStyleTrack.propTrackData.styleSelection = layerEvent.styleSelection; restoredStyleTrack.propTrackData.propTweens = []; restoredStyleTrack.propTrackData.trackType = "style"; restoredStyleTrack.propTrackData.trackEditorProperty = layerEvent.trackEditorProperty; restoredStyleTrack.propTrackData.styleIndex = layerEvent.styleIndex; restoredStyleTrack.propTrackData.existingRule = layerEvent.existingRule; this.arrStyleTracks.push(restoredStyleTrack); } else if (layerEvent.layerEventType === "deleteStyle") { this.arrStyleTracks.splice(layerEvent._event.selectedStyleIndex, 1); } } }, // ==== End Event handlers // ==== Begin Controllers init:{ value:function () { this.createPositionTracks(); this.element.addEventListener("layerEvent", this, false); } }, createPositionTracks:{ value:function(){ if (this.arrPositionTracks.length > 0) { return; } var newLeftTrack = {}; newLeftTrack.propTrackData = {}; newLeftTrack.propTrackData.propTweens = []; newLeftTrack.propTrackData.styleIndex = 1; newLeftTrack.propTrackData.trackType = "position"; newLeftTrack.propTrackData.trackEditorProperty = "left"; this.arrPositionTracks.push(newLeftTrack); var newTopTrack = {}; newTopTrack.propTrackData = {}; newTopTrack.propTrackData.propTweens = []; newTopTrack.propTrackData.styleIndex = 0; newTopTrack.propTrackData.trackType = "position"; newTopTrack.propTrackData.trackEditorProperty = "top"; this.arrPositionTracks.push(newTopTrack); var newWidthTrack = {}; newWidthTrack.propTrackData = {}; newWidthTrack.propTrackData.propTweens = []; newWidthTrack.propTrackData.styleIndex = 2; newWidthTrack.propTrackData.trackType = "position"; newWidthTrack.propTrackData.trackEditorProperty = "width"; this.arrPositionTracks.push(newWidthTrack); var newHeightTrack = {}; newHeightTrack.propTrackData = {}; newHeightTrack.propTrackData.propTweens = []; newHeightTrack.propTrackData.styleIndex = 3; newHeightTrack.propTrackData.trackType = "position"; newHeightTrack.propTrackData.trackEditorProperty = "height"; this.arrPositionTracks.push(newHeightTrack); } }, createTrackData:{ value:function () { tempData = {}; tempData.bypassAnimation = this.bypassAnimation; tempData.trackID = this.layerID; tempData.tweens = this.tweens; tempData.animatedElement = this.animatedElement; tempData.arrStyleTracks = this.arrStyleTracks; tempData.arrPositionTracks = this.arrPositionTracks; tempData.isTrackAnimated = this.isTrackAnimated; tempData.trackDuration = this.trackDuration; tempData.animationName = this.animationName; tempData.currentKeyframeRule = this.currentKeyframeRule; tempData.isMainCollapsed = this.isMainCollapsed; tempData.isPositionCollapsed = this.isPositionCollapsed; tempData.isTransformCollapsed = this.isTransformCollapsed; tempData.isStyleCollapsed = this.isStyleCollapsed; tempData.trackPosition = this.trackPosition; tempData.isVisible = this.isVisible; this.trackData = tempData; } }, triggerOutgoingBinding:{ value:function () { this.trackData.triggerBinding = !this.trackData.triggerBinding; } }, insertTween:{ value:function (clickPos) { var currentMillisecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80); var currentMillisec = currentMillisecPerPixel * clickPos; this.trackDuration = currentMillisec; var newTween = {}; newTween.tweenData = {}; if (clickPos == 0) { this.animatedElement = this.application.ninja.timeline.arrLayers[this.application.ninja.timeline.currentLayersSelected[0]].layerData.stageElement; newTween.tweenData.spanWidth = 0; newTween.tweenData.keyFramePosition = 0; newTween.tweenData.keyFrameMillisec = 0; newTween.tweenData.tweenID = 0; newTween.tweenData.spanPosition = 0; newTween.tweenData.easing = "none"; newTween.tweenData.initSelect = true; newTween.tweenData.tweenedProperties = []; newTween.tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop + "px"; newTween.tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft + "px"; newTween.tweenData.tweenedProperties["width"] = this.animatedElement.offsetWidth + "px"; newTween.tweenData.tweenedProperties["height"] = this.animatedElement.offsetHeight + "px"; this.tweens.push(newTween); this.createMatchingPositionSizeTween(newTween); } else { newTween.tweenData.spanWidth = clickPos - this.tweens[this.tweens.length - 1].tweenData.keyFramePosition; newTween.tweenData.keyFramePosition = clickPos; newTween.tweenData.keyFrameMillisec = currentMillisec; newTween.tweenData.tweenID = this.nextKeyframe; newTween.tweenData.spanPosition = clickPos - newTween.tweenData.spanWidth; newTween.tweenData.easing = "none"; newTween.tweenData.initSelect = true; newTween.tweenData.tweenedProperties = []; newTween.tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop + "px"; newTween.tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft + "px"; newTween.tweenData.tweenedProperties["width"] = this.animatedElement.offsetWidth + "px"; newTween.tweenData.tweenedProperties["height"] = this.animatedElement.offsetHeight + "px"; this.tweens.push(newTween); var animationDuration = (this.trackDuration / 1000) + "s"; this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-duration", animationDuration); this.nextKeyframe += 1; this.createMatchingPositionSizeTween(newTween); } this.application.ninja.currentDocument.model.needsSave = true; } }, removeTween:{ value:function(){ var tweenIDToRemove = this.application.ninja.timeline.selectedTweens[0].tweenID, oldPosition = this.application.ninja.timeline.selectedTweens[0].spanPosition, oldSpanWidth = this.application.ninja.timeline.selectedTweens[0].spanWidth; if(tweenIDToRemove == this.tweens[this.tweens.length-1].tweenData.tweenID){ this.trackDuration = this.tweens[this.tweens.length-2].tweenData.keyFrameMillisec; this.tweens.pop(); return; } this.tweens[tweenIDToRemove + 1].tweenData.spanPosition = oldPosition; this.tweens[tweenIDToRemove + 1].spanPosition = oldPosition; this.tweens[tweenIDToRemove + 1].tweenData.spanWidth = this.tweens[tweenIDToRemove + 1].tweenData.spanWidth + oldSpanWidth; this.tweens[tweenIDToRemove + 1].spanWidth = this.tweens[tweenIDToRemove + 1].spanWidth + oldSpanWidth; for(var i in this.tweenRepetition.childComponents){ this.tweenRepetition.childComponents[i].setData(); } this.tweens.splice(tweenIDToRemove, 1); this.application.ninja.currentDocument.model.needsSave = true; for (var j = 0; j < this.tweens.length; j++) { this.tweens[j].tweenID = j; this.tweens[j].tweenData.tweenID = j; } } }, // splitTweenAt: Split a tween at a particular position (x coordinate) splitTweenAt: { value:function (position) { var i, j, nextComponentIndex, tweensLength = this.tweens.length-1, prevTween, nextTween, splitTweenIndex; // Search through the tweens and find the pair whose keyframes bracket position. for(i=0; i prevTween && position < nextTween) { // We will insert a new tween at this index splitTweenIndex = i+1; // Update the next tween to have new span position and width. this.tweens[i+1].tweenData.spanPosition = position; this.tweens[i+1].spanPosition = position; this.tweens[i+1].tweenData.spanWidth = this.tweens[i+1].tweenData.keyFramePosition - position; this.tweens[i+1].spanWidth = this.tweens[i+1].keyFramePosition - position; // You'd think that would be enough to make the component associated with that part of the array redraw, wouldn't you? // Turns out we have to manually poke the desired childComponent in the repetition to register its new changes. // So we have to get the index of the actual componentin the repetition, which may not match our iteration index. for (j = 0; j < tweensLength +1; j++) { if (this.tweenRepetition.childComponents[j].keyFramePosition === nextTween) { nextComponentIndex = j; } } this.tweenRepetition.childComponents[nextComponentIndex].setData(); // Create the new tween and splice it into the model var newTweenToInsert = {}; newTweenToInsert.tweenData = {}; newTweenToInsert.tweenData.spanWidth = position - prevTween; newTweenToInsert.tweenData.keyFramePosition = position; newTweenToInsert.tweenData.keyFrameMillisec = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80) * position; newTweenToInsert.tweenData.tweenID = this.tweens.length; newTweenToInsert.tweenData.spanPosition = position - newTweenToInsert.tweenData.spanWidth; newTweenToInsert.tweenData.tweenedProperties = []; newTweenToInsert.tweenData.easing = "none"; newTweenToInsert.tweenData.initSelect = true; newTweenToInsert.tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop + "px"; newTweenToInsert.tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft + "px"; newTweenToInsert.tweenData.tweenedProperties["width"] = this.animatedElement.offsetWidth + "px"; newTweenToInsert.tweenData.tweenedProperties["height"] = this.animatedElement.offsetHeight + "px"; this.tweens.splice(splitTweenIndex, 0, newTweenToInsert); i = tweensLength; } } this.application.ninja.currentDocument.model.needsSave = true; for (i = 0; i <= tweensLength+1; i++) { this.tweens[i].tweenID = i; this.tweens[i].tweenData.tweenID = i; } } }, retrieveStoredTweens:{ value:function () { var percentValue, fraction, splitValue,offsetAttribute,topOffSetAttribute,leftOffsetAttribute,widthOffsetAttribute,heightOffsetAttribute; var currentMilliSec,currentMilliSecPerPixel,clickPosition,tempTiming,tempTimingFloat,trackTiming,i = 0; var selectedIndex = this.application.ninja.timeline.getLayerIndexByID(this.trackID); this.application.ninja.timeline.arrLayers[selectedIndex].layerData.created=true; this.animatedElement = this.application.ninja.timeline.arrLayers[selectedIndex].layerData.stageElement; if(this.animatedElement!==undefined){ this.animationName = this.application.ninja.stylesController.getElementStyle(this.animatedElement, "-webkit-animation-name"); if(this.animationName){ // check for multiple animation names var animationNameList = this.animationName.split(","); if (animationNameList.length > 1) { this.animationNamesString = this.animationName; this.animationName = animationNameList[0]; this.getAllAnimationRules(animationNameList); } else { this.animationNamesString = this.animationName; } trackTiming = this.application.ninja.stylesController.getElementStyle(this.animatedElement, "-webkit-animation-duration"); this.nextKeyframe = 0; this.currentKeyframeRule = this.application.ninja.stylesController.getAnimationRuleWithName(this.animationName, this.application.ninja.currentDocument.model.views.design.document); for (i =0; this.currentKeyframeRule[i] ;i++) { var newTween = {}; newTween.tweenData = {}; var j, styleLength = this.currentKeyframeRule[i].style.length, keyframeStyles = []; for (j = 0; j < styleLength; j++) { var currProp = this.currentKeyframeRule[i].style[j]; var propVal = this.currentKeyframeRule[i].style[currProp]; keyframeStyles.push([currProp, propVal]); } // recreate tween properties array for timeline tween newTween.tweenData.tweenedProperties = []; for(var k in keyframeStyles){ newTween.tweenData.tweenedProperties[keyframeStyles[k][0]] = keyframeStyles[k][1]; } if (this.currentKeyframeRule[i].keyText === "0%") { newTween.tweenData.spanWidth = 0; newTween.tweenData.keyFramePosition = 0; newTween.tweenData.keyFrameMillisec = 0; newTween.tweenData.tweenID = 0; newTween.tweenData.spanPosition = 0; newTween.tweenData.initSelect = false; this.tweens.push(newTween); this.createMatchingPositionSizeTween(newTween); } else { tempTiming = trackTiming.split("s"); tempTimingFloat = parseFloat(tempTiming[0]); this.trackDuration = tempTimingFloat *1000; percentValue = this.currentKeyframeRule[i].keyText; splitValue = percentValue.split("%"); fraction = splitValue[0] / 100; currentMilliSec = fraction * this.trackDuration; currentMilliSecPerPixel = Math.floor(this.application.ninja.timeline.millisecondsOffset / 80); clickPosition = currentMilliSec / currentMilliSecPerPixel; newTween.tweenData.spanWidth = clickPosition - this.tweens[this.tweens.length - 1].tweenData.keyFramePosition; newTween.tweenData.keyFramePosition = clickPosition; newTween.tweenData.keyFrameMillisec = currentMilliSec; newTween.tweenData.tweenID = this.nextKeyframe; newTween.tweenData.initSelect = false; newTween.tweenData.spanPosition =clickPosition - newTween.tweenData.spanWidth; newTween.tweenData.easing = this.currentKeyframeRule[i].style.webkitAnimationName; if (newTween.tweenData.easing == "") { newTween.tweenData.easing = "none"; } this.tweens.push(newTween); this.createMatchingPositionSizeTween(newTween); } this.nextKeyframe += 1; } this.isTrackAnimated = true; } } } }, getAllAnimationRules:{ value:function(ruleNames){ ruleNames.splice(0,1); // temp remove first animation already retrieved for main track for(var i in ruleNames){ var currentName = ruleNames[i].replace(/^\s+|\s+$/g,""); // trim whitespace var currentRule = this.application.ninja.stylesController.getAnimationRuleWithName(currentName, this.application.ninja.currentDocument._document); this.ruleList[currentName] = currentRule; } this.recreatePropertyTracks(this.ruleList); } }, recreatePropertyTracks:{ value:function(ruleSet){ for(var i in ruleSet){ var styleProp = ruleSet[i][0].style[0]; this.application.ninja.timeline.layerRepetition.childComponents[0].addStyle(styleProp, ruleSet[i]); } } }, addAnimationRuleToElement:{ value:function (tweenEvent) { this.tweens[0].tweenData.tweenedProperties["top"] = this.animatedElement.offsetTop + "px"; this.tweens[0].tweenData.tweenedProperties["left"] = this.animatedElement.offsetLeft + "px"; this.tweens[0].tweenData.tweenedProperties["width"] = this.animatedElement.offsetWidth + "px"; this.tweens[0].tweenData.tweenedProperties["height"] = this.animatedElement.offsetHeight + "px"; var animationDuration = Math.round(this.trackDuration / 1000) + "s"; this.animationName = this.animatedElement.classList[0] + "_PositionSize"; if(this.animationNamesString.length == 0){ this.animationNamesString = this.animationName; } else { this.animationNamesString = this.animationName + ", " + this.animationNamesString; } this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-name", this.animationNamesString); this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-duration", animationDuration); this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-fill-mode", "forwards"); this.ninjaStylesContoller.setElementStyle(this.animatedElement, "-webkit-animation-iteration-count", 1); var initRule = "@-webkit-keyframes " + this.animationName + " { 0% {top: " + this.animatedElement.offsetTop + "px; left: " + this.animatedElement.offsetLeft + "px;} 100% {top: " + this.animatedElement.offsetTop + "px; left: " + this.animatedElement.offsetLeft + "px;} }"; this.currentKeyframeRule = this.ninjaStylesContoller.addRule(initRule); this.insertTween(tweenEvent.offsetX); this.isTrackAnimated = true; } }, updateKeyframeRule:{ value:function () { this.ninjaStylesContoller.deleteRule(this.currentKeyframeRule); var keyframeString = "@-webkit-keyframes " + this.animationName + " {"; for (var i = 0; i < this.tweens.length; i++) { var keyMill = parseInt(this.tweens[i].tweenData.keyFrameMillisec); // trackDur should be parseFloat rounded to significant digits var trackDur = parseInt(this.trackDuration); var keyframePercent = Math.round((keyMill / trackDur) * 100) + "%"; var keyframePropertyString = " " + keyframePercent + " {"; for(var prop in this.tweens[i].tweenData.tweenedProperties){ keyframePropertyString += prop + ": " + this.tweens[i].tweenData.tweenedProperties[prop] + ";"; } keyframePropertyString += "}"; keyframeString += keyframePropertyString; } keyframeString += " }"; this.currentKeyframeRule = this.ninjaStylesContoller.addRule(keyframeString); this.application.ninja.currentDocument.model.needsSave = true; } }, createMatchingPositionSizeTween:{ value:function (newTween) { var i; var posTracks = this.positionTracksRepetition.childComponents.length; for (i = 0; i < posTracks; i++) { this.positionTracksRepetition.childComponents[i].propTweens.push(newTween); } } }, findXOffset:{ value:function (obj) { var curleft = 0; if (typeof(obj) === "undefined") { } if (obj.offsetParent) { do { curleft += (obj.offsetLeft - obj.scrollLeft); } while (obj = obj.offsetParent); } return curleft; } }, getTweenIndexById: { value: function(intID) { var i = 0, arrTweensLength = this.tweens.length; for (i = 0; i < arrTweensLength; i++) { if (this.tweens[i].tweenData.tweenID === intID) { returnVal = i; } } return returnVal; } } // ==== End Controllers });