mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-18 05:18:39 +08:00
implemented CSS animations
fixing animation tests
This commit is contained in:
@ -87,7 +87,7 @@ allTests["SEARCH-BAR"] = require('./ui/search-bar/search-bar-tests');
|
|||||||
allTests["CONNECTIVITY"] = require("./connectivity-tests");
|
allTests["CONNECTIVITY"] = require("./connectivity-tests");
|
||||||
allTests["SEGMENTED-BAR"] = require("./ui/segmented-bar/segmented-bar-tests");
|
allTests["SEGMENTED-BAR"] = require("./ui/segmented-bar/segmented-bar-tests");
|
||||||
allTests["ANIMATION"] = require("./ui/animation/animation-tests");
|
allTests["ANIMATION"] = require("./ui/animation/animation-tests");
|
||||||
|
allTests["CSS-ANIMATION"] = require("./ui/animation/css-animation-tests");
|
||||||
if (!isRunningOnEmulator()) {
|
if (!isRunningOnEmulator()) {
|
||||||
allTests["LOCATION"] = require("./location-tests");
|
allTests["LOCATION"] = require("./location-tests");
|
||||||
}
|
}
|
||||||
|
302
apps/tests/ui/animation/css-animation-tests.ts
Normal file
302
apps/tests/ui/animation/css-animation-tests.ts
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
import TKUnit = require("../../TKUnit");
|
||||||
|
import page = require("ui/page");
|
||||||
|
import styleScope = require("ui/styling/style-scope");
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
import enums = require("ui/enums");
|
||||||
|
import helper = require("../../ui/helper");
|
||||||
|
import stackModule = require("ui/layouts/stack-layout");
|
||||||
|
import labelModule = require("ui/label");
|
||||||
|
import color = require("color");
|
||||||
|
import selectorModule = require("ui/styling/css-selector");
|
||||||
|
|
||||||
|
function createAnimationFromCSS(css: string, name: string): keyframeAnimation.KeyframeAnimationInfo {
|
||||||
|
let scope = new styleScope.StyleScope();
|
||||||
|
scope.css = css;
|
||||||
|
scope.ensureSelectors();
|
||||||
|
let selector = findSelectorInScope(scope, name);
|
||||||
|
if (selector !== undefined) {
|
||||||
|
let animation = selector.animations[0];
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findSelectorInScope(scope: styleScope.StyleScope, name: string): selectorModule.CssSelector {
|
||||||
|
let selector = undefined;
|
||||||
|
for (let sel of (<any>scope)._mergedCssSelectors) {
|
||||||
|
if (sel.expression === name) {
|
||||||
|
selector = sel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.test_ReadAnimationProperties = function () {
|
||||||
|
let css = ".test { " +
|
||||||
|
"animation-name: first; " +
|
||||||
|
"animation-duration: 4s; " +
|
||||||
|
"animation-timing-function: ease-in; " +
|
||||||
|
"animation-delay: 1.5; " +
|
||||||
|
"animation-iteration-count: 10; " +
|
||||||
|
"animation-direction: reverse; " +
|
||||||
|
"animation-fill-mode: forwards; " +
|
||||||
|
" }";
|
||||||
|
let animation = createAnimationFromCSS(css, "test");
|
||||||
|
TKUnit.assertEqual(animation.name, "first");
|
||||||
|
TKUnit.assertEqual(animation.duration, 4000);
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.easeIn);
|
||||||
|
TKUnit.assertEqual(animation.delay, 1500);
|
||||||
|
TKUnit.assertEqual(animation.iterations, 10);
|
||||||
|
TKUnit.assertTrue(animation.isForwards);
|
||||||
|
TKUnit.assertTrue(animation.isReverse);
|
||||||
|
};
|
||||||
|
exports.test_ReadTheAnimationProperty = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation: second 0.2s ease-out 1 2 }", "test");
|
||||||
|
TKUnit.assertEqual(animation.name, "second");
|
||||||
|
TKUnit.assertEqual(animation.duration, 200);
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.easeOut);
|
||||||
|
TKUnit.assertEqual(animation.delay, 1000);
|
||||||
|
TKUnit.assertEqual(animation.iterations, 2);
|
||||||
|
};
|
||||||
|
exports.test_ReadAnimationCurve = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-timing-function: ease-in; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.easeIn);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-timing-function: ease-out; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.easeOut);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-timing-function: linear; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.linear);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-timing-function: ease-in-out; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.easeInOut);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-timing-function: spring; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.curve, enums.AnimationCurve.spring);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-timing-function: cubic-bezier(0.1, 1.0, 0.5, 0.5); }", "test");
|
||||||
|
let curve = animation.curve;
|
||||||
|
TKUnit.assert(curve.x1 === 0.1 && curve.y1 === 1.0 && curve.x2 === 0.5 && curve.y2 === 0.5);
|
||||||
|
};
|
||||||
|
exports.test_ReadIterations = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-iteration-count: 5; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.iterations, 5);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-iteration-count: infinite; }", "test");
|
||||||
|
TKUnit.assertEqual(animation.iterations, Number.MAX_VALUE);
|
||||||
|
};
|
||||||
|
exports.test_ReadFillMode = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-iteration-count: 5; }", "test");
|
||||||
|
TKUnit.assertFalse(animation.isForwards);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-fill-mode: forwards; }", "test");
|
||||||
|
TKUnit.assertTrue(animation.isForwards);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-fill-mode: backwards; }", "test");
|
||||||
|
TKUnit.assertFalse(animation.isForwards);
|
||||||
|
};
|
||||||
|
exports.test_ReadDirection = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-iteration-count: 5; }", "test");
|
||||||
|
TKUnit.assertFalse(animation.isReverse);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-direction: reverse; }", "test");
|
||||||
|
TKUnit.assertTrue(animation.isReverse);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-direction: normal; }", "test");
|
||||||
|
TKUnit.assertFalse(animation.isReverse);
|
||||||
|
};
|
||||||
|
exports.test_ReadKeyframe = function () {
|
||||||
|
let scope = new styleScope.StyleScope();
|
||||||
|
scope.css = ".test { animation-name: test; } @keyframes test { from { background-color: red; } to { background-color: blue; } }";
|
||||||
|
scope.ensureSelectors();
|
||||||
|
let selector = findSelectorInScope(scope, "test");
|
||||||
|
TKUnit.assert(selector !== undefined, "CSS selector was not created!");
|
||||||
|
let animation = selector.animations[0];
|
||||||
|
TKUnit.assertEqual(animation.name, "test", "Wrong animation name!");
|
||||||
|
TKUnit.assertEqual(animation.keyframes.length, 2, "Keyframes not parsed correctly!");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].duration, 0, "First keyframe duration should be 0");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].duration, 1, "Second keyframe duration should be 1");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations.length, 1, "Keyframe declarations are not correct");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "backgroundColor", "Keyframe declarations are not correct");
|
||||||
|
};
|
||||||
|
exports.test_ReadScale = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: scaleX(5),scaleY(10); } }", "test");
|
||||||
|
let scale = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "scale");
|
||||||
|
TKUnit.assert(scale.x === 5 && scale.y === 10);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: scale(-5, 12.3pt); } }", "test");
|
||||||
|
scale = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "scale");
|
||||||
|
TKUnit.assert(scale.x === -5 && scale.y === 12.3);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: scaleY(10); } }", "test");
|
||||||
|
scale = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "scale");
|
||||||
|
TKUnit.assert(scale.x === 1 && scale.y === 10);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: scale3d(10, 20, 30); } }", "test");
|
||||||
|
scale = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "scale");
|
||||||
|
TKUnit.assert(scale.x === 10 && scale.y === 20);
|
||||||
|
};
|
||||||
|
exports.test_ReadTranslate = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: translateX(5),translateY(10); } }", "test");
|
||||||
|
let translate = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "translate");
|
||||||
|
TKUnit.assert(translate.x === 5 && translate.y === 10);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: translate(-5, 12.3pt); } }", "test");
|
||||||
|
translate = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "translate");
|
||||||
|
TKUnit.assert(translate.x === -5 && translate.y === 12.3);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: translateX(10); } }", "test");
|
||||||
|
translate = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "translate");
|
||||||
|
TKUnit.assert(translate.x === 10 && translate.y === 0);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: translate3d(10, 20, 30); } }", "test");
|
||||||
|
translate = animation.keyframes[0].declarations[0].value;
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "translate");
|
||||||
|
TKUnit.assert(translate.x === 10 && translate.y === 20);
|
||||||
|
};
|
||||||
|
exports.test_ReadRotate = function () {
|
||||||
|
let animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: rotate(5); } }", "test");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "rotate");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].value, 5);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: rotate(45deg); } }", "test");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "rotate");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].value, 45);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: rotate(0.7853981634rad); } }", "test");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].property, "rotate");
|
||||||
|
TKUnit.assertTrue(animation.keyframes[0].declarations[0].value - 45 < 0.1);
|
||||||
|
};
|
||||||
|
exports.test_ReadTransform = function () {
|
||||||
|
let css = ".test { animation-name: test; } @keyframes test { to { transform: rotate(10),scaleX(5),translate(2,4); } }";
|
||||||
|
let animation = createAnimationFromCSS(css, "test");
|
||||||
|
let rotate = animation.keyframes[0].declarations[0].value;
|
||||||
|
let scale = animation.keyframes[0].declarations[1].value;
|
||||||
|
let translate = animation.keyframes[0].declarations[2].value;
|
||||||
|
TKUnit.assertEqual(rotate, 10);
|
||||||
|
TKUnit.assert(scale.x === 5 && scale.y === 1);
|
||||||
|
TKUnit.assert(translate.x === 2 && translate.y === 4);
|
||||||
|
animation = createAnimationFromCSS(".test { animation-name: test; } @keyframes test { to { transform: none; } }", "test");
|
||||||
|
rotate = animation.keyframes[0].declarations[0].value;
|
||||||
|
scale = animation.keyframes[0].declarations[1].value;
|
||||||
|
translate = animation.keyframes[0].declarations[2].value;
|
||||||
|
TKUnit.assertEqual(rotate, 0);
|
||||||
|
TKUnit.assert(scale.x === 1 && scale.y === 1);
|
||||||
|
TKUnit.assert(translate.x === 0 && translate.y === 0);
|
||||||
|
};
|
||||||
|
exports.test_ReadAnimationWithUnsortedKeyframes = function () {
|
||||||
|
let css = ".test { animation-name: test; } " +
|
||||||
|
"@keyframes test { " +
|
||||||
|
"from { opacity: 0; } " +
|
||||||
|
"20%, 60% { opacity: 0.5; } " +
|
||||||
|
"40%, 80% { opacity: 0.3; } " +
|
||||||
|
"to { opacity: 1; } " +
|
||||||
|
"}";
|
||||||
|
let animation = createAnimationFromCSS(css, "test");
|
||||||
|
TKUnit.assertEqual(animation.keyframes.length, 6);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].declarations[0].value, 0);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].declarations[0].value, 0.5);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[2].declarations[0].value, 0.3);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[3].declarations[0].value, 0.5);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[4].declarations[0].value, 0.3);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[5].declarations[0].value, 1);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].duration, 0);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].duration, 0.2);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[2].duration, 0.4);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[3].duration, 0.6);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[4].duration, 0.8);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[5].duration, 1);
|
||||||
|
};
|
||||||
|
exports.test_ReadAnimationsWithCSSImport = function () {
|
||||||
|
let css = "@import '~/ui/animation/test.css'; .test { animation-name: test; }";
|
||||||
|
let animation = createAnimationFromCSS(css, "test");
|
||||||
|
TKUnit.assertEqual(animation.keyframes.length, 3);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].declarations[0].property, "backgroundColor");
|
||||||
|
};
|
||||||
|
exports.test_LoadTwoAnimationsWithTheSameName = function () {
|
||||||
|
let scope = new styleScope.StyleScope();
|
||||||
|
scope.css = "@keyframes a1 { from { opacity: 0; } to { opacity: 1; } } @keyframes a1 { from { opacity: 0; } to { opacity: 0.5; } } .a { animation-name: a1; }";
|
||||||
|
scope.ensureSelectors();
|
||||||
|
let selector = findSelectorInScope(scope, "a");
|
||||||
|
let animation = selector.animations[0];
|
||||||
|
TKUnit.assertEqual(animation.keyframes.length, 2);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].declarations[0].value, 0.5);
|
||||||
|
scope = new styleScope.StyleScope();
|
||||||
|
scope.css = "@keyframes k { from { opacity: 0; } to { opacity: 1; } } .a { animation-name: k; animation-duration: 2; } .a { animation-name: k; animation-duration: 3; }";
|
||||||
|
scope.ensureSelectors();
|
||||||
|
selector = findSelectorInScope(scope, "a");
|
||||||
|
TKUnit.assertEqual(selector.animations[0].keyframes.length, 2);
|
||||||
|
TKUnit.assertEqual(selector.animations[0].keyframes.length, 2);
|
||||||
|
};
|
||||||
|
exports.test_LoadAnimationProgrammatically = function () {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
helper.buildUIAndRunTest(stack, function (views) {
|
||||||
|
let page = views[1];
|
||||||
|
page.css = "@keyframes a { from { opacity: 1; } to { opacity: 0; } }";
|
||||||
|
let animation = page.getKeyframeAnimationWithName("a");
|
||||||
|
TKUnit.assertEqual(animation.keyframes.length, 2);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].declarations[0].property, "opacity");
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].declarations[0].value, 0);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
exports.test_ExecuteCSSAnimation = function () {
|
||||||
|
let mainPage;
|
||||||
|
let label;
|
||||||
|
let pageFactory = function () {
|
||||||
|
label = new labelModule.Label();
|
||||||
|
label.text = "label";
|
||||||
|
let stackLayout = new stackModule.StackLayout();
|
||||||
|
stackLayout.addChild(label);
|
||||||
|
mainPage = new page.Page();
|
||||||
|
mainPage.css = "@keyframes k { from { background-color: red; } to { background-color: green; } } .l { animation-name: k; animation-duration: 0.5s; animation-fill-mode: forwards; }";
|
||||||
|
mainPage.content = stackLayout;
|
||||||
|
return mainPage;
|
||||||
|
};
|
||||||
|
helper.navigate(pageFactory);
|
||||||
|
TKUnit.waitUntilReady(function () { return label.isLoaded; });
|
||||||
|
label.className = "l";
|
||||||
|
TKUnit.waitUntilReady(function () { return new color.Color("green").equals(label.backgroundColor); }, 1);
|
||||||
|
TKUnit.assert(new color.Color("green").equals(label.backgroundColor));
|
||||||
|
helper.goBack();
|
||||||
|
};
|
||||||
|
exports.test_ExecuteFillMode = function () {
|
||||||
|
let mainPage;
|
||||||
|
let label;
|
||||||
|
let pageFactory = function () {
|
||||||
|
label = new labelModule.Label();
|
||||||
|
label.text = "label";
|
||||||
|
let stackLayout = new stackModule.StackLayout();
|
||||||
|
stackLayout.addChild(label);
|
||||||
|
mainPage = new page.Page();
|
||||||
|
mainPage.css = "@keyframes k { from { background-color: red; } to { background-color: green; } } " +
|
||||||
|
".l { animation-name: k; animation-duration: 0.5s; animation-fill-mode: none; } " +
|
||||||
|
".l2 { animation-name: k; animation-duration: 0.5s; animation-fill-mode: forwards; }";
|
||||||
|
mainPage.content = stackLayout;
|
||||||
|
return mainPage;
|
||||||
|
};
|
||||||
|
helper.navigate(pageFactory);
|
||||||
|
TKUnit.waitUntilReady(function () { return label.isLoaded; });
|
||||||
|
TKUnit.assertEqual(label.backgroundColor, undefined);
|
||||||
|
label.className = "l";
|
||||||
|
TKUnit.wait(2);
|
||||||
|
TKUnit.assertEqual(label.backgroundColor, undefined);
|
||||||
|
label.className = "l2";
|
||||||
|
TKUnit.waitUntilReady(function() { return new color.Color("green").equals(label.backgroundColor); }, 1);
|
||||||
|
TKUnit.assert(new color.Color("green").equals(label.backgroundColor));
|
||||||
|
helper.goBack();
|
||||||
|
helper.goBack();
|
||||||
|
};
|
||||||
|
exports.test_ReadTwoAnimations = function () {
|
||||||
|
let scope = new styleScope.StyleScope();
|
||||||
|
scope.css = ".test { animation: one 0.2s ease-out 1 2, two 2s ease-in; }";
|
||||||
|
scope.ensureSelectors();
|
||||||
|
let selector = findSelectorInScope(scope, "test");
|
||||||
|
TKUnit.assertEqual(selector.animations.length, 2);
|
||||||
|
TKUnit.assertEqual(selector.animations[0].curve, enums.AnimationCurve.easeOut);
|
||||||
|
TKUnit.assertEqual(selector.animations[1].curve, enums.AnimationCurve.easeIn);
|
||||||
|
TKUnit.assertEqual(selector.animations[1].name, "two");
|
||||||
|
TKUnit.assertEqual(selector.animations[1].duration, 2000);
|
||||||
|
};
|
||||||
|
exports.test_AnimationCurveInKeyframes = function () {
|
||||||
|
let scope = new styleScope.StyleScope();
|
||||||
|
scope.css = "@keyframes an { from { animation-timing-function: linear; background-color: red; } 50% { background-color: green; } to { background-color: black; } } .test { animation-name: an; animation-timing-function: ease-in; }";
|
||||||
|
scope.ensureSelectors();
|
||||||
|
let selector = findSelectorInScope(scope, "test");
|
||||||
|
let animation = selector.animations[0];
|
||||||
|
TKUnit.assertEqual(animation.keyframes[0].curve, enums.AnimationCurve.linear);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].curve, undefined);
|
||||||
|
TKUnit.assertEqual(animation.keyframes[1].curve, undefined);
|
||||||
|
let realAnimation = keyframeAnimation.KeyframeAnimation.keyframeAnimationFromInfo(animation, 2);
|
||||||
|
TKUnit.assertEqual(realAnimation.animations[1].curve, enums.AnimationCurve.linear);
|
||||||
|
TKUnit.assertEqual(realAnimation.animations[2].curve, enums.AnimationCurve.easeIn);
|
||||||
|
};
|
5
apps/tests/ui/animation/test.css
Normal file
5
apps/tests/ui/animation/test.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@keyframes test {
|
||||||
|
from { background-color: red; }
|
||||||
|
50% { background-color: yellow; }
|
||||||
|
to { background-color: green; }
|
||||||
|
}
|
@ -179,7 +179,6 @@ export var test_isAddedToNativeVisualTree_IsUpdated = function () {
|
|||||||
|
|
||||||
views[1]._addView(newButton);
|
views[1]._addView(newButton);
|
||||||
TKUnit.assert(newButton._isAddedToNativeVisualTree);
|
TKUnit.assert(newButton._isAddedToNativeVisualTree);
|
||||||
|
|
||||||
views[1]._removeView(newButton);
|
views[1]._removeView(newButton);
|
||||||
TKUnit.assert(!newButton._isAddedToNativeVisualTree);
|
TKUnit.assert(!newButton._isAddedToNativeVisualTree);
|
||||||
}
|
}
|
||||||
|
@ -233,6 +233,7 @@
|
|||||||
"apps/tests/ui/action-bar/action-bar-tests.ios.ts",
|
"apps/tests/ui/action-bar/action-bar-tests.ios.ts",
|
||||||
"apps/tests/ui/activity-indicator/activity-indicator-tests.ts",
|
"apps/tests/ui/activity-indicator/activity-indicator-tests.ts",
|
||||||
"apps/tests/ui/animation/animation-tests.ts",
|
"apps/tests/ui/animation/animation-tests.ts",
|
||||||
|
"apps/tests/ui/animation/css-animation-tests.ts",
|
||||||
"apps/tests/ui/bindable-tests.ts",
|
"apps/tests/ui/bindable-tests.ts",
|
||||||
"apps/tests/ui/binding-expressions-tests.ts",
|
"apps/tests/ui/binding-expressions-tests.ts",
|
||||||
"apps/tests/ui/bindingContext_testPage.ts",
|
"apps/tests/ui/bindingContext_testPage.ts",
|
||||||
@ -498,6 +499,8 @@
|
|||||||
"ui/animation/animation.android.ts",
|
"ui/animation/animation.android.ts",
|
||||||
"ui/animation/animation.d.ts",
|
"ui/animation/animation.d.ts",
|
||||||
"ui/animation/animation.ios.ts",
|
"ui/animation/animation.ios.ts",
|
||||||
|
"ui/animation/keyframe-animation.d.ts",
|
||||||
|
"ui/animation/keyframe-animation.ts",
|
||||||
"ui/border/border.d.ts",
|
"ui/border/border.d.ts",
|
||||||
"ui/border/border.ts",
|
"ui/border/border.ts",
|
||||||
"ui/builder/binding-builder.d.ts",
|
"ui/builder/binding-builder.d.ts",
|
||||||
|
@ -5,18 +5,19 @@ import color = require("color");
|
|||||||
import trace = require("trace");
|
import trace = require("trace");
|
||||||
import types = require("utils/types");
|
import types = require("utils/types");
|
||||||
import enums = require("ui/enums");
|
import enums = require("ui/enums");
|
||||||
|
import styleModule = require("ui/styling/style");
|
||||||
|
|
||||||
global.moduleMerge(common, exports);
|
global.moduleMerge(common, exports);
|
||||||
|
|
||||||
var argbEvaluator: android.animation.ArgbEvaluator;
|
let argbEvaluator: android.animation.ArgbEvaluator;
|
||||||
function ensureArgbEvaluator() {
|
function ensureArgbEvaluator() {
|
||||||
if (!argbEvaluator) {
|
if (!argbEvaluator) {
|
||||||
argbEvaluator = new android.animation.ArgbEvaluator();
|
argbEvaluator = new android.animation.ArgbEvaluator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyPrefix = "ui.animation.";
|
let keyPrefix = "ui.animation.";
|
||||||
var propertyKeys = {};
|
let propertyKeys = {};
|
||||||
propertyKeys[common.Properties.backgroundColor] = Symbol(keyPrefix + common.Properties.backgroundColor);
|
propertyKeys[common.Properties.backgroundColor] = Symbol(keyPrefix + common.Properties.backgroundColor);
|
||||||
propertyKeys[common.Properties.opacity] = Symbol(keyPrefix + common.Properties.opacity);
|
propertyKeys[common.Properties.opacity] = Symbol(keyPrefix + common.Properties.opacity);
|
||||||
propertyKeys[common.Properties.rotate] = Symbol(keyPrefix + common.Properties.rotate);
|
propertyKeys[common.Properties.rotate] = Symbol(keyPrefix + common.Properties.rotate);
|
||||||
@ -30,12 +31,13 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
private _animators: Array<android.animation.Animator>;
|
private _animators: Array<android.animation.Animator>;
|
||||||
private _propertyUpdateCallbacks: Array<Function>;
|
private _propertyUpdateCallbacks: Array<Function>;
|
||||||
private _propertyResetCallbacks: Array<Function>;
|
private _propertyResetCallbacks: Array<Function>;
|
||||||
|
private _valueSource: number;
|
||||||
|
|
||||||
public play(): definition.AnimationPromise {
|
public play(): definition.AnimationPromise {
|
||||||
var animationFinishedPromise = super.play();
|
var animationFinishedPromise = super.play();
|
||||||
|
|
||||||
var i: number;
|
let i: number;
|
||||||
var length: number;
|
let length: number;
|
||||||
|
|
||||||
this._animators = new Array<android.animation.Animator>();
|
this._animators = new Array<android.animation.Animator>();
|
||||||
this._propertyUpdateCallbacks = new Array<Function>();
|
this._propertyUpdateCallbacks = new Array<Function>();
|
||||||
@ -78,7 +80,11 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
constructor(animationDefinitions: Array<definition.AnimationDefinition>, playSequentially?: boolean) {
|
constructor(animationDefinitions: Array<definition.AnimationDefinition>, playSequentially?: boolean) {
|
||||||
super(animationDefinitions, playSequentially);
|
super(animationDefinitions, playSequentially);
|
||||||
|
|
||||||
var that = this;
|
if (animationDefinitions.length > 0 && (<any>animationDefinitions[0]).valueSource !== undefined) {
|
||||||
|
this._valueSource = (<any>animationDefinitions[0]).valueSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
let that = this;
|
||||||
this._animatorListener = new android.animation.Animator.AnimatorListener({
|
this._animatorListener = new android.animation.Animator.AnimatorListener({
|
||||||
onAnimationStart: function (animator: android.animation.Animator): void {
|
onAnimationStart: function (animator: android.animation.Animator): void {
|
||||||
trace.write("MainAnimatorListener.onAndroidAnimationStart(" + animator +")", trace.categories.Animation);
|
trace.write("MainAnimatorListener.onAndroidAnimationStart(" + animator +")", trace.categories.Animation);
|
||||||
@ -103,8 +109,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = 0;
|
let i = 0;
|
||||||
var length = this._propertyUpdateCallbacks.length;
|
let length = this._propertyUpdateCallbacks.length;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
this._propertyUpdateCallbacks[i]();
|
this._propertyUpdateCallbacks[i]();
|
||||||
}
|
}
|
||||||
@ -112,8 +118,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onAndroidAnimationCancel() {
|
private _onAndroidAnimationCancel() {
|
||||||
var i = 0;
|
let i = 0;
|
||||||
var length = this._propertyResetCallbacks.length;
|
let length = this._propertyResetCallbacks.length;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
this._propertyResetCallbacks[i]();
|
this._propertyResetCallbacks[i]();
|
||||||
}
|
}
|
||||||
@ -135,18 +141,18 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
throw new Error("Animation value cannot be null or undefined!");
|
throw new Error("Animation value cannot be null or undefined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
var nativeArray;
|
let nativeArray;
|
||||||
var nativeView: android.view.View = (<android.view.View>propertyAnimation.target._nativeView);
|
let nativeView: android.view.View = (<android.view.View>propertyAnimation.target._nativeView);
|
||||||
var animators = new Array<android.animation.Animator>();
|
let animators = new Array<android.animation.Animator>();
|
||||||
var propertyUpdateCallbacks = new Array<Function>();
|
let propertyUpdateCallbacks = new Array<Function>();
|
||||||
var propertyResetCallbacks = new Array<Function>();
|
let propertyResetCallbacks = new Array<Function>();
|
||||||
var originalValue1;
|
let originalValue1;
|
||||||
var originalValue2;
|
let originalValue2;
|
||||||
var density = utils.layout.getDisplayDensity();
|
let density = utils.layout.getDisplayDensity();
|
||||||
var xyObjectAnimators: any;
|
let xyObjectAnimators: any;
|
||||||
var animatorSet: android.animation.AnimatorSet;
|
let animatorSet: android.animation.AnimatorSet;
|
||||||
|
|
||||||
var key = propertyKeys[propertyAnimation.property];
|
let key = propertyKeys[propertyAnimation.property];
|
||||||
if (key) {
|
if (key) {
|
||||||
propertyAnimation.target[key] = propertyAnimation;
|
propertyAnimation.target[key] = propertyAnimation;
|
||||||
}
|
}
|
||||||
@ -159,13 +165,22 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let valueSource = this._valueSource;
|
||||||
|
|
||||||
switch (propertyAnimation.property) {
|
switch (propertyAnimation.property) {
|
||||||
|
|
||||||
case common.Properties.opacity:
|
case common.Properties.opacity:
|
||||||
originalValue1 = nativeView.getAlpha();
|
originalValue1 = nativeView.getAlpha();
|
||||||
nativeArray = (<any>Array).create("float", 1);
|
nativeArray = (<any>Array).create("float", 1);
|
||||||
nativeArray[0] = propertyAnimation.value;
|
nativeArray[0] = propertyAnimation.value;
|
||||||
propertyUpdateCallbacks.push(checkAnimation(() => { propertyAnimation.target.opacity = propertyAnimation.value }));
|
if (this._valueSource !== undefined) {
|
||||||
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.opacityProperty, propertyAnimation.value, valueSource);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
propertyUpdateCallbacks.push(checkAnimation(() => { propertyAnimation.target.opacity = propertyAnimation.value; }));
|
||||||
|
}
|
||||||
propertyResetCallbacks.push(checkAnimation(() => { nativeView.setAlpha(originalValue1); }));
|
propertyResetCallbacks.push(checkAnimation(() => { nativeView.setAlpha(originalValue1); }));
|
||||||
animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "alpha", nativeArray));
|
animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "alpha", nativeArray));
|
||||||
break;
|
break;
|
||||||
@ -176,15 +191,23 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
nativeArray = (<any>Array).create(java.lang.Object, 2);
|
nativeArray = (<any>Array).create(java.lang.Object, 2);
|
||||||
nativeArray[0] = propertyAnimation.target.backgroundColor ? java.lang.Integer.valueOf((<color.Color>propertyAnimation.target.backgroundColor).argb) : java.lang.Integer.valueOf(-1);
|
nativeArray[0] = propertyAnimation.target.backgroundColor ? java.lang.Integer.valueOf((<color.Color>propertyAnimation.target.backgroundColor).argb) : java.lang.Integer.valueOf(-1);
|
||||||
nativeArray[1] = java.lang.Integer.valueOf((<color.Color>propertyAnimation.value).argb);
|
nativeArray[1] = java.lang.Integer.valueOf((<color.Color>propertyAnimation.value).argb);
|
||||||
var animator = android.animation.ValueAnimator.ofObject(argbEvaluator, nativeArray);
|
let animator = android.animation.ValueAnimator.ofObject(argbEvaluator, nativeArray);
|
||||||
animator.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener({
|
animator.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener({
|
||||||
onAnimationUpdate(animator: android.animation.ValueAnimator) {
|
onAnimationUpdate(animator: android.animation.ValueAnimator) {
|
||||||
var argb = (<java.lang.Integer>animator.getAnimatedValue()).intValue();
|
let argb = (<java.lang.Integer>animator.getAnimatedValue()).intValue();
|
||||||
propertyAnimation.target.backgroundColor = new color.Color(argb);
|
propertyAnimation.target.style._setValue(styleModule.backgroundColorProperty, new color.Color(argb), valueSource);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (this._valueSource !== undefined) {
|
||||||
|
let valueSource = this._valueSource;
|
||||||
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.backgroundColorProperty, propertyAnimation.value, valueSource);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
propertyUpdateCallbacks.push(checkAnimation(() => { propertyAnimation.target.backgroundColor = propertyAnimation.value; }));
|
propertyUpdateCallbacks.push(checkAnimation(() => { propertyAnimation.target.backgroundColor = propertyAnimation.value; }));
|
||||||
|
}
|
||||||
propertyResetCallbacks.push(checkAnimation(() => { nativeView.setBackground(originalValue1); }));
|
propertyResetCallbacks.push(checkAnimation(() => { nativeView.setBackground(originalValue1); }));
|
||||||
animators.push(animator);
|
animators.push(animator);
|
||||||
break;
|
break;
|
||||||
@ -205,10 +228,18 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
originalValue1 = nativeView.getTranslationX();
|
originalValue1 = nativeView.getTranslationX();
|
||||||
originalValue2 = nativeView.getTranslationY();
|
originalValue2 = nativeView.getTranslationY();
|
||||||
|
|
||||||
|
if (this._valueSource !== undefined) {
|
||||||
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.translateXProperty, propertyAnimation.value.x, valueSource);
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.translateYProperty, propertyAnimation.value.y, valueSource);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
propertyAnimation.target.translateX = propertyAnimation.value.x;
|
propertyAnimation.target.translateX = propertyAnimation.value.x;
|
||||||
propertyAnimation.target.translateY = propertyAnimation.value.y;
|
propertyAnimation.target.translateY = propertyAnimation.value.y;
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
propertyResetCallbacks.push(checkAnimation(() => {
|
propertyResetCallbacks.push(checkAnimation(() => {
|
||||||
nativeView.setTranslationX(originalValue1);
|
nativeView.setTranslationX(originalValue1);
|
||||||
@ -237,10 +268,18 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
originalValue1 = nativeView.getScaleX();
|
originalValue1 = nativeView.getScaleX();
|
||||||
originalValue2 = nativeView.getScaleY();
|
originalValue2 = nativeView.getScaleY();
|
||||||
|
|
||||||
|
if (this._valueSource !== undefined) {
|
||||||
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.scaleXProperty, propertyAnimation.value.x, valueSource);
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.scaleYProperty, propertyAnimation.value.y, valueSource);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
propertyAnimation.target.scaleX = propertyAnimation.value.x;
|
propertyAnimation.target.scaleX = propertyAnimation.value.x;
|
||||||
propertyAnimation.target.scaleY = propertyAnimation.value.y;
|
propertyAnimation.target.scaleY = propertyAnimation.value.y;
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
propertyResetCallbacks.push(checkAnimation(() => {
|
propertyResetCallbacks.push(checkAnimation(() => {
|
||||||
nativeView.setScaleY(originalValue1);
|
nativeView.setScaleY(originalValue1);
|
||||||
@ -257,7 +296,14 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
originalValue1 = nativeView.getRotation();
|
originalValue1 = nativeView.getRotation();
|
||||||
nativeArray = (<any>Array).create("float", 1);
|
nativeArray = (<any>Array).create("float", 1);
|
||||||
nativeArray[0] = propertyAnimation.value;
|
nativeArray[0] = propertyAnimation.value;
|
||||||
|
if (this._valueSource !== undefined) {
|
||||||
|
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||||
|
propertyAnimation.target.style._setValue(styleModule.rotateProperty, propertyAnimation.value, valueSource);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
propertyUpdateCallbacks.push(checkAnimation(() => { propertyAnimation.target.rotate = propertyAnimation.value; }));
|
propertyUpdateCallbacks.push(checkAnimation(() => { propertyAnimation.target.rotate = propertyAnimation.value; }));
|
||||||
|
}
|
||||||
propertyResetCallbacks.push(checkAnimation(() => { nativeView.setRotation(originalValue1); }));
|
propertyResetCallbacks.push(checkAnimation(() => { nativeView.setRotation(originalValue1); }));
|
||||||
animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "rotation", nativeArray));
|
animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "rotation", nativeArray));
|
||||||
break;
|
break;
|
||||||
@ -266,8 +312,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
throw new Error("Cannot animate " + propertyAnimation.property);
|
throw new Error("Cannot animate " + propertyAnimation.property);
|
||||||
}
|
}
|
||||||
|
|
||||||
var i = 0;
|
let i = 0;
|
||||||
var length = animators.length;
|
let length = animators.length;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
|
|
||||||
// Duration
|
// Duration
|
||||||
@ -302,11 +348,11 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var easeIn = new android.view.animation.AccelerateInterpolator(1);
|
let easeIn = new android.view.animation.AccelerateInterpolator(1);
|
||||||
var easeOut = new android.view.animation.DecelerateInterpolator(1);
|
let easeOut = new android.view.animation.DecelerateInterpolator(1);
|
||||||
var easeInOut = new android.view.animation.AccelerateDecelerateInterpolator();
|
let easeInOut = new android.view.animation.AccelerateDecelerateInterpolator();
|
||||||
var linear = new android.view.animation.LinearInterpolator();
|
let linear = new android.view.animation.LinearInterpolator();
|
||||||
var bounce = new android.view.animation.BounceInterpolator();
|
let bounce = new android.view.animation.BounceInterpolator();
|
||||||
export function _resolveAnimationCurve(curve: any): any {
|
export function _resolveAnimationCurve(curve: any): any {
|
||||||
switch (curve) {
|
switch (curve) {
|
||||||
case enums.AnimationCurve.easeIn:
|
case enums.AnimationCurve.easeIn:
|
||||||
@ -324,11 +370,13 @@ export function _resolveAnimationCurve(curve: any): any {
|
|||||||
case enums.AnimationCurve.spring:
|
case enums.AnimationCurve.spring:
|
||||||
trace.write("Animation curve resolved to android.view.animation.BounceInterpolator().", trace.categories.Animation);
|
trace.write("Animation curve resolved to android.view.animation.BounceInterpolator().", trace.categories.Animation);
|
||||||
return bounce;
|
return bounce;
|
||||||
|
case enums.AnimationCurve.ease:
|
||||||
|
return (<any>android).support.v4.view.animation.PathInterpolatorCompat.create(0.25, 0.1, 0.25, 1.0);
|
||||||
default:
|
default:
|
||||||
trace.write("Animation curve resolved to original: " + curve, trace.categories.Animation);
|
trace.write("Animation curve resolved to original: " + curve, trace.categories.Animation);
|
||||||
if (curve instanceof common.CubicBezierAnimationCurve) {
|
if (curve instanceof common.CubicBezierAnimationCurve) {
|
||||||
var animationCurve = <common.CubicBezierAnimationCurve>curve;
|
let animationCurve = <common.CubicBezierAnimationCurve>curve;
|
||||||
var interpolator = (<any>android).support.v4.view.animation.PathInterpolatorCompat.create(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2);
|
let interpolator = (<any>android).support.v4.view.animation.PathInterpolatorCompat.create(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2);
|
||||||
return interpolator;
|
return interpolator;
|
||||||
}
|
}
|
||||||
return curve;
|
return curve;
|
||||||
|
@ -3,13 +3,15 @@ import common = require("./animation-common");
|
|||||||
import viewModule = require("ui/core/view");
|
import viewModule = require("ui/core/view");
|
||||||
import trace = require("trace");
|
import trace = require("trace");
|
||||||
import enums = require("ui/enums");
|
import enums = require("ui/enums");
|
||||||
|
import style = require("ui/styling/style");
|
||||||
|
import dependencyObservable = require("ui/core/dependency-observable");
|
||||||
|
|
||||||
global.moduleMerge(common, exports);
|
global.moduleMerge(common, exports);
|
||||||
|
|
||||||
var _transform = "_transform";
|
let _transform = "_transform";
|
||||||
var _skip = "_skip";
|
let _skip = "_skip";
|
||||||
|
|
||||||
var FLT_MAX = 340282346638528859811704183484516925440.000000;
|
let FLT_MAX = 340282346638528859811704183484516925440.000000;
|
||||||
|
|
||||||
declare var CASpringAnimation:any;
|
declare var CASpringAnimation:any;
|
||||||
|
|
||||||
@ -29,19 +31,54 @@ class AnimationDelegateImpl extends NSObject {
|
|||||||
|
|
||||||
private _finishedCallback: Function;
|
private _finishedCallback: Function;
|
||||||
private _propertyAnimation: common.PropertyAnimation;
|
private _propertyAnimation: common.PropertyAnimation;
|
||||||
|
private _valueSource: number;
|
||||||
|
|
||||||
public static initWithFinishedCallback(finishedCallback: Function, propertyAnimation: common.PropertyAnimation): AnimationDelegateImpl {
|
public static initWithFinishedCallback(finishedCallback: Function, propertyAnimation: common.PropertyAnimation, valueSource: number): AnimationDelegateImpl {
|
||||||
let delegate = <AnimationDelegateImpl>AnimationDelegateImpl.new();
|
let delegate = <AnimationDelegateImpl>AnimationDelegateImpl.new();
|
||||||
delegate._finishedCallback = finishedCallback;
|
delegate._finishedCallback = finishedCallback;
|
||||||
delegate._propertyAnimation = propertyAnimation;
|
delegate._propertyAnimation = propertyAnimation;
|
||||||
|
delegate._valueSource = valueSource;
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
animationDidStart(anim: CAAnimation): void {
|
animationDidStart(anim: CAAnimation): void {
|
||||||
var value = this._propertyAnimation.value;
|
let value = this._propertyAnimation.value;
|
||||||
|
|
||||||
(<any>this._propertyAnimation.target)._suspendPresentationLayerUpdates();
|
(<any>this._propertyAnimation.target)._suspendPresentationLayerUpdates();
|
||||||
|
|
||||||
|
if (this._valueSource !== undefined) {
|
||||||
|
let targetStyle = this._propertyAnimation.target.style;
|
||||||
|
switch (this._propertyAnimation.property) {
|
||||||
|
case common.Properties.backgroundColor:
|
||||||
|
targetStyle._setValue(style.backgroundColorProperty, value, this._valueSource);
|
||||||
|
break;
|
||||||
|
case common.Properties.opacity:
|
||||||
|
targetStyle._setValue(style.opacityProperty, value, this._valueSource);
|
||||||
|
break;
|
||||||
|
case common.Properties.rotate:
|
||||||
|
targetStyle._setValue(style.rotateProperty, value, this._valueSource);
|
||||||
|
break;
|
||||||
|
case common.Properties.translate:
|
||||||
|
targetStyle._setValue(style.translateXProperty, value.x, this._valueSource);
|
||||||
|
targetStyle._setValue(style.translateYProperty, value.y, this._valueSource);
|
||||||
|
break;
|
||||||
|
case common.Properties.scale:
|
||||||
|
targetStyle._setValue(style.scaleXProperty, value.x, this._valueSource);
|
||||||
|
targetStyle._setValue(style.scaleYProperty, value.y, this._valueSource);
|
||||||
|
break;
|
||||||
|
case _transform:
|
||||||
|
if (value[common.Properties.translate] !== undefined) {
|
||||||
|
targetStyle._setValue(style.translateXProperty, value[common.Properties.translate].x, this._valueSource);
|
||||||
|
targetStyle._setValue(style.translateYProperty, value[common.Properties.translate].y, this._valueSource);
|
||||||
|
}
|
||||||
|
if (value[common.Properties.scale] !== undefined) {
|
||||||
|
targetStyle._setValue(style.scaleXProperty, value[common.Properties.scale].x, this._valueSource);
|
||||||
|
targetStyle._setValue(style.scaleYProperty, value[common.Properties.scale].y, this._valueSource);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
switch (this._propertyAnimation.property) {
|
switch (this._propertyAnimation.property) {
|
||||||
case common.Properties.backgroundColor:
|
case common.Properties.backgroundColor:
|
||||||
this._propertyAnimation.target.backgroundColor = value;
|
this._propertyAnimation.target.backgroundColor = value;
|
||||||
@ -52,6 +89,14 @@ class AnimationDelegateImpl extends NSObject {
|
|||||||
case common.Properties.rotate:
|
case common.Properties.rotate:
|
||||||
this._propertyAnimation.target.rotate = value;
|
this._propertyAnimation.target.rotate = value;
|
||||||
break;
|
break;
|
||||||
|
case common.Properties.translate:
|
||||||
|
this._propertyAnimation.target.translateX = value.x;
|
||||||
|
this._propertyAnimation.target.translateY = value.y;
|
||||||
|
break;
|
||||||
|
case common.Properties.scale:
|
||||||
|
this._propertyAnimation.target.scaleX = value.x;
|
||||||
|
this._propertyAnimation.target.scaleY = value.y;
|
||||||
|
break;
|
||||||
case _transform:
|
case _transform:
|
||||||
if (value[common.Properties.translate] !== undefined) {
|
if (value[common.Properties.translate] !== undefined) {
|
||||||
this._propertyAnimation.target.translateX = value[common.Properties.translate].x;
|
this._propertyAnimation.target.translateX = value[common.Properties.translate].x;
|
||||||
@ -63,6 +108,7 @@ class AnimationDelegateImpl extends NSObject {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(<any>this._propertyAnimation.target)._resumePresentationLayerUpdates();
|
(<any>this._propertyAnimation.target)._resumePresentationLayerUpdates();
|
||||||
}
|
}
|
||||||
@ -71,11 +117,6 @@ class AnimationDelegateImpl extends NSObject {
|
|||||||
if (this._finishedCallback) {
|
if (this._finishedCallback) {
|
||||||
this._finishedCallback(!finished);
|
this._finishedCallback(!finished);
|
||||||
}
|
}
|
||||||
if (!finished) {
|
|
||||||
if ((<any>this._propertyAnimation)._propertyResetCallback) {
|
|
||||||
(<any>this._propertyAnimation)._propertyResetCallback((<any>this._propertyAnimation)._originalValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (finished && this.nextAnimation) {
|
if (finished && this.nextAnimation) {
|
||||||
this.nextAnimation();
|
this.nextAnimation();
|
||||||
}
|
}
|
||||||
@ -87,9 +128,10 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
private _finishedAnimations: number;
|
private _finishedAnimations: number;
|
||||||
private _cancelledAnimations: number;
|
private _cancelledAnimations: number;
|
||||||
private _mergedPropertyAnimations: Array<common.PropertyAnimation>;
|
private _mergedPropertyAnimations: Array<common.PropertyAnimation>;
|
||||||
|
private _valueSource: number;
|
||||||
|
|
||||||
public play(): definition.AnimationPromise {
|
public play(): definition.AnimationPromise {
|
||||||
var animationFinishedPromise = super.play();
|
let animationFinishedPromise = super.play();
|
||||||
this._finishedAnimations = 0;
|
this._finishedAnimations = 0;
|
||||||
this._cancelledAnimations = 0;
|
this._cancelledAnimations = 0;
|
||||||
this._iOSAnimationFunction();
|
this._iOSAnimationFunction();
|
||||||
@ -99,22 +141,34 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
public cancel(): void {
|
public cancel(): void {
|
||||||
super.cancel();
|
super.cancel();
|
||||||
|
|
||||||
var i = 0;
|
let i = 0;
|
||||||
var length = this._mergedPropertyAnimations.length;
|
let length = this._mergedPropertyAnimations.length;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
(<UIView>this._mergedPropertyAnimations[i].target._nativeView).layer.removeAllAnimations();
|
(<UIView>this._mergedPropertyAnimations[i].target._nativeView).layer.removeAllAnimations();
|
||||||
|
if ((<any>this._mergedPropertyAnimations[i])._propertyResetCallback) {
|
||||||
|
(<any>this._mergedPropertyAnimations[i])._propertyResetCallback((<any>this._mergedPropertyAnimations[i])._originalValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(animationDefinitions: Array<definition.AnimationDefinition>, playSequentially?: boolean) {
|
constructor(animationDefinitions: Array<definition.AnimationDefinition>, playSequentially?: boolean) {
|
||||||
super(animationDefinitions, playSequentially);
|
super(animationDefinitions, playSequentially);
|
||||||
|
|
||||||
|
if (animationDefinitions.length > 0 && (<any>animationDefinitions[0]).valueSource !== undefined) {
|
||||||
|
this._valueSource = (<any>animationDefinitions[0]).valueSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!playSequentially) {
|
||||||
trace.write("Non-merged Property Animations: " + this._propertyAnimations.length, trace.categories.Animation);
|
trace.write("Non-merged Property Animations: " + this._propertyAnimations.length, trace.categories.Animation);
|
||||||
this._mergedPropertyAnimations = Animation._mergeAffineTransformAnimations(this._propertyAnimations);
|
this._mergedPropertyAnimations = Animation._mergeAffineTransformAnimations(this._propertyAnimations);
|
||||||
trace.write("Merged Property Animations: " + this._mergedPropertyAnimations.length, trace.categories.Animation);
|
trace.write("Merged Property Animations: " + this._mergedPropertyAnimations.length, trace.categories.Animation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._mergedPropertyAnimations = this._propertyAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
var that = this;
|
let that = this;
|
||||||
var animationFinishedCallback = (cancelled: boolean) => {
|
let animationFinishedCallback = (cancelled: boolean) => {
|
||||||
if (that._playSequentially) {
|
if (that._playSequentially) {
|
||||||
// This function will be called by the last animation when done or by another animation if the user cancels them halfway through.
|
// This function will be called by the last animation when done or by another animation if the user cancels them halfway through.
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
@ -144,10 +198,10 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this._iOSAnimationFunction = Animation._createiOSAnimationFunction(this._mergedPropertyAnimations, 0, this._playSequentially, animationFinishedCallback);
|
this._iOSAnimationFunction = Animation._createiOSAnimationFunction(this._mergedPropertyAnimations, 0, this._playSequentially, this._valueSource, animationFinishedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _createiOSAnimationFunction(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, finishedCallback: (cancelled?: boolean) => void): Function {
|
private static _createiOSAnimationFunction(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, valueSource: number, finishedCallback: (cancelled?: boolean) => void): Function {
|
||||||
return (cancelled?: boolean) => {
|
return (cancelled?: boolean) => {
|
||||||
|
|
||||||
if (cancelled && finishedCallback) {
|
if (cancelled && finishedCallback) {
|
||||||
@ -156,34 +210,34 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var animation = propertyAnimations[index];
|
let animation = propertyAnimations[index];
|
||||||
var args = Animation._getNativeAnimationArguments(animation);
|
let args = Animation._getNativeAnimationArguments(animation, valueSource);
|
||||||
|
|
||||||
if (animation.curve === enums.AnimationCurve.spring) {
|
if (animation.curve === enums.AnimationCurve.spring) {
|
||||||
Animation._createNativeSpringAnimation(propertyAnimations, index, playSequentially, args, animation, finishedCallback);
|
Animation._createNativeSpringAnimation(propertyAnimations, index, playSequentially, args, animation, valueSource, finishedCallback);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Animation._createNativeAnimation(propertyAnimations, index, playSequentially, args, animation, finishedCallback);
|
Animation._createNativeAnimation(propertyAnimations, index, playSequentially, args, animation, valueSource, finishedCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _getNativeAnimationArguments(animation: common.PropertyAnimation): AnimationInfo {
|
private static _getNativeAnimationArguments(animation: common.PropertyAnimation, valueSource: number): AnimationInfo {
|
||||||
|
|
||||||
var nativeView = <UIView>animation.target._nativeView;
|
let nativeView = <UIView>animation.target._nativeView;
|
||||||
var presentationLayer = nativeView.layer.presentationLayer();
|
let presentationLayer = nativeView.layer.presentationLayer();
|
||||||
var propertyNameToAnimate = animation.property;
|
let propertyNameToAnimate = animation.property;
|
||||||
var value = animation.value;
|
let value = animation.value;
|
||||||
var originalValue;
|
let originalValue;
|
||||||
|
|
||||||
var tempRotate = animation.target.rotate * Math.PI / 180;
|
let tempRotate = animation.target.rotate * Math.PI / 180;
|
||||||
var abs
|
let abs;
|
||||||
|
|
||||||
switch (animation.property) {
|
switch (animation.property) {
|
||||||
case common.Properties.backgroundColor:
|
case common.Properties.backgroundColor:
|
||||||
(<any>animation)._originalValue = animation.target.backgroundColor;
|
(<any>animation)._originalValue = animation.target.backgroundColor;
|
||||||
(<any>animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value };
|
(<any>animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value; };
|
||||||
if (presentationLayer != null) {
|
if (presentationLayer != null && valueSource !== dependencyObservable.ValueSource.Css) {
|
||||||
originalValue = presentationLayer.backgroundColor;
|
originalValue = presentationLayer.backgroundColor;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -197,8 +251,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
break;
|
break;
|
||||||
case common.Properties.opacity:
|
case common.Properties.opacity:
|
||||||
(<any>animation)._originalValue = animation.target.opacity;
|
(<any>animation)._originalValue = animation.target.opacity;
|
||||||
(<any>animation)._propertyResetCallback = (value) => { animation.target.opacity = value };
|
(<any>animation)._propertyResetCallback = (value) => { animation.target.opacity = value; };
|
||||||
if (presentationLayer != null) {
|
if (presentationLayer != null && valueSource !== dependencyObservable.ValueSource.Css) {
|
||||||
originalValue = presentationLayer.opacity;
|
originalValue = presentationLayer.opacity;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -207,9 +261,9 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
break;
|
break;
|
||||||
case common.Properties.rotate:
|
case common.Properties.rotate:
|
||||||
(<any>animation)._originalValue = animation.target.rotate;
|
(<any>animation)._originalValue = animation.target.rotate;
|
||||||
(<any>animation)._propertyResetCallback = (value) => { animation.target.rotate = value };
|
(<any>animation)._propertyResetCallback = (value) => { animation.target.rotate = value; };
|
||||||
propertyNameToAnimate = "transform.rotation";
|
propertyNameToAnimate = "transform.rotation";
|
||||||
if (presentationLayer != null) {
|
if (presentationLayer != null && valueSource !== dependencyObservable.ValueSource.Css) {
|
||||||
originalValue = presentationLayer.valueForKeyPath("transform.rotation");
|
originalValue = presentationLayer.valueForKeyPath("transform.rotation");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -224,8 +278,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
case common.Properties.translate:
|
case common.Properties.translate:
|
||||||
(<any>animation)._originalValue = { x:animation.target.translateX, y:animation.target.translateY };
|
(<any>animation)._originalValue = { x:animation.target.translateX, y:animation.target.translateY };
|
||||||
(<any>animation)._propertyResetCallback = (value) => { animation.target.translateX = value.x; animation.target.translateY = value.y; };
|
(<any>animation)._propertyResetCallback = (value) => { animation.target.translateX = value.x; animation.target.translateY = value.y; };
|
||||||
propertyNameToAnimate = "transform"
|
propertyNameToAnimate = "transform";
|
||||||
if (presentationLayer != null) {
|
if (presentationLayer != null && valueSource !== dependencyObservable.ValueSource.Css) {
|
||||||
originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
|
originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -236,8 +290,8 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
case common.Properties.scale:
|
case common.Properties.scale:
|
||||||
(<any>animation)._originalValue = { x:animation.target.scaleX, y:animation.target.scaleY };
|
(<any>animation)._originalValue = { x:animation.target.scaleX, y:animation.target.scaleY };
|
||||||
(<any>animation)._propertyResetCallback = (value) => { animation.target.scaleX = value.x; animation.target.scaleY = value.y; };
|
(<any>animation)._propertyResetCallback = (value) => { animation.target.scaleX = value.x; animation.target.scaleY = value.y; };
|
||||||
propertyNameToAnimate = "transform"
|
propertyNameToAnimate = "transform";
|
||||||
if (presentationLayer != null) {
|
if (presentationLayer != null && valueSource !== dependencyObservable.ValueSource.Css) {
|
||||||
originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
|
originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -246,7 +300,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
value = NSValue.valueWithCATransform3D(CATransform3DScale(nativeView.layer.transform, value.x, value.y, 1));
|
value = NSValue.valueWithCATransform3D(CATransform3DScale(nativeView.layer.transform, value.x, value.y, 1));
|
||||||
break;
|
break;
|
||||||
case _transform:
|
case _transform:
|
||||||
if (presentationLayer != null) {
|
if (presentationLayer != null && valueSource !== dependencyObservable.ValueSource.Css) {
|
||||||
originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
|
originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -260,24 +314,24 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
animation.target.scaleX = value.xs;
|
animation.target.scaleX = value.xs;
|
||||||
animation.target.scaleY = value.ys;
|
animation.target.scaleY = value.ys;
|
||||||
};
|
};
|
||||||
propertyNameToAnimate = "transform"
|
propertyNameToAnimate = "transform";
|
||||||
value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation));
|
value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Cannot animate " + animation.property);
|
throw new Error("Cannot animate " + animation.property);
|
||||||
}
|
}
|
||||||
|
|
||||||
var duration = 0.3;
|
let duration = 0.3;
|
||||||
if (animation.duration !== undefined) {
|
if (animation.duration !== undefined) {
|
||||||
duration = animation.duration / 1000.0;
|
duration = animation.duration / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var delay = undefined;
|
let delay = undefined;
|
||||||
if (animation.delay) {
|
if (animation.delay) {
|
||||||
delay = animation.delay / 1000.0;
|
delay = animation.delay / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var repeatCount = undefined;
|
let repeatCount = undefined;
|
||||||
if (animation.iterations !== undefined) {
|
if (animation.iterations !== undefined) {
|
||||||
if (animation.iterations === Number.POSITIVE_INFINITY) {
|
if (animation.iterations === Number.POSITIVE_INFINITY) {
|
||||||
repeatCount = FLT_MAX;
|
repeatCount = FLT_MAX;
|
||||||
@ -297,10 +351,10 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _createNativeAnimation(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, args: AnimationInfo, animation: common.PropertyAnimation, finishedCallback: (cancelled?: boolean) => void) {
|
private static _createNativeAnimation(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, args: AnimationInfo, animation: common.PropertyAnimation, valueSource: number, finishedCallback: (cancelled?: boolean) => void) {
|
||||||
|
|
||||||
var nativeView = <UIView>animation.target._nativeView;
|
let nativeView = <UIView>animation.target._nativeView;
|
||||||
var nativeAnimation = CABasicAnimation.animationWithKeyPath(args.propertyNameToAnimate);
|
let nativeAnimation = CABasicAnimation.animationWithKeyPath(args.propertyNameToAnimate);
|
||||||
nativeAnimation.fromValue = args.fromValue;
|
nativeAnimation.fromValue = args.fromValue;
|
||||||
nativeAnimation.toValue = args.toValue;
|
nativeAnimation.toValue = args.toValue;
|
||||||
nativeAnimation.duration = args.duration;
|
nativeAnimation.duration = args.duration;
|
||||||
@ -314,14 +368,14 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
nativeAnimation.timingFunction = animation.curve;
|
nativeAnimation.timingFunction = animation.curve;
|
||||||
}
|
}
|
||||||
|
|
||||||
var animationDelegate = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation);
|
let animationDelegate = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation, valueSource);
|
||||||
nativeAnimation.setValueForKey(animationDelegate, "delegate");
|
nativeAnimation.setValueForKey(animationDelegate, "delegate");
|
||||||
|
|
||||||
nativeView.layer.addAnimationForKey(nativeAnimation, args.propertyNameToAnimate);
|
nativeView.layer.addAnimationForKey(nativeAnimation, args.propertyNameToAnimate);
|
||||||
|
|
||||||
var callback = undefined;
|
let callback = undefined;
|
||||||
if (index+1 < propertyAnimations.length) {
|
if (index + 1 < propertyAnimations.length) {
|
||||||
callback = Animation._createiOSAnimationFunction(propertyAnimations, index+1, playSequentially, finishedCallback);
|
callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, valueSource, finishedCallback);
|
||||||
if (!playSequentially) {
|
if (!playSequentially) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@ -331,14 +385,14 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _createNativeSpringAnimation(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, args: AnimationInfo, animation: common.PropertyAnimation, finishedCallback: (cancelled?: boolean) => void) {
|
private static _createNativeSpringAnimation(propertyAnimations: Array<common.PropertyAnimation>, index: number, playSequentially: boolean, args: AnimationInfo, animation: common.PropertyAnimation, valueSource: number, finishedCallback: (cancelled?: boolean) => void) {
|
||||||
|
|
||||||
var nativeView = <UIView>animation.target._nativeView;
|
let nativeView = <UIView>animation.target._nativeView;
|
||||||
|
|
||||||
var callback = undefined;
|
let callback = undefined;
|
||||||
var nextAnimation;
|
let nextAnimation;
|
||||||
if (index + 1 < propertyAnimations.length) {
|
if (index + 1 < propertyAnimations.length) {
|
||||||
callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, finishedCallback);
|
callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, valueSource, finishedCallback);
|
||||||
if (!playSequentially) {
|
if (!playSequentially) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@ -347,7 +401,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var delay = 0;
|
let delay = 0;
|
||||||
if (args.delay) {
|
if (args.delay) {
|
||||||
delay = args.delay;
|
delay = args.delay;
|
||||||
}
|
}
|
||||||
@ -396,7 +450,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (finishedCallback) {
|
if (finishedCallback) {
|
||||||
var cancelled = !finished;
|
let cancelled = !finished;
|
||||||
finishedCallback(cancelled);
|
finishedCallback(cancelled);
|
||||||
}
|
}
|
||||||
if (finished && nextAnimation) {
|
if (finished && nextAnimation) {
|
||||||
@ -406,18 +460,18 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _createNativeAffineTransform(animation: common.PropertyAnimation): CATransform3D {
|
private static _createNativeAffineTransform(animation: common.PropertyAnimation): CATransform3D {
|
||||||
var value = animation.value;
|
let value = animation.value;
|
||||||
var result:CATransform3D = CATransform3DIdentity;
|
let result:CATransform3D = CATransform3DIdentity;
|
||||||
|
|
||||||
if (value[common.Properties.translate] !== undefined) {
|
if (value[common.Properties.translate] !== undefined) {
|
||||||
var x = value[common.Properties.translate].x;
|
let x = value[common.Properties.translate].x;
|
||||||
var y = value[common.Properties.translate].y;
|
let y = value[common.Properties.translate].y;
|
||||||
result = CATransform3DTranslate(result, x, y, 0);
|
result = CATransform3DTranslate(result, x, y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value[common.Properties.scale] !== undefined) {
|
if (value[common.Properties.scale] !== undefined) {
|
||||||
var x = value[common.Properties.scale].x;
|
let x = value[common.Properties.scale].x;
|
||||||
var y = value[common.Properties.scale].y;
|
let y = value[common.Properties.scale].y;
|
||||||
result = CATransform3DScale(result, x, y, 1);
|
result = CATransform3DScale(result, x, y, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +485,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _canBeMerged(animation1: common.PropertyAnimation, animation2: common.PropertyAnimation) {
|
private static _canBeMerged(animation1: common.PropertyAnimation, animation2: common.PropertyAnimation) {
|
||||||
var result =
|
let result =
|
||||||
Animation._isAffineTransform(animation1.property) &&
|
Animation._isAffineTransform(animation1.property) &&
|
||||||
Animation._isAffineTransform(animation2.property) &&
|
Animation._isAffineTransform(animation2.property) &&
|
||||||
animation1.target === animation2.target &&
|
animation1.target === animation2.target &&
|
||||||
@ -443,11 +497,11 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _mergeAffineTransformAnimations(propertyAnimations: Array<common.PropertyAnimation>): Array<common.PropertyAnimation> {
|
private static _mergeAffineTransformAnimations(propertyAnimations: Array<common.PropertyAnimation>): Array<common.PropertyAnimation> {
|
||||||
var result = new Array<common.PropertyAnimation>();
|
let result = new Array<common.PropertyAnimation>();
|
||||||
|
|
||||||
var i = 0;
|
let i = 0;
|
||||||
var j;
|
let j;
|
||||||
var length = propertyAnimations.length;
|
let length = propertyAnimations.length;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
if (propertyAnimations[i][_skip]) {
|
if (propertyAnimations[i][_skip]) {
|
||||||
continue;
|
continue;
|
||||||
@ -465,7 +519,7 @@ export class Animation extends common.Animation implements definition.Animation
|
|||||||
// rotate: 90,
|
// rotate: 90,
|
||||||
// scale: {x: 2, y: 2 }
|
// scale: {x: 2, y: 2 }
|
||||||
// }
|
// }
|
||||||
var newTransformAnimation: common.PropertyAnimation = {
|
let newTransformAnimation: common.PropertyAnimation = {
|
||||||
target: propertyAnimations[i].target,
|
target: propertyAnimations[i].target,
|
||||||
property: _transform,
|
property: _transform,
|
||||||
value: {},
|
value: {},
|
||||||
@ -510,12 +564,14 @@ export function _resolveAnimationCurve(curve: any): any {
|
|||||||
return CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionLinear);
|
return CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionLinear);
|
||||||
case enums.AnimationCurve.spring:
|
case enums.AnimationCurve.spring:
|
||||||
return curve;
|
return curve;
|
||||||
|
case enums.AnimationCurve.ease:
|
||||||
|
return CAMediaTimingFunction.functionWithControlPoints(0.25, 0.1, 0.25, 1.0);
|
||||||
default:
|
default:
|
||||||
if (curve instanceof CAMediaTimingFunction) {
|
if (curve instanceof CAMediaTimingFunction) {
|
||||||
return curve;
|
return curve;
|
||||||
}
|
}
|
||||||
else if (curve instanceof common.CubicBezierAnimationCurve) {
|
else if (curve instanceof common.CubicBezierAnimationCurve) {
|
||||||
var animationCurve = <common.CubicBezierAnimationCurve>curve;
|
let animationCurve = <common.CubicBezierAnimationCurve>curve;
|
||||||
return CAMediaTimingFunction.functionWithControlPoints(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2);
|
return CAMediaTimingFunction.functionWithControlPoints(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -524,12 +580,12 @@ export function _resolveAnimationCurve(curve: any): any {
|
|||||||
|
|
||||||
export function _getTransformMismatchErrorMessage(view: viewModule.View): string {
|
export function _getTransformMismatchErrorMessage(view: viewModule.View): string {
|
||||||
// Order is important: translate, rotate, scale
|
// Order is important: translate, rotate, scale
|
||||||
var result: CGAffineTransform = CGAffineTransformIdentity;
|
let result: CGAffineTransform = CGAffineTransformIdentity;
|
||||||
result = CGAffineTransformTranslate(result, view.translateX, view.translateY);
|
result = CGAffineTransformTranslate(result, view.translateX, view.translateY);
|
||||||
result = CGAffineTransformRotate(result, view.rotate * Math.PI / 180);
|
result = CGAffineTransformRotate(result, view.rotate * Math.PI / 180);
|
||||||
result = CGAffineTransformScale(result, view.scaleX, view.scaleY);
|
result = CGAffineTransformScale(result, view.scaleX, view.scaleY);
|
||||||
var viewTransform = NSStringFromCGAffineTransform(result);
|
let viewTransform = NSStringFromCGAffineTransform(result);
|
||||||
var nativeTransform = NSStringFromCGAffineTransform(view._nativeView.transform);
|
let nativeTransform = NSStringFromCGAffineTransform(view._nativeView.transform);
|
||||||
|
|
||||||
if (viewTransform !== nativeTransform) {
|
if (viewTransform !== nativeTransform) {
|
||||||
return "View and Native transforms do not match. View: " + viewTransform + "; Native: " + nativeTransform;
|
return "View and Native transforms do not match. View: " + viewTransform + "; Native: " + nativeTransform;
|
||||||
|
94
ui/animation/keyframe-animation.d.ts
vendored
Normal file
94
ui/animation/keyframe-animation.d.ts
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
declare module "ui/animation/keyframe-animation" {
|
||||||
|
|
||||||
|
import view = require("ui/core/view");
|
||||||
|
|
||||||
|
export interface KeyframeDeclaration {
|
||||||
|
property: string;
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KeyframeInfo {
|
||||||
|
duration: number;
|
||||||
|
curve: any;
|
||||||
|
declarations: Array<KeyframeDeclaration>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines animation options for the View.animate method.
|
||||||
|
*/
|
||||||
|
export class KeyframeAnimationInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animation name.
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the animation in milliseconds. The default duration is 300 milliseconds.
|
||||||
|
*/
|
||||||
|
duration: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of time, in milliseconds, to delay starting the animation.
|
||||||
|
*/
|
||||||
|
delay: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies how many times the animation should be played. Default is 1.
|
||||||
|
* iOS animations support fractional iterations, i.e. 1.5.
|
||||||
|
* To repeat an animation infinitely, use Number.POSITIVE_INFINITY
|
||||||
|
*/
|
||||||
|
iterations: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional animation curve. Possible values are contained in the [AnimationCurve enumeration](../enums/AnimationCurve/README.md).
|
||||||
|
* Alternatively, you can pass an instance of type UIViewAnimationCurve for iOS or android.animation.TimeInterpolator for Android.
|
||||||
|
*/
|
||||||
|
curve: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the animation values will be applied on the animated object after the animation finishes.
|
||||||
|
*/
|
||||||
|
isForwards: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true the animation will be played backwards.
|
||||||
|
*/
|
||||||
|
isReverse: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return animation keyframes.
|
||||||
|
*/
|
||||||
|
keyframes: Array<KeyframeInfo>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyframeAnimation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of time, in milliseconds, to delay starting the animation.
|
||||||
|
*/
|
||||||
|
delay: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies how many times the animation should be played. Default is 1.
|
||||||
|
* iOS animations support fractional iterations, i.e. 1.5.
|
||||||
|
* To repeat an animation infinitely, use Number.POSITIVE_INFINITY
|
||||||
|
*/
|
||||||
|
iterations: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the application is currently running.
|
||||||
|
*/
|
||||||
|
isPlaying: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays the animation.
|
||||||
|
*/
|
||||||
|
public play: (view: view.View) => Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a keyframe animation from animation definition.
|
||||||
|
*/
|
||||||
|
public static keyframeAnimationFromInfo(info: KeyframeAnimationInfo, valueSourceModifier: number);
|
||||||
|
}
|
||||||
|
}
|
196
ui/animation/keyframe-animation.ts
Normal file
196
ui/animation/keyframe-animation.ts
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
import definition = require("ui/animation/keyframe-animation");
|
||||||
|
import view = require("ui/core/view");
|
||||||
|
import enums = require("ui/enums");
|
||||||
|
import style = require("ui/styling/style");
|
||||||
|
|
||||||
|
export class KeyframeDeclaration implements definition.KeyframeDeclaration {
|
||||||
|
public property: string;
|
||||||
|
public value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyframeInfo implements definition.KeyframeInfo {
|
||||||
|
public duration: number;
|
||||||
|
public curve: any;
|
||||||
|
public declarations: Array<KeyframeDeclaration>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyframeAnimationInfo implements definition.KeyframeAnimationInfo {
|
||||||
|
public name: string = "";
|
||||||
|
public duration: number = 0.3;
|
||||||
|
public delay: number = 0;
|
||||||
|
public iterations: number = 1;
|
||||||
|
public curve: any = enums.AnimationCurve.ease;
|
||||||
|
public isForwards: boolean = false;
|
||||||
|
public isReverse: boolean = false;
|
||||||
|
public keyframes: Array<KeyframeInfo>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyframeAnimation {
|
||||||
|
public animations: Array<Object>;
|
||||||
|
public delay: number = 0;
|
||||||
|
public iterations: number = 1;
|
||||||
|
|
||||||
|
private _resolve;
|
||||||
|
private _reject;
|
||||||
|
private _isPlaying: boolean;
|
||||||
|
private _isForwards: boolean;
|
||||||
|
|
||||||
|
public static keyframeAnimationFromInfo(info: KeyframeAnimationInfo, valueSourceModifier: number) {
|
||||||
|
let animations = new Array<Object>();
|
||||||
|
let length = info.keyframes.length;
|
||||||
|
let startDuration = 0;
|
||||||
|
if (info.isReverse) {
|
||||||
|
for (let index = length - 1; index >= 0; index --) {
|
||||||
|
let keyframe = info.keyframes[index];
|
||||||
|
startDuration = KeyframeAnimation.parseKeyframe(info, keyframe, animations, startDuration, valueSourceModifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let index = 0; index < length; index ++) {
|
||||||
|
let keyframe = info.keyframes[index];
|
||||||
|
startDuration = KeyframeAnimation.parseKeyframe(info, keyframe, animations, startDuration, valueSourceModifier);
|
||||||
|
}
|
||||||
|
for (let index = length - 1; index > 0; index --) {
|
||||||
|
let a1 = animations[index];
|
||||||
|
let a2 = animations[index - 1];
|
||||||
|
if (a2["curve"] !== undefined) {
|
||||||
|
a1["curve"] = a2["curve"];
|
||||||
|
a2["curve"] = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let index = 1; index < length; index++) {
|
||||||
|
let a = animations[index];
|
||||||
|
if (a["curve"] === undefined) {
|
||||||
|
a["curve"] = info.curve;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let animation: KeyframeAnimation = new KeyframeAnimation();
|
||||||
|
animation.delay = info.delay;
|
||||||
|
animation.iterations = info.iterations;
|
||||||
|
animation.animations = animations;
|
||||||
|
animation._isForwards = info.isForwards;
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static parseKeyframe(info: KeyframeAnimationInfo, keyframe: KeyframeInfo, animations: Array<Object>, startDuration: number, valueSourceModifier: number): number {
|
||||||
|
let animation = {};
|
||||||
|
for (let declaration of keyframe.declarations) {
|
||||||
|
animation[declaration.property] = declaration.value;
|
||||||
|
}
|
||||||
|
let duration = keyframe.duration;
|
||||||
|
if (duration === 0) {
|
||||||
|
duration = 0.01;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
duration = (info.duration * duration) - startDuration;
|
||||||
|
startDuration += duration;
|
||||||
|
}
|
||||||
|
animation["duration"] = info.isReverse ? info.duration - duration : duration;
|
||||||
|
animation["curve"] = keyframe.curve;
|
||||||
|
animation["forceLayer"] = true;
|
||||||
|
animation["valueSource"] = valueSourceModifier;
|
||||||
|
animations.push(animation);
|
||||||
|
return startDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPlaying(): boolean {
|
||||||
|
return this._isPlaying;
|
||||||
|
}
|
||||||
|
|
||||||
|
public play(view: view.View): Promise<void> {
|
||||||
|
if (this._isPlaying) {
|
||||||
|
throw new Error("Animation is already playing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let animationFinishedPromise = new Promise<void>((resolve, reject) => {
|
||||||
|
this._resolve = resolve;
|
||||||
|
this._reject = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._isPlaying = true;
|
||||||
|
|
||||||
|
if (this.delay !== 0) {
|
||||||
|
let that = this;
|
||||||
|
setTimeout(function (){ that.animate(view, 0, that.iterations); }, that.delay, that);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.animate(view, 0, this.iterations);
|
||||||
|
}
|
||||||
|
|
||||||
|
return animationFinishedPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
private animate(view: view.View, index: number, iterations: number) {
|
||||||
|
if (index === 0) {
|
||||||
|
let animation = this.animations[0];
|
||||||
|
let modifier = animation["valueSource"];
|
||||||
|
|
||||||
|
if ("backgroundColor" in animation) {
|
||||||
|
view.style._setValue(style.backgroundColorProperty, animation["backgroundColor"], modifier);
|
||||||
|
}
|
||||||
|
if ("scale" in animation) {
|
||||||
|
view.style._setValue(style.scaleXProperty, animation["scale"].x, modifier);
|
||||||
|
view.style._setValue(style.scaleYProperty, animation["scale"].y, modifier);
|
||||||
|
}
|
||||||
|
if ("translate" in animation) {
|
||||||
|
view.style._setValue(style.translateXProperty, animation["translate"].x, modifier);
|
||||||
|
view.style._setValue(style.translateYProperty, animation["translate"].y, modifier);
|
||||||
|
}
|
||||||
|
if ("rotate" in animation) {
|
||||||
|
view.style._setValue(style.rotateProperty, animation["rotate"], modifier);
|
||||||
|
}
|
||||||
|
if ("opacity" in animation) {
|
||||||
|
view.style._setValue(style.opacityProperty, animation["opacity"], modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
let that = this;
|
||||||
|
setTimeout(function () { that.animate(view, 1, iterations); }, 1, that);
|
||||||
|
}
|
||||||
|
else if (index < 0 || index >= this.animations.length) {
|
||||||
|
iterations -= 1;
|
||||||
|
if (iterations > 0) {
|
||||||
|
this.animate(view, 0, iterations);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this._isForwards === false) {
|
||||||
|
let animation = this.animations[this.animations.length - 1];
|
||||||
|
let modifier = animation["valueSource"];
|
||||||
|
if ("backgroundColor" in animation) {
|
||||||
|
view.style._resetValue(style.backgroundColorProperty, modifier);
|
||||||
|
}
|
||||||
|
if ("scale" in animation) {
|
||||||
|
view.style._resetValue(style.scaleXProperty, modifier);
|
||||||
|
view.style._resetValue(style.scaleYProperty, modifier);
|
||||||
|
}
|
||||||
|
if ("translate" in animation) {
|
||||||
|
view.style._resetValue(style.translateXProperty, modifier);
|
||||||
|
view.style._resetValue(style.translateYProperty, modifier);
|
||||||
|
}
|
||||||
|
if ("rotate" in animation) {
|
||||||
|
view.style._resetValue(style.rotateProperty, modifier);
|
||||||
|
}
|
||||||
|
if ("opacity" in animation) {
|
||||||
|
view.style._resetValue(style.opacityProperty, modifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._resolveAnimationFinishedPromise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
view.animate(this.animations[index]).then(() => {
|
||||||
|
this.animate(view, index + 1, iterations);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public _resolveAnimationFinishedPromise() {
|
||||||
|
this._isPlaying = false;
|
||||||
|
this._resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
public _rejectAnimationFinishedPromise() {
|
||||||
|
this._isPlaying = false;
|
||||||
|
this._reject(new Error("Animation cancelled."));
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,24 @@ export class Button extends common.Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._android.setOnTouchListener(new android.view.View.OnTouchListener(
|
||||||
|
<utils.Owned & android.view.View.IOnTouchListener>{
|
||||||
|
get owner() {
|
||||||
|
return that.get();
|
||||||
|
},
|
||||||
|
|
||||||
|
onTouch: function(v, ev) {
|
||||||
|
if (ev.getAction() === 0) { // down
|
||||||
|
this.owner._goToVisualState("highlighted");
|
||||||
|
}
|
||||||
|
else if (ev.getAction() === 1) { // up
|
||||||
|
this.owner._goToVisualState("normal");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public _onTextPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
public _onTextPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||||
|
@ -6,6 +6,7 @@ import view = require("ui/core/view");
|
|||||||
import utils = require("utils/utils");
|
import utils = require("utils/utils");
|
||||||
import enums = require("ui/enums");
|
import enums = require("ui/enums");
|
||||||
import dependencyObservable = require("ui/core/dependency-observable");
|
import dependencyObservable = require("ui/core/dependency-observable");
|
||||||
|
import styleScope = require("../styling/style-scope");
|
||||||
|
|
||||||
class TapHandlerImpl extends NSObject {
|
class TapHandlerImpl extends NSObject {
|
||||||
private _owner: WeakRef<Button>;
|
private _owner: WeakRef<Button>;
|
||||||
@ -47,6 +48,22 @@ export class Button extends common.Button {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onLoaded() {
|
||||||
|
super.onLoaded();
|
||||||
|
if (this.parent !== null && this.page !== null) {
|
||||||
|
let rootPage = this.page;
|
||||||
|
let scope: styleScope.StyleScope = (<any>rootPage)._getStyleScope();
|
||||||
|
if (scope.getVisualStates(this) !== undefined) {
|
||||||
|
this._stateChangedHandler.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onUnloaded() {
|
||||||
|
super.onUnloaded();
|
||||||
|
this._stateChangedHandler.stop();
|
||||||
|
}
|
||||||
|
|
||||||
get ios(): UIButton {
|
get ios(): UIButton {
|
||||||
return this._ios;
|
return this._ios;
|
||||||
}
|
}
|
||||||
|
4
ui/core/control-state-change.d.ts
vendored
4
ui/core/control-state-change.d.ts
vendored
@ -10,5 +10,9 @@
|
|||||||
* @param callback A callback called when a visual state of the UIControl is changed.
|
* @param callback A callback called when a visual state of the UIControl is changed.
|
||||||
*/
|
*/
|
||||||
constructor(control: any /* UIControl */, callback: (state: string) => void);
|
constructor(control: any /* UIControl */, callback: (state: string) => void);
|
||||||
|
|
||||||
|
start();
|
||||||
|
|
||||||
|
stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,22 +21,31 @@ export class ControlStateChangeListener implements definition.ControlStateChange
|
|||||||
private _observer: NSObject;
|
private _observer: NSObject;
|
||||||
private _states: string[];
|
private _states: string[];
|
||||||
private _control: UIControl;
|
private _control: UIControl;
|
||||||
|
private _observing: boolean = false;
|
||||||
|
|
||||||
private _callback: (state: string) => void;
|
private _callback: (state: string) => void;
|
||||||
|
|
||||||
constructor(control: UIControl, callback: (state: string) => void) {
|
constructor(control: UIControl, callback: (state: string) => void) {
|
||||||
this._observer = ObserverClass.alloc();
|
this._observer = ObserverClass.alloc();
|
||||||
this._observer["_owner"] = this;
|
this._observer["_owner"] = this;
|
||||||
|
|
||||||
// TODO: Commenting for now, needs revision later since we must detach the observers upon control deallocation
|
|
||||||
//control.addObserverForKeyPathOptionsContext(this._observer, "selected", NSKeyValueObservingOptions.NSKeyValueObservingOptionNew, null);
|
|
||||||
//control.addObserverForKeyPathOptionsContext(this._observer, "enabled", NSKeyValueObservingOptions.NSKeyValueObservingOptionNew, null);
|
|
||||||
//control.addObserverForKeyPathOptionsContext(this._observer, "highlighted", NSKeyValueObservingOptions.NSKeyValueObservingOptionNew, null);
|
|
||||||
|
|
||||||
this._control = control;
|
this._control = control;
|
||||||
this._callback = callback;
|
this._callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
if (!this._observing) {
|
||||||
|
this._control.addObserverForKeyPathOptionsContext(this._observer, "highlighted", NSKeyValueObservingOptions.NSKeyValueObservingOptionNew, null);
|
||||||
|
this._observing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop() {
|
||||||
|
if (this._observing) {
|
||||||
|
this._observing = false;
|
||||||
|
this._control.removeObserverForKeyPath(this._observer, "highlighted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _onEnabledChanged() {
|
private _onEnabledChanged() {
|
||||||
this._updateState();
|
this._updateState();
|
||||||
}
|
}
|
||||||
@ -52,11 +61,8 @@ export class ControlStateChangeListener implements definition.ControlStateChange
|
|||||||
private _updateState() {
|
private _updateState() {
|
||||||
var state = visualStateConstants.Normal;
|
var state = visualStateConstants.Normal;
|
||||||
if (this._control.highlighted) {
|
if (this._control.highlighted) {
|
||||||
state = visualStateConstants.Pressed;
|
state = "highlighted";
|
||||||
} else if (this._control.highlighted) {
|
|
||||||
// TODO:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._callback(state);
|
this._callback(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -636,6 +636,71 @@ export class ViewStyler implements style.Styler {
|
|||||||
(<android.view.View>view._nativeView).setPadding(left, top, right, bottom);
|
(<android.view.View>view._nativeView).setPadding(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rotate
|
||||||
|
private static setRotateProperty(view: View, newValue: any) {
|
||||||
|
view.rotate = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetRotateProperty(view: View, nativeValue: any) {
|
||||||
|
view.rotate = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getRotateProperty(view: View): any {
|
||||||
|
return view.rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ScaleX
|
||||||
|
private static setScaleXProperty(view: View, newValue: any) {
|
||||||
|
view.scaleX = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetScaleXProperty(view: View, nativeValue: any) {
|
||||||
|
view.scaleX = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getScaleXProperty(view: View): any {
|
||||||
|
return view.scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ScaleY
|
||||||
|
private static setScaleYProperty(view: View, newValue: any) {
|
||||||
|
view.scaleY = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetScaleYProperty(view: View, nativeValue: any) {
|
||||||
|
view.scaleY = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getScaleYProperty(view: View): any {
|
||||||
|
return view.scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TranslateX
|
||||||
|
private static setTranslateXProperty(view: View, newValue: any) {
|
||||||
|
view.translateX = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetTranslateXProperty(view: View, nativeValue: any) {
|
||||||
|
view.translateX = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getTranslateXProperty(view: View): any {
|
||||||
|
return view.translateX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TranslateY
|
||||||
|
private static setTranslateYProperty(view: View, newValue: any) {
|
||||||
|
view.translateY = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetTranslateYProperty(view: View, nativeValue: any) {
|
||||||
|
view.translateY = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getTranslateYProperty(view: View): any {
|
||||||
|
return view.translateY;
|
||||||
|
}
|
||||||
|
|
||||||
public static registerHandlers() {
|
public static registerHandlers() {
|
||||||
style.registerHandler(style.visibilityProperty, new style.StylePropertyChangedHandler(
|
style.registerHandler(style.visibilityProperty, new style.StylePropertyChangedHandler(
|
||||||
ViewStyler.setVisibilityProperty,
|
ViewStyler.setVisibilityProperty,
|
||||||
@ -679,6 +744,31 @@ export class ViewStyler implements style.Styler {
|
|||||||
style.registerHandler(style.nativePaddingsProperty, new style.StylePropertyChangedHandler(
|
style.registerHandler(style.nativePaddingsProperty, new style.StylePropertyChangedHandler(
|
||||||
ViewStyler.setPaddingProperty,
|
ViewStyler.setPaddingProperty,
|
||||||
ViewStyler.resetPaddingProperty), "LayoutBase");
|
ViewStyler.resetPaddingProperty), "LayoutBase");
|
||||||
|
|
||||||
|
style.registerHandler(style.rotateProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setRotateProperty,
|
||||||
|
ViewStyler.resetRotateProperty,
|
||||||
|
ViewStyler.getRotateProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.scaleXProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setScaleXProperty,
|
||||||
|
ViewStyler.resetScaleXProperty,
|
||||||
|
ViewStyler.getScaleXProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.scaleYProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setScaleYProperty,
|
||||||
|
ViewStyler.resetScaleYProperty,
|
||||||
|
ViewStyler.getScaleYProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.translateXProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setTranslateXProperty,
|
||||||
|
ViewStyler.resetTranslateXProperty,
|
||||||
|
ViewStyler.getTranslateXProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.translateYProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setTranslateYProperty,
|
||||||
|
ViewStyler.resetTranslateYProperty,
|
||||||
|
ViewStyler.getTranslateYProperty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +517,71 @@ export class ViewStyler implements style.Styler {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rotate
|
||||||
|
private static setRotateProperty(view: View, newValue: any) {
|
||||||
|
view.rotate = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetRotateProperty(view: View, nativeValue: any) {
|
||||||
|
view.rotate = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getRotateProperty(view: View): any {
|
||||||
|
return view.rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ScaleX
|
||||||
|
private static setScaleXProperty(view: View, newValue: any) {
|
||||||
|
view.scaleX = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetScaleXProperty(view: View, nativeValue: any) {
|
||||||
|
view.scaleX = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getScaleXProperty(view: View): any {
|
||||||
|
return view.scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ScaleY
|
||||||
|
private static setScaleYProperty(view: View, newValue: any) {
|
||||||
|
view.scaleY = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetScaleYProperty(view: View, nativeValue: any) {
|
||||||
|
view.scaleY = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getScaleYProperty(view: View): any {
|
||||||
|
return view.scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TranslateX
|
||||||
|
private static setTranslateXProperty(view: View, newValue: any) {
|
||||||
|
view.translateX = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetTranslateXProperty(view: View, nativeValue: any) {
|
||||||
|
view.translateX = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getTranslateXProperty(view: View): any {
|
||||||
|
return view.translateX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TranslateY
|
||||||
|
private static setTranslateYProperty(view: View, newValue: any) {
|
||||||
|
view.translateY = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static resetTranslateYProperty(view: View, nativeValue: any) {
|
||||||
|
view.translateY = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static getTranslateYProperty(view: View): any {
|
||||||
|
return view.translateY;
|
||||||
|
}
|
||||||
|
|
||||||
public static registerHandlers() {
|
public static registerHandlers() {
|
||||||
style.registerHandler(style.backgroundInternalProperty, new style.StylePropertyChangedHandler(
|
style.registerHandler(style.backgroundInternalProperty, new style.StylePropertyChangedHandler(
|
||||||
ViewStyler.setBackgroundInternalProperty,
|
ViewStyler.setBackgroundInternalProperty,
|
||||||
@ -545,6 +610,31 @@ export class ViewStyler implements style.Styler {
|
|||||||
ViewStyler.setBorderRadiusProperty,
|
ViewStyler.setBorderRadiusProperty,
|
||||||
ViewStyler.resetBorderRadiusProperty,
|
ViewStyler.resetBorderRadiusProperty,
|
||||||
ViewStyler.getBorderRadiusProperty));
|
ViewStyler.getBorderRadiusProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.rotateProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setRotateProperty,
|
||||||
|
ViewStyler.resetRotateProperty,
|
||||||
|
ViewStyler.getRotateProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.scaleXProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setScaleXProperty,
|
||||||
|
ViewStyler.resetScaleXProperty,
|
||||||
|
ViewStyler.getScaleXProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.scaleYProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setScaleYProperty,
|
||||||
|
ViewStyler.resetScaleYProperty,
|
||||||
|
ViewStyler.getScaleYProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.translateXProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setTranslateXProperty,
|
||||||
|
ViewStyler.resetTranslateXProperty,
|
||||||
|
ViewStyler.getTranslateXProperty));
|
||||||
|
|
||||||
|
style.registerHandler(style.translateYProperty, new style.StylePropertyChangedHandler(
|
||||||
|
ViewStyler.setTranslateYProperty,
|
||||||
|
ViewStyler.resetTranslateYProperty,
|
||||||
|
ViewStyler.getTranslateYProperty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
ui/enums/enums.d.ts
vendored
7
ui/enums/enums.d.ts
vendored
@ -523,7 +523,12 @@
|
|||||||
/**
|
/**
|
||||||
* Represents an animation curve type.
|
* Represents an animation curve type.
|
||||||
*/
|
*/
|
||||||
module AnimationCurve {
|
export module AnimationCurve {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value. Specifies a transition effect with a slow start, then fast, then end slowly (equivalent to cubic-bezier(0.25,0.1,0.25,1))
|
||||||
|
*/
|
||||||
|
export var ease: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ease-in curve causes the animation to begin slowly, and then speed up as it progresses.
|
* An ease-in curve causes the animation to begin slowly, and then speed up as it progresses.
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import animationModule = require("ui/animation");
|
|
||||||
|
|
||||||
export module KeyboardType {
|
export module KeyboardType {
|
||||||
export var datetime = "datetime";
|
export var datetime = "datetime";
|
||||||
export var phone = "phone";
|
export var phone = "phone";
|
||||||
@ -159,13 +157,17 @@ export module BackgroundRepeat {
|
|||||||
export var noRepeat: string = "no-repeat";
|
export var noRepeat: string = "no-repeat";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var animationModule;
|
||||||
|
|
||||||
export module AnimationCurve {
|
export module AnimationCurve {
|
||||||
|
export var ease = "ease";
|
||||||
export var easeIn = "easeIn";
|
export var easeIn = "easeIn";
|
||||||
export var easeOut = "easeOut";
|
export var easeOut = "easeOut";
|
||||||
export var easeInOut = "easeInOut";
|
export var easeInOut = "easeInOut";
|
||||||
export var linear = "linear";
|
export var linear = "linear";
|
||||||
export var spring = "spring";
|
export var spring = "spring";
|
||||||
export function cubicBezier(x1: number, y1: number, x2: number, y2: number): animationModule.CubicBezierAnimationCurve {
|
export function cubicBezier(x1: number, y1: number, x2: number, y2: number): Object {
|
||||||
|
animationModule = animationModule || require("ui/animation");
|
||||||
return new animationModule.CubicBezierAnimationCurve(x1, y1 ,x2, y2);
|
return new animationModule.CubicBezierAnimationCurve(x1, y1 ,x2, y2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,21 @@ export class ListView extends common.ListView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _childrenCount(): number {
|
||||||
|
let keys = Object.keys(this._realizedItems);
|
||||||
|
return keys.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public _eachChildView(callback: (child: viewModule.View) => boolean): void {
|
||||||
|
let keys = Object.keys(this._realizedItems);
|
||||||
|
let length = keys.length;
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
let key = keys[i];
|
||||||
|
let view: viewModule.View = this._realizedItems[key];
|
||||||
|
callback(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public _getRealizedView(convertView: android.view.View, index: number) {
|
public _getRealizedView(convertView: android.view.View, index: number) {
|
||||||
if (!convertView) {
|
if (!convertView) {
|
||||||
return this._getItemTemplateContent(index);
|
return this._getItemTemplateContent(index);
|
||||||
|
@ -241,6 +241,16 @@ export class ListView extends common.ListView {
|
|||||||
return this._ios;
|
return this._ios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _childrenCount(): number {
|
||||||
|
return this._map.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public _eachChildView(callback: (child: view.View) => boolean): void {
|
||||||
|
this._map.forEach(function(view, key) {
|
||||||
|
callback(view);
|
||||||
|
}, this._map);
|
||||||
|
}
|
||||||
|
|
||||||
public scrollToIndex(index: number) {
|
public scrollToIndex(index: number) {
|
||||||
if (this._ios) {
|
if (this._ios) {
|
||||||
this._ios.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0),
|
this._ios.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0),
|
||||||
|
@ -8,6 +8,7 @@ import * as style from "../styling/style";
|
|||||||
import * as fileSystemModule from "file-system";
|
import * as fileSystemModule from "file-system";
|
||||||
import * as frameModule from "ui/frame";
|
import * as frameModule from "ui/frame";
|
||||||
import proxy = require("ui/core/proxy");
|
import proxy = require("ui/core/proxy");
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
|
||||||
var fs: typeof fileSystemModule;
|
var fs: typeof fileSystemModule;
|
||||||
function ensureFS() {
|
function ensureFS() {
|
||||||
@ -175,6 +176,15 @@ export class Page extends ContentView implements dts.Page {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public removeCssSelectors(selectorExpression: string) {
|
||||||
|
this._styleScope.removeSelectors(selectorExpression);
|
||||||
|
this._refreshCss();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getKeyframeAnimationWithName(animationName: string): keyframeAnimation.KeyframeAnimationInfo {
|
||||||
|
return this._styleScope.getKeyframeAnimationWithName(animationName);
|
||||||
|
}
|
||||||
|
|
||||||
get frame(): frameModule.Frame {
|
get frame(): frameModule.Frame {
|
||||||
return <frameModule.Frame>this.parent;
|
return <frameModule.Frame>this.parent;
|
||||||
}
|
}
|
||||||
|
12
ui/page/page.d.ts
vendored
12
ui/page/page.d.ts
vendored
@ -8,6 +8,7 @@ declare module "ui/page" {
|
|||||||
import frame = require("ui/frame");
|
import frame = require("ui/frame");
|
||||||
import actionBar = require("ui/action-bar");
|
import actionBar = require("ui/action-bar");
|
||||||
import dependencyObservable = require("ui/core/dependency-observable");
|
import dependencyObservable = require("ui/core/dependency-observable");
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
|
||||||
//@private
|
//@private
|
||||||
import styleScope = require("ui/styling/style-scope");
|
import styleScope = require("ui/styling/style-scope");
|
||||||
@ -120,6 +121,17 @@ declare module "ui/page" {
|
|||||||
*/
|
*/
|
||||||
addCssFile(cssFileName: string): void;
|
addCssFile(cssFileName: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all selectors matching the specified selector expression.
|
||||||
|
* @param selectorExpression - A valid selector expression.
|
||||||
|
*/
|
||||||
|
removeCssSelectors(selectorExpression: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a CSS keyframe animation with the specified name, if it exists.
|
||||||
|
*/
|
||||||
|
getKeyframeAnimationWithName(animationName: string): keyframeAnimation.KeyframeAnimationInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A property that is used to pass a data from another page (while navigate to).
|
* A property that is used to pass a data from another page (while navigate to).
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import enums = require("ui/enums");
|
import enums = require("ui/enums");
|
||||||
import color = require("color");
|
import color = require("color");
|
||||||
|
import types = require("utils/types");
|
||||||
|
|
||||||
export function colorConverter(value: string): color.Color {
|
export function colorConverter(value: string): color.Color {
|
||||||
return new color.Color(value);
|
return new color.Color(value);
|
||||||
@ -73,3 +74,96 @@ export function opacityConverter(value: string): number {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function timeConverter(value: string): number {
|
||||||
|
var result = parseFloat(value);
|
||||||
|
if (value.indexOf("ms") === -1) {
|
||||||
|
result = result*1000;
|
||||||
|
}
|
||||||
|
result = Math.max(0.0, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bezieArgumentConverter(value: string): number {
|
||||||
|
var result = parseFloat(value);
|
||||||
|
result = Math.max(0.0, result);
|
||||||
|
result = Math.min(1.0, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function animationTimingFunctionConverter(value: string): Object {
|
||||||
|
let result: Object = enums.AnimationCurve.ease;
|
||||||
|
switch (value) {
|
||||||
|
case "ease":
|
||||||
|
result = enums.AnimationCurve.ease;
|
||||||
|
break;
|
||||||
|
case "linear":
|
||||||
|
result = enums.AnimationCurve.linear;
|
||||||
|
break;
|
||||||
|
case "ease-in":
|
||||||
|
result = enums.AnimationCurve.easeIn;
|
||||||
|
break;
|
||||||
|
case "ease-out":
|
||||||
|
result = enums.AnimationCurve.easeOut;
|
||||||
|
break;
|
||||||
|
case "ease-in-out":
|
||||||
|
result = enums.AnimationCurve.easeInOut;
|
||||||
|
break;
|
||||||
|
case "spring":
|
||||||
|
result = enums.AnimationCurve.spring;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (value.indexOf("cubic-bezier(") === 0) {
|
||||||
|
let bezierArr = value.substring(13).split(/[,]+/);
|
||||||
|
if (bezierArr.length !== 4) {
|
||||||
|
throw new Error("Invalid value for animation: " + value);
|
||||||
|
}
|
||||||
|
result = enums.AnimationCurve.cubicBezier(bezieArgumentConverter(bezierArr[0]),
|
||||||
|
bezieArgumentConverter(bezierArr[1]),
|
||||||
|
bezieArgumentConverter(bezierArr[2]),
|
||||||
|
bezieArgumentConverter(bezierArr[3]));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error("Invalid value for animation: " + value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformConverter(value: any): Object {
|
||||||
|
if (value === "none") {
|
||||||
|
let operations = {};
|
||||||
|
operations[value] = value;
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
else if (types.isString(value)) {
|
||||||
|
let operations = {};
|
||||||
|
let operator = "";
|
||||||
|
let pos = 0;
|
||||||
|
while (pos < value.length) {
|
||||||
|
if (value[pos] === " " || value[pos] === ",") {
|
||||||
|
pos ++;
|
||||||
|
}
|
||||||
|
else if (value[pos] === "(") {
|
||||||
|
let start = pos + 1;
|
||||||
|
while (pos < value.length && value[pos] !== ")") {
|
||||||
|
pos ++;
|
||||||
|
}
|
||||||
|
let operand = value.substring(start, pos);
|
||||||
|
operations[operator] = operand.trim();
|
||||||
|
operator = "";
|
||||||
|
pos ++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
operator += value[pos ++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
202
ui/styling/css-animation-parser.ts
Normal file
202
ui/styling/css-animation-parser.ts
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import animationModule = require("ui/animation");
|
||||||
|
import keyframeAnimationModule = require("ui/animation/keyframe-animation");
|
||||||
|
import cssParser = require("css");
|
||||||
|
import converters = require("../styling/converters");
|
||||||
|
import types = require("utils/types");
|
||||||
|
import colorModule = require("color");
|
||||||
|
import styleProperty = require("ui/styling/style-property");
|
||||||
|
|
||||||
|
interface TransformInfo {
|
||||||
|
scale: animationModule.Pair;
|
||||||
|
translate: animationModule.Pair;
|
||||||
|
}
|
||||||
|
|
||||||
|
let animationProperties = {
|
||||||
|
"animation-name": (info, declaration) => info.name = declaration.value,
|
||||||
|
"animation-duration": (info, declaration) => info.duration = converters.timeConverter(declaration.value),
|
||||||
|
"animation-delay": (info, declaration) => info.delay = converters.timeConverter(declaration.value),
|
||||||
|
"animation-timing-function": (info, declaration) => info.curve = converters.animationTimingFunctionConverter(declaration.value),
|
||||||
|
"animation-iteration-count": (info, declaration) => declaration.value === "infinite" ? info.iterations = Number.MAX_VALUE : info.iterations = converters.numberConverter(declaration.value),
|
||||||
|
"animation-direction": (info, declaration) => info.isReverse = declaration.value === "reverse",
|
||||||
|
"animation-fill-mode": (info, declaration) => info.isForwards = declaration.value === "forwards"
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CssAnimationParser {
|
||||||
|
|
||||||
|
public static keyframeAnimationsFromCSSDeclarations(declarations: cssParser.Declaration[]): Array<keyframeAnimationModule.KeyframeAnimationInfo> {
|
||||||
|
let animations: Array<keyframeAnimationModule.KeyframeAnimationInfo> = new Array<keyframeAnimationModule.KeyframeAnimationInfo>();
|
||||||
|
let animationInfo: keyframeAnimationModule.KeyframeAnimationInfo = undefined;
|
||||||
|
if (declarations === null || declarations === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
for (let declaration of declarations) {
|
||||||
|
if (declaration.property === "animation") {
|
||||||
|
CssAnimationParser.keyframeAnimationsFromCSSProperty(declaration.value, animations);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let propertyHandler = animationProperties[declaration.property];
|
||||||
|
if (propertyHandler) {
|
||||||
|
if (animationInfo === undefined) {
|
||||||
|
animationInfo = new keyframeAnimationModule.KeyframeAnimationInfo();
|
||||||
|
animations.push(animationInfo);
|
||||||
|
}
|
||||||
|
propertyHandler(animationInfo, declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return animations.length === 0 ? undefined : animations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static keyframesArrayFromCSS(cssKeyframes: Object): Array<keyframeAnimationModule.KeyframeInfo> {
|
||||||
|
let parsedKeyframes = new Array<keyframeAnimationModule.KeyframeInfo>();
|
||||||
|
for (let keyframe of (<any>cssKeyframes).keyframes) {
|
||||||
|
let declarations = CssAnimationParser.parseKeyframeDeclarations(keyframe);
|
||||||
|
for (let time of keyframe.values) {
|
||||||
|
if (time === "from") {
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
else if (time === "to") {
|
||||||
|
time = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
time = parseFloat(time) / 100;
|
||||||
|
if (time < 0) {
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
if (time > 100) {
|
||||||
|
time = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let current = parsedKeyframes[time];
|
||||||
|
if (current === undefined) {
|
||||||
|
current = <keyframeAnimationModule.KeyframeInfo>{};
|
||||||
|
current.duration = time;
|
||||||
|
parsedKeyframes[time] = current;
|
||||||
|
}
|
||||||
|
for (let declaration of <any>keyframe.declarations) {
|
||||||
|
if (declaration.property === "animation-timing-function") {
|
||||||
|
current.curve = converters.animationTimingFunctionConverter(declaration.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.declarations = declarations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let array = new Array();
|
||||||
|
for (let parsedKeyframe in parsedKeyframes) {
|
||||||
|
array.push(parsedKeyframes[parsedKeyframe]);
|
||||||
|
}
|
||||||
|
array.sort(function (a, b) { return a.duration - b.duration; });
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static keyframeAnimationsFromCSSProperty(value: any, animations: Array<keyframeAnimationModule.KeyframeAnimationInfo>) {
|
||||||
|
if (types.isString(value)) {
|
||||||
|
let values = value.split(/[,]+/);
|
||||||
|
for (let parsedValue of values) {
|
||||||
|
let animationInfo = new keyframeAnimationModule.KeyframeAnimationInfo();
|
||||||
|
let arr = (<string>parsedValue).trim().split(/[ ]+/);
|
||||||
|
|
||||||
|
if (arr.length > 0) {
|
||||||
|
animationInfo.name = arr[0];
|
||||||
|
}
|
||||||
|
if (arr.length > 1) {
|
||||||
|
animationInfo.duration = converters.timeConverter(arr[1]);
|
||||||
|
}
|
||||||
|
if (arr.length > 2) {
|
||||||
|
animationInfo.curve = converters.animationTimingFunctionConverter(arr[2]);
|
||||||
|
}
|
||||||
|
if (arr.length > 3) {
|
||||||
|
animationInfo.delay = converters.timeConverter(arr[3]);
|
||||||
|
}
|
||||||
|
if (arr.length > 4) {
|
||||||
|
animationInfo.iterations = parseInt(arr[4]);
|
||||||
|
}
|
||||||
|
if (arr.length > 5) {
|
||||||
|
animationInfo.isReverse = arr[4] === "reverse";
|
||||||
|
}
|
||||||
|
if (arr.length > 6) {
|
||||||
|
animationInfo.isForwards = arr[5] === "forwards";
|
||||||
|
}
|
||||||
|
if (arr.length > 7) {
|
||||||
|
throw new Error("Invalid value for animation: " + value);
|
||||||
|
}
|
||||||
|
animations.push(animationInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static parseKeyframeDeclarations(keyframe: Object): Array<keyframeAnimationModule.KeyframeDeclaration> {
|
||||||
|
let declarations = {};
|
||||||
|
let transforms = { scale: undefined, translate: undefined };
|
||||||
|
for (let declaration of (<any>keyframe).declarations) {
|
||||||
|
let property = styleProperty.getPropertyByCssName(declaration.property);
|
||||||
|
if (property) {
|
||||||
|
let val = declaration.value;
|
||||||
|
if (property.name === "opacity") {
|
||||||
|
val = parseFloat(val);
|
||||||
|
}
|
||||||
|
else if (property.name === "backgroundColor") {
|
||||||
|
val = new colorModule.Color(val);
|
||||||
|
}
|
||||||
|
declarations[property.name] = val;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let pairs = styleProperty.getShorthandPairs(declaration.property, declaration.value);
|
||||||
|
if (pairs) {
|
||||||
|
for (let j = 0; j < pairs.length; j++) {
|
||||||
|
let pair = pairs[j];
|
||||||
|
if (!this.preprocessAnimationValues(pair, transforms)) {
|
||||||
|
declarations[pair.property.name] = pair.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transforms.scale !== undefined) {
|
||||||
|
declarations["scale"] = transforms.scale;
|
||||||
|
}
|
||||||
|
if (transforms.translate !== undefined) {
|
||||||
|
declarations["translate"] = transforms.translate;
|
||||||
|
}
|
||||||
|
let array = new Array<keyframeAnimationModule.KeyframeDeclaration>();
|
||||||
|
for (let declaration in declarations) {
|
||||||
|
let keyframeDeclaration = <keyframeAnimationModule.KeyframeDeclaration>{};
|
||||||
|
keyframeDeclaration.property = declaration;
|
||||||
|
keyframeDeclaration.value = declarations[declaration];
|
||||||
|
array.push(keyframeDeclaration);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static preprocessAnimationValues(pair: styleProperty.KeyValuePair<styleProperty.Property, any>, transforms: TransformInfo) {
|
||||||
|
if (pair.property.name === "scaleX") {
|
||||||
|
if (transforms.scale === undefined) {
|
||||||
|
transforms.scale = { x: 1, y: 1 };
|
||||||
|
}
|
||||||
|
transforms.scale.x = pair.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pair.property.name === "scaleY") {
|
||||||
|
if (transforms.scale === undefined) {
|
||||||
|
transforms.scale = { x: 1, y: 1 };
|
||||||
|
}
|
||||||
|
transforms.scale.y = pair.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pair.property.name === "translateX") {
|
||||||
|
if (transforms.translate === undefined) {
|
||||||
|
transforms.translate = { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
transforms.translate.x = pair.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pair.property.name === "translateY") {
|
||||||
|
if (transforms.translate === undefined) {
|
||||||
|
transforms.translate = { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
transforms.translate.y = pair.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
5
ui/styling/css-selector.d.ts
vendored
5
ui/styling/css-selector.d.ts
vendored
@ -2,6 +2,7 @@
|
|||||||
import view = require("ui/core/view");
|
import view = require("ui/core/view");
|
||||||
import cssParser = require("css");
|
import cssParser = require("css");
|
||||||
import styleProperty = require("ui/styling/style-property");
|
import styleProperty = require("ui/styling/style-property");
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
|
||||||
export class CssSelector {
|
export class CssSelector {
|
||||||
constructor(expression: string, declarations: cssParser.Declaration[]);
|
constructor(expression: string, declarations: cssParser.Declaration[]);
|
||||||
@ -13,9 +14,11 @@
|
|||||||
|
|
||||||
specificity: number;
|
specificity: number;
|
||||||
|
|
||||||
|
animations: Array<keyframeAnimation.KeyframeAnimationInfo>;
|
||||||
|
|
||||||
matches(view: view.View): boolean;
|
matches(view: view.View): boolean;
|
||||||
|
|
||||||
apply(view: view.View);
|
apply(view: view.View, valueSourceModifier: number);
|
||||||
|
|
||||||
eachSetter(callback: (property: styleProperty.Property, resolvedValue: any) => void);
|
eachSetter(callback: (property: styleProperty.Property, resolvedValue: any) => void);
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,18 @@ import * as trace from "trace";
|
|||||||
import * as styleProperty from "ui/styling/style-property";
|
import * as styleProperty from "ui/styling/style-property";
|
||||||
import * as types from "utils/types";
|
import * as types from "utils/types";
|
||||||
import * as utils from "utils/utils";
|
import * as utils from "utils/utils";
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
import cssAnimationParser = require("./css-animation-parser");
|
||||||
import {getSpecialPropertySetter} from "ui/builder/special-properties";
|
import {getSpecialPropertySetter} from "ui/builder/special-properties";
|
||||||
|
|
||||||
var ID_SPECIFICITY = 1000000;
|
let ID_SPECIFICITY = 1000000;
|
||||||
var ATTR_SPECIFITY = 10000;
|
let ATTR_SPECIFITY = 10000;
|
||||||
var CLASS_SPECIFICITY = 100;
|
let CLASS_SPECIFICITY = 100;
|
||||||
var TYPE_SPECIFICITY = 1;
|
let TYPE_SPECIFICITY = 1;
|
||||||
|
|
||||||
export class CssSelector {
|
export class CssSelector {
|
||||||
|
public animations: Array<keyframeAnimation.KeyframeAnimationInfo>;
|
||||||
|
|
||||||
private _expression: string;
|
private _expression: string;
|
||||||
private _declarations: cssParser.Declaration[];
|
private _declarations: cssParser.Declaration[];
|
||||||
private _attrExpression: string;
|
private _attrExpression: string;
|
||||||
@ -22,7 +26,7 @@ export class CssSelector {
|
|||||||
let leftSquareBracketIndex = expression.indexOf(LSBRACKET);
|
let leftSquareBracketIndex = expression.indexOf(LSBRACKET);
|
||||||
if (leftSquareBracketIndex > 0) {
|
if (leftSquareBracketIndex > 0) {
|
||||||
// extracts what is inside square brackets ([target = 'test'] will extract "target = 'test'")
|
// extracts what is inside square brackets ([target = 'test'] will extract "target = 'test'")
|
||||||
var paramsRegex = /\[\s*(.*)\s*\]/;
|
let paramsRegex = /\[\s*(.*)\s*\]/;
|
||||||
let attrParams = paramsRegex.exec(expression);
|
let attrParams = paramsRegex.exec(expression);
|
||||||
if (attrParams && attrParams.length > 1) {
|
if (attrParams && attrParams.length > 1) {
|
||||||
this._attrExpression = attrParams[1].trim();
|
this._attrExpression = attrParams[1].trim();
|
||||||
@ -34,6 +38,7 @@ export class CssSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._declarations = declarations;
|
this._declarations = declarations;
|
||||||
|
this.animations = cssAnimationParser.CssAnimationParser.keyframeAnimationsFromCSSDeclarations(declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
get expression(): string {
|
get expression(): string {
|
||||||
@ -52,13 +57,18 @@ export class CssSelector {
|
|||||||
throw "Specificity property is abstract";
|
throw "Specificity property is abstract";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected get valueSourceModifier(): number {
|
||||||
|
return observable.ValueSource.Css;
|
||||||
|
}
|
||||||
|
|
||||||
public matches(view: view.View): boolean {
|
public matches(view: view.View): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public apply(view: view.View) {
|
public apply(view: view.View, valueSourceModifier: number) {
|
||||||
|
let modifier = valueSourceModifier || this.valueSourceModifier;
|
||||||
this.eachSetter((property, value) => {
|
this.eachSetter((property, value) => {
|
||||||
if(types.isString(property)) {
|
if (types.isString(property)) {
|
||||||
let attrHandled = false;
|
let attrHandled = false;
|
||||||
let specialSetter = getSpecialPropertySetter(property);
|
let specialSetter = getSpecialPropertySetter(property);
|
||||||
|
|
||||||
@ -72,12 +82,20 @@ export class CssSelector {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
view.style._setValue(property, value, observable.ValueSource.Css);
|
view.style._setValue(property, value, modifier);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
trace.write("Error setting property: " + property.name + " view: " + view + " value: " + value + " " + ex, trace.categories.Style, trace.messageType.error);
|
trace.write("Error setting property: " + property.name + " view: " + view + " value: " + value + " " + ex, trace.categories.Style, trace.messageType.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (this.animations && view.isLoaded) {
|
||||||
|
for (let animationInfo of this.animations) {
|
||||||
|
let realAnimation = keyframeAnimation.KeyframeAnimation.keyframeAnimationFromInfo(animationInfo, modifier);
|
||||||
|
if (realAnimation) {
|
||||||
|
realAnimation.play(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public eachSetter(callback: (property, resolvedValue: any) => void) {
|
public eachSetter(callback: (property, resolvedValue: any) => void) {
|
||||||
@ -93,7 +111,7 @@ export class CssSelector {
|
|||||||
callback(property, resolvedValue);
|
callback(property, resolvedValue);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var pairs = styleProperty.getShorthandPairs(name, resolvedValue);
|
let pairs = styleProperty.getShorthandPairs(name, resolvedValue);
|
||||||
if (pairs) {
|
if (pairs) {
|
||||||
for (let j = 0; j < pairs.length; j++) {
|
for (let j = 0; j < pairs.length; j++) {
|
||||||
let pair = pairs[j];
|
let pair = pairs[j];
|
||||||
@ -178,7 +196,7 @@ class CssClassSelector extends CssSelector {
|
|||||||
return CLASS_SPECIFICITY;
|
return CLASS_SPECIFICITY;
|
||||||
}
|
}
|
||||||
public matches(view: view.View): boolean {
|
public matches(view: view.View): boolean {
|
||||||
var expectedClass = this.expression;
|
let expectedClass = this.expression;
|
||||||
let result = view._cssClasses.some((cssClass, i, arr) => { return cssClass === expectedClass });
|
let result = view._cssClasses.some((cssClass, i, arr) => { return cssClass === expectedClass });
|
||||||
if (result && this.attrExpression) {
|
if (result && this.attrExpression) {
|
||||||
return matchesAttr(this.attrExpression, view);
|
return matchesAttr(this.attrExpression, view);
|
||||||
@ -357,10 +375,14 @@ export class CssVisualStateSelector extends CssSelector {
|
|||||||
return this._state;
|
return this._state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected get valueSourceModifier(): number {
|
||||||
|
return observable.ValueSource.VisualState;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(expression: string, declarations: cssParser.Declaration[]) {
|
constructor(expression: string, declarations: cssParser.Declaration[]) {
|
||||||
super(expression, declarations);
|
super(expression, declarations);
|
||||||
|
|
||||||
var args = expression.split(COLON);
|
let args = expression.split(COLON);
|
||||||
this._key = args[0];
|
this._key = args[0];
|
||||||
this._state = args[1];
|
this._state = args[1];
|
||||||
|
|
||||||
@ -381,13 +403,13 @@ export class CssVisualStateSelector extends CssSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public matches(view: view.View): boolean {
|
public matches(view: view.View): boolean {
|
||||||
var matches = true;
|
let matches = true;
|
||||||
if (this._isById) {
|
if (this._isById) {
|
||||||
matches = this._match === view.id;
|
matches = this._match === view.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._isByClass) {
|
if (this._isByClass) {
|
||||||
var expectedClass = this._match;
|
let expectedClass = this._match;
|
||||||
matches = view._cssClasses.some((cssClass, i, arr) => { return cssClass === expectedClass });
|
matches = view._cssClasses.some((cssClass, i, arr) => { return cssClass === expectedClass });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,18 +429,18 @@ export class CssVisualStateSelector extends CssSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var HASH = "#";
|
let HASH = "#";
|
||||||
var DOT = ".";
|
let DOT = ".";
|
||||||
var COLON = ":";
|
let COLON = ":";
|
||||||
var SPACE = " ";
|
let SPACE = " ";
|
||||||
var GTHAN = ">";
|
let GTHAN = ">";
|
||||||
var LSBRACKET = "[";
|
let LSBRACKET = "[";
|
||||||
var RSBRACKET = "]";
|
let RSBRACKET = "]";
|
||||||
var EQUAL = "=";
|
let EQUAL = "=";
|
||||||
|
|
||||||
export function createSelector(expression: string, declarations: cssParser.Declaration[]): CssSelector {
|
export function createSelector(expression: string, declarations: cssParser.Declaration[]): CssSelector {
|
||||||
let goodExpr = expression.replace(/>/g, " > ").replace(/\s\s+/g, " ");
|
let goodExpr = expression.replace(/>/g, " > ").replace(/\s\s+/g, " ");
|
||||||
var spaceIndex = goodExpr.indexOf(SPACE);
|
let spaceIndex = goodExpr.indexOf(SPACE);
|
||||||
if (spaceIndex >= 0) {
|
if (spaceIndex >= 0) {
|
||||||
return new CssCompositeSelector(goodExpr, declarations);
|
return new CssCompositeSelector(goodExpr, declarations);
|
||||||
}
|
}
|
||||||
@ -462,6 +484,6 @@ class InlineStyleSelector extends CssSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyInlineSyle(view: view.View, declarations: cssParser.Declaration[]) {
|
export function applyInlineSyle(view: view.View, declarations: cssParser.Declaration[]) {
|
||||||
var localStyleSelector = new InlineStyleSelector(declarations);
|
let localStyleSelector = new InlineStyleSelector(declarations);
|
||||||
localStyleSelector.apply(view);
|
localStyleSelector.apply(view);
|
||||||
}
|
}
|
||||||
|
4
ui/styling/style-scope.d.ts
vendored
4
ui/styling/style-scope.d.ts
vendored
@ -3,6 +3,7 @@ declare module "ui/styling/style-scope" {
|
|||||||
import view = require("ui/core/view");
|
import view = require("ui/core/view");
|
||||||
import cssSelector = require("ui/styling/css-selector");
|
import cssSelector = require("ui/styling/css-selector");
|
||||||
import cssParser = require("css");
|
import cssParser = require("css");
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
|
||||||
export class StyleScope {
|
export class StyleScope {
|
||||||
public css: string;
|
public css: string;
|
||||||
@ -14,6 +15,9 @@ declare module "ui/styling/style-scope" {
|
|||||||
|
|
||||||
public applySelectors(view: view.View): void
|
public applySelectors(view: view.View): void
|
||||||
public getVisualStates(view: view.View): Object;
|
public getVisualStates(view: view.View): Object;
|
||||||
|
|
||||||
|
public removeSelectors(selectorExpression: string);
|
||||||
|
public getKeyframeAnimationWithName(animationName: string): keyframeAnimation.KeyframeAnimationInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyInlineSyle(view: view.View, style: string): void;
|
export function applyInlineSyle(view: view.View, style: string): void;
|
||||||
|
@ -7,6 +7,9 @@ import * as typesModule from "utils/types";
|
|||||||
import * as utilsModule from "utils/utils";
|
import * as utilsModule from "utils/utils";
|
||||||
import * as fileSystemModule from "file-system";
|
import * as fileSystemModule from "file-system";
|
||||||
import * as visualStateModule from "./visual-state";
|
import * as visualStateModule from "./visual-state";
|
||||||
|
import keyframeAnimation = require("ui/animation/keyframe-animation");
|
||||||
|
import cssAnimationParser = require("./css-animation-parser");
|
||||||
|
import observable = require("ui/core/dependency-observable");
|
||||||
|
|
||||||
var types: typeof typesModule;
|
var types: typeof typesModule;
|
||||||
function ensureTypes() {
|
function ensureTypes() {
|
||||||
@ -50,10 +53,12 @@ export class StyleScope {
|
|||||||
private _localCssSelectorVersion: number = 0;
|
private _localCssSelectorVersion: number = 0;
|
||||||
private _localCssSelectorsAppliedVersion: number = 0;
|
private _localCssSelectorsAppliedVersion: number = 0;
|
||||||
private _applicationCssSelectorsAppliedVersion: number = 0;
|
private _applicationCssSelectorsAppliedVersion: number = 0;
|
||||||
|
private _keyframes = {};
|
||||||
|
|
||||||
get css(): string {
|
get css(): string {
|
||||||
return this._css;
|
return this._css;
|
||||||
}
|
}
|
||||||
|
|
||||||
set css(value: string) {
|
set css(value: string) {
|
||||||
this._cssFileName = undefined;
|
this._cssFileName = undefined;
|
||||||
this.setCss(value);
|
this.setCss(value);
|
||||||
@ -71,7 +76,7 @@ export class StyleScope {
|
|||||||
|
|
||||||
this._reset();
|
this._reset();
|
||||||
|
|
||||||
const parsedSelectors = StyleScope.createSelectorsFromCss(cssString, cssFileName);
|
const parsedSelectors = StyleScope.createSelectorsFromCss(cssString, cssFileName, this._keyframes);
|
||||||
if (append) {
|
if (append) {
|
||||||
this._localCssSelectors.push.apply(this._localCssSelectors, parsedSelectors);
|
this._localCssSelectors.push.apply(this._localCssSelectors, parsedSelectors);
|
||||||
} else {
|
} else {
|
||||||
@ -82,35 +87,51 @@ export class StyleScope {
|
|||||||
this.ensureSelectors();
|
this.ensureSelectors();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createSelectorsFromCss(css: string, cssFileName: string): cssSelector.CssSelector[] {
|
public removeSelectors(selectorExpression: string) {
|
||||||
try {
|
for (let i = this._mergedCssSelectors.length - 1; i >= 0; i--) {
|
||||||
var pageCssSyntaxTree = css ? cssParser.parse(css, { source: cssFileName }) : null;
|
let selector = this._mergedCssSelectors[i];
|
||||||
|
if (selector.expression === selectorExpression) {
|
||||||
var pageCssSelectors = new Array<cssSelector.CssSelector>();
|
this._mergedCssSelectors.splice(i, 1);
|
||||||
|
}
|
||||||
if (pageCssSyntaxTree) {
|
}
|
||||||
pageCssSelectors = StyleScope._joinCssSelectorsArrays([pageCssSelectors, StyleScope.createSelectorsFromImports(pageCssSyntaxTree)]);
|
|
||||||
pageCssSelectors = StyleScope._joinCssSelectorsArrays([pageCssSelectors, StyleScope.createSelectorsFromSyntaxTree(pageCssSyntaxTree)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getKeyframeAnimationWithName(animationName: string): keyframeAnimation.KeyframeAnimationInfo {
|
||||||
|
let keyframes = this._keyframes[animationName];
|
||||||
|
if (keyframes !== undefined) {
|
||||||
|
let animation = new keyframeAnimation.KeyframeAnimationInfo();
|
||||||
|
animation.keyframes = cssAnimationParser.CssAnimationParser.keyframesArrayFromCSS(keyframes);
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static createSelectorsFromCss(css: string, cssFileName: string, keyframes: Object): cssSelector.CssSelector[] {
|
||||||
|
try {
|
||||||
|
let pageCssSyntaxTree = css ? cssParser.parse(css, { source: cssFileName }) : null;
|
||||||
|
let pageCssSelectors = new Array<cssSelector.CssSelector>();
|
||||||
|
if (pageCssSyntaxTree) {
|
||||||
|
pageCssSelectors = StyleScope._joinCssSelectorsArrays([pageCssSelectors, StyleScope.createSelectorsFromImports(pageCssSyntaxTree, keyframes)]);
|
||||||
|
pageCssSelectors = StyleScope._joinCssSelectorsArrays([pageCssSelectors, StyleScope.createSelectorsFromSyntaxTree(pageCssSyntaxTree, keyframes)]);
|
||||||
|
}
|
||||||
return pageCssSelectors;
|
return pageCssSelectors;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
trace.write("Css styling failed: " + e, trace.categories.Error, trace.messageType.error);
|
trace.write("Css styling failed: " + e, trace.categories.Error, trace.messageType.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createSelectorsFromImports(tree: cssParser.SyntaxTree): cssSelector.CssSelector[] {
|
public static createSelectorsFromImports(tree: cssParser.SyntaxTree, keyframes: Object): cssSelector.CssSelector[] {
|
||||||
var selectors = new Array<cssSelector.CssSelector>();
|
let selectors = new Array<cssSelector.CssSelector>();
|
||||||
ensureTypes();
|
ensureTypes();
|
||||||
|
|
||||||
if (!types.isNullOrUndefined(tree)) {
|
if (!types.isNullOrUndefined(tree)) {
|
||||||
var imports = tree["stylesheet"]["rules"].filter(r=> r.type === "import");
|
let imports = tree["stylesheet"]["rules"].filter(r=> r.type === "import");
|
||||||
|
|
||||||
for (var i = 0; i < imports.length; i++) {
|
for (let i = 0; i < imports.length; i++) {
|
||||||
var importItem = imports[i]["import"];
|
let importItem = imports[i]["import"];
|
||||||
|
|
||||||
var match = importItem && (<string>importItem).match(pattern);
|
let match = importItem && (<string>importItem).match(pattern);
|
||||||
var url = match && match[2];
|
let url = match && match[2];
|
||||||
|
|
||||||
if (!types.isNullOrUndefined(url)) {
|
if (!types.isNullOrUndefined(url)) {
|
||||||
ensureUtils();
|
ensureUtils();
|
||||||
@ -118,16 +139,16 @@ export class StyleScope {
|
|||||||
if (utils.isFileOrResourcePath(url)) {
|
if (utils.isFileOrResourcePath(url)) {
|
||||||
ensureFS();
|
ensureFS();
|
||||||
|
|
||||||
var fileName = types.isString(url) ? url.trim() : "";
|
let fileName = types.isString(url) ? url.trim() : "";
|
||||||
if (fileName.indexOf("~/") === 0) {
|
if (fileName.indexOf("~/") === 0) {
|
||||||
fileName = fs.path.join(fs.knownFolders.currentApp().path, fileName.replace("~/", ""));
|
fileName = fs.path.join(fs.knownFolders.currentApp().path, fileName.replace("~/", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs.File.exists(fileName)) {
|
if (fs.File.exists(fileName)) {
|
||||||
var file = fs.File.fromPath(fileName);
|
let file = fs.File.fromPath(fileName);
|
||||||
var text = file.readTextSync();
|
let text = file.readTextSync();
|
||||||
if (text) {
|
if (text) {
|
||||||
selectors = StyleScope._joinCssSelectorsArrays([selectors, StyleScope.createSelectorsFromCss(text, fileName)]);
|
selectors = StyleScope._joinCssSelectorsArrays([selectors, StyleScope.createSelectorsFromCss(text, fileName, keyframes)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,6 +173,7 @@ export class StyleScope {
|
|||||||
|
|
||||||
if (toMerge.length > 0) {
|
if (toMerge.length > 0) {
|
||||||
this._mergedCssSelectors = StyleScope._joinCssSelectorsArrays(toMerge);
|
this._mergedCssSelectors = StyleScope._joinCssSelectorsArrays(toMerge);
|
||||||
|
this._applyKeyframesOnSelectors();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -159,8 +181,8 @@ export class StyleScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _joinCssSelectorsArrays(arrays: Array<Array<cssSelector.CssSelector>>): Array<cssSelector.CssSelector> {
|
private static _joinCssSelectorsArrays(arrays: Array<Array<cssSelector.CssSelector>>): Array<cssSelector.CssSelector> {
|
||||||
var mergedResult = [];
|
let mergedResult = [];
|
||||||
var i;
|
let i;
|
||||||
for (i = 0; i < arrays.length; i++) {
|
for (i = 0; i < arrays.length; i++) {
|
||||||
if (arrays[i]) {
|
if (arrays[i]) {
|
||||||
mergedResult.push.apply(mergedResult, arrays[i]);
|
mergedResult.push.apply(mergedResult, arrays[i]);
|
||||||
@ -175,8 +197,7 @@ export class StyleScope {
|
|||||||
this.ensureSelectors();
|
this.ensureSelectors();
|
||||||
|
|
||||||
view.style._beginUpdate();
|
view.style._beginUpdate();
|
||||||
|
let i,
|
||||||
var i,
|
|
||||||
selector: cssSelector.CssSelector,
|
selector: cssSelector.CssSelector,
|
||||||
matchedStateSelectors = new Array<cssSelector.CssVisualStateSelector>()
|
matchedStateSelectors = new Array<cssSelector.CssVisualStateSelector>()
|
||||||
|
|
||||||
@ -187,14 +208,14 @@ export class StyleScope {
|
|||||||
if (selector instanceof cssSelector.CssVisualStateSelector) {
|
if (selector instanceof cssSelector.CssVisualStateSelector) {
|
||||||
matchedStateSelectors.push(<cssSelector.CssVisualStateSelector>selector);
|
matchedStateSelectors.push(<cssSelector.CssVisualStateSelector>selector);
|
||||||
} else {
|
} else {
|
||||||
selector.apply(view);
|
selector.apply(view, observable.ValueSource.Css);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchedStateSelectors.length > 0) {
|
if (matchedStateSelectors.length > 0) {
|
||||||
// Create a key for all matched selectors for this element
|
// Create a key for all matched selectors for this element
|
||||||
var key: string = "";
|
let key: string = "";
|
||||||
matchedStateSelectors.forEach((s) => key += s.key + "|");
|
matchedStateSelectors.forEach((s) => key += s.key + "|");
|
||||||
|
|
||||||
// Associate the view to the created key
|
// Associate the view to the created key
|
||||||
@ -210,7 +231,7 @@ export class StyleScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getVisualStates(view: view.View): Object {
|
public getVisualStates(view: view.View): Object {
|
||||||
var key = this._viewIdToKey[view._domId];
|
let key = this._viewIdToKey[view._domId];
|
||||||
if (key === undefined) {
|
if (key === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -219,7 +240,7 @@ export class StyleScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _createVisualsStatesForSelectors(key: string, matchedStateSelectors: Array<cssSelector.CssVisualStateSelector>) {
|
private _createVisualsStatesForSelectors(key: string, matchedStateSelectors: Array<cssSelector.CssVisualStateSelector>) {
|
||||||
var i,
|
let i,
|
||||||
allStates = {},
|
allStates = {},
|
||||||
stateSelector: cssSelector.CssVisualStateSelector;
|
stateSelector: cssSelector.CssVisualStateSelector;
|
||||||
|
|
||||||
@ -229,25 +250,30 @@ export class StyleScope {
|
|||||||
for (i = 0; i < matchedStateSelectors.length; i++) {
|
for (i = 0; i < matchedStateSelectors.length; i++) {
|
||||||
stateSelector = matchedStateSelectors[i];
|
stateSelector = matchedStateSelectors[i];
|
||||||
|
|
||||||
var visualState = allStates[stateSelector.state];
|
let visualState = allStates[stateSelector.state];
|
||||||
if (!visualState) {
|
if (!visualState) {
|
||||||
visualState = new vs.VisualState();
|
visualState = new vs.VisualState();
|
||||||
allStates[stateSelector.state] = visualState;
|
allStates[stateSelector.state] = visualState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add all stateSelectors instead of adding setters
|
||||||
|
if (stateSelector.animations && stateSelector.animations.length > 0) {
|
||||||
|
visualState.animatedSelectors.push(stateSelector);
|
||||||
|
}
|
||||||
|
else {
|
||||||
stateSelector.eachSetter((property, value) => {
|
stateSelector.eachSetter((property, value) => {
|
||||||
visualState.setters[property.name] = value;
|
visualState.setters[property.name] = value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static createSelectorsFromSyntaxTree(ast: cssParser.SyntaxTree): Array<cssSelector.CssSelector> {
|
private static createSelectorsFromSyntaxTree(ast: cssParser.SyntaxTree, keyframes: Object): Array<cssSelector.CssSelector> {
|
||||||
var result: Array<cssSelector.CssSelector> = [];
|
let result: Array<cssSelector.CssSelector> = [];
|
||||||
|
let rules = ast.stylesheet.rules;
|
||||||
var rules = ast.stylesheet.rules;
|
let rule: cssParser.Rule;
|
||||||
var rule: cssParser.Rule;
|
let i;
|
||||||
var i;
|
let j;
|
||||||
var j;
|
|
||||||
|
|
||||||
// Create selectors form AST
|
// Create selectors form AST
|
||||||
for (i = 0; i < rules.length; i++) {
|
for (i = 0; i < rules.length; i++) {
|
||||||
@ -256,10 +282,10 @@ export class StyleScope {
|
|||||||
if (rule.type === "rule") {
|
if (rule.type === "rule") {
|
||||||
|
|
||||||
// Filter comment nodes.
|
// Filter comment nodes.
|
||||||
var filteredDeclarations = [];
|
let filteredDeclarations = [];
|
||||||
if (rule.declarations) {
|
if (rule.declarations) {
|
||||||
for (j = 0; j < rule.declarations.length; j++) {
|
for (j = 0; j < rule.declarations.length; j++) {
|
||||||
var declaration = rule.declarations[j];
|
let declaration = rule.declarations[j];
|
||||||
if (declaration.type === "declaration") {
|
if (declaration.type === "declaration") {
|
||||||
filteredDeclarations.push({
|
filteredDeclarations.push({
|
||||||
property: declaration.property.toLowerCase(),
|
property: declaration.property.toLowerCase(),
|
||||||
@ -268,11 +294,12 @@ export class StyleScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < rule.selectors.length; j++) {
|
for (j = 0; j < rule.selectors.length; j++) {
|
||||||
result.push(cssSelector.createSelector(rule.selectors[j], filteredDeclarations));
|
result.push(cssSelector.createSelector(rule.selectors[j], filteredDeclarations));
|
||||||
}
|
}
|
||||||
//}
|
}
|
||||||
|
else if (rule.type === "keyframes") {
|
||||||
|
keyframes[(<any>rule).name] = rule;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,12 +310,26 @@ export class StyleScope {
|
|||||||
this._statesByKey = {};
|
this._statesByKey = {};
|
||||||
this._viewIdToKey = {};
|
this._viewIdToKey = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _applyKeyframesOnSelectors() {
|
||||||
|
for (let i = this._mergedCssSelectors.length - 1; i >= 0; i--) {
|
||||||
|
let selector = this._mergedCssSelectors[i];
|
||||||
|
if (selector.animations !== undefined) {
|
||||||
|
for (let animation of selector.animations) {
|
||||||
|
let keyframe = this._keyframes[animation.name];
|
||||||
|
if (keyframe !== undefined) {
|
||||||
|
animation.keyframes = cssAnimationParser.CssAnimationParser.keyframesArrayFromCSS(keyframe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyInlineSyle(view: view.View, style: string) {
|
export function applyInlineSyle(view: view.View, style: string) {
|
||||||
try {
|
try {
|
||||||
var syntaxTree = cssParser.parse("local { " + style + " }", undefined);
|
let syntaxTree = cssParser.parse("local { " + style + " }", undefined);
|
||||||
var filteredDeclarations = syntaxTree.stylesheet.rules[0].declarations.filter((val, i, arr) => { return val.type === "declaration" });
|
let filteredDeclarations = syntaxTree.stylesheet.rules[0].declarations.filter((val, i, arr) => { return val.type === "declaration" });
|
||||||
cssSelector.applyInlineSyle(view, filteredDeclarations);
|
cssSelector.applyInlineSyle(view, filteredDeclarations);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
trace.write("Applying local style failed: " + ex, trace.categories.Error, trace.messageType.error);
|
trace.write("Applying local style failed: " + ex, trace.categories.Error, trace.messageType.error);
|
||||||
|
11
ui/styling/style.d.ts
vendored
11
ui/styling/style.d.ts
vendored
@ -35,6 +35,11 @@ declare module "ui/styling/style" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Style extends DependencyObservable implements styling.Style {
|
export class Style extends DependencyObservable implements styling.Style {
|
||||||
|
public rotate: number;
|
||||||
|
public translateX: number;
|
||||||
|
public translateY: number;
|
||||||
|
public scaleX: number;
|
||||||
|
public scaleY: number;
|
||||||
public color: Color;
|
public color: Color;
|
||||||
public backgroundColor: Color;
|
public backgroundColor: Color;
|
||||||
public backgroundImage: string;
|
public backgroundImage: string;
|
||||||
@ -89,6 +94,12 @@ declare module "ui/styling/style" {
|
|||||||
export function registerNoStylingClass(className);
|
export function registerNoStylingClass(className);
|
||||||
export function getHandler(property: Property, view: View): StylePropertyChangedHandler;
|
export function getHandler(property: Property, view: View): StylePropertyChangedHandler;
|
||||||
// Property registration
|
// Property registration
|
||||||
|
|
||||||
|
export var rotateProperty: styleProperty.Property;
|
||||||
|
export var translateXProperty: styleProperty.Property;
|
||||||
|
export var translateYProperty: styleProperty.Property;
|
||||||
|
export var scaleXProperty: styleProperty.Property;
|
||||||
|
export var scaleYProperty: styleProperty.Property;
|
||||||
export var colorProperty: styleProperty.Property;
|
export var colorProperty: styleProperty.Property;
|
||||||
export var backgroundImageProperty: styleProperty.Property;
|
export var backgroundImageProperty: styleProperty.Property;
|
||||||
export var backgroundColorProperty: styleProperty.Property;
|
export var backgroundColorProperty: styleProperty.Property;
|
||||||
|
@ -470,6 +470,46 @@ export class Style extends DependencyObservable implements styling.Style {
|
|||||||
private _updateCounter = 0;
|
private _updateCounter = 0;
|
||||||
private _nativeSetters = new Map<Property, any>();
|
private _nativeSetters = new Map<Property, any>();
|
||||||
|
|
||||||
|
get rotate(): number {
|
||||||
|
return this._getValue(rotateProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
set rotate(value: number) {
|
||||||
|
this._setValue(rotateProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get scaleX(): number {
|
||||||
|
return this._getValue(scaleXProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
set scaleX(value: number) {
|
||||||
|
this._setValue(scaleXProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get scaleY(): number {
|
||||||
|
return this._getValue(scaleYProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
set scaleY(value: number) {
|
||||||
|
this._setValue(scaleYProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get translateX(): number {
|
||||||
|
return this._getValue(translateXProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
set translateX(value: number) {
|
||||||
|
this._setValue(translateXProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get translateY(): number {
|
||||||
|
return this._getValue(translateYProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
set translateY(value: number) {
|
||||||
|
this._setValue(translateYProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
get color(): Color {
|
get color(): Color {
|
||||||
return this._getValue(colorProperty);
|
return this._getValue(colorProperty);
|
||||||
}
|
}
|
||||||
@ -934,6 +974,22 @@ export function getHandler(property: Property, view: View): definition.StyleProp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Property registration
|
// Property registration
|
||||||
|
|
||||||
|
export var rotateProperty = new styleProperty.Property("rotate", "rotate",
|
||||||
|
new PropertyMetadata(undefined, PropertyMetadataSettings.None, null));
|
||||||
|
|
||||||
|
export var scaleXProperty = new styleProperty.Property("scaleX", "scaleX",
|
||||||
|
new PropertyMetadata(undefined, PropertyMetadataSettings.None, null));
|
||||||
|
|
||||||
|
export var scaleYProperty = new styleProperty.Property("scaleY", "scaleY",
|
||||||
|
new PropertyMetadata(undefined, PropertyMetadataSettings.None, null));
|
||||||
|
|
||||||
|
export var translateXProperty = new styleProperty.Property("translateX", "translateX",
|
||||||
|
new PropertyMetadata(undefined, PropertyMetadataSettings.None, null));
|
||||||
|
|
||||||
|
export var translateYProperty = new styleProperty.Property("translateY", "translateY",
|
||||||
|
new PropertyMetadata(undefined, PropertyMetadataSettings.None, null));
|
||||||
|
|
||||||
export var colorProperty = new styleProperty.Property("color", "color",
|
export var colorProperty = new styleProperty.Property("color", "color",
|
||||||
new PropertyMetadata(undefined, PropertyMetadataSettings.Inheritable, undefined, Color.isValid, Color.equals),
|
new PropertyMetadata(undefined, PropertyMetadataSettings.Inheritable, undefined, Color.isValid, Color.equals),
|
||||||
converters.colorConverter);
|
converters.colorConverter);
|
||||||
@ -1132,10 +1188,65 @@ function onFontChanged(value: any): Array<styleProperty.KeyValuePair<styleProper
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onTransformChanged(value: any): Array<styleProperty.KeyValuePair<styleProperty.Property, any>> {
|
||||||
|
var newTransform = converters.transformConverter(value);
|
||||||
|
var array = new Array<styleProperty.KeyValuePair<styleProperty.Property, any>>();
|
||||||
|
var values = undefined;
|
||||||
|
for (var transform in newTransform) {
|
||||||
|
switch (transform) {
|
||||||
|
case "scaleX":
|
||||||
|
array.push({ property: scaleXProperty, value: parseFloat(newTransform[transform]) });
|
||||||
|
break;
|
||||||
|
case "scaleY":
|
||||||
|
array.push({ property: scaleYProperty, value: parseFloat(newTransform[transform]) });
|
||||||
|
break;
|
||||||
|
case "scale":
|
||||||
|
case "scale3d":
|
||||||
|
values = newTransform[transform].split(",");
|
||||||
|
if (values.length === 2 || values.length === 3) {
|
||||||
|
array.push({ property: scaleXProperty, value: parseFloat(values[0]) });
|
||||||
|
array.push({ property: scaleYProperty, value: parseFloat(values[1]) });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "translateX":
|
||||||
|
array.push({ property: translateXProperty, value: parseFloat(newTransform[transform]) });
|
||||||
|
break;
|
||||||
|
case "translateY":
|
||||||
|
array.push({ property: translateYProperty, value: parseFloat(newTransform[transform]) });
|
||||||
|
break;
|
||||||
|
case "translate":
|
||||||
|
case "translate3d":
|
||||||
|
values = newTransform[transform].split(",");
|
||||||
|
if (values.length === 2 || values.length === 3) {
|
||||||
|
array.push({ property: translateXProperty, value: parseFloat(values[0]) });
|
||||||
|
array.push({ property: translateYProperty, value: parseFloat(values[1]) });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "rotate":
|
||||||
|
let text = newTransform[transform];
|
||||||
|
let val = parseFloat(text);
|
||||||
|
if (text.slice(-3) === "rad") {
|
||||||
|
val = val * (180.0 / Math.PI);
|
||||||
|
}
|
||||||
|
array.push({ property: rotateProperty, value: val });
|
||||||
|
break;
|
||||||
|
case "none":
|
||||||
|
array.push({ property: scaleXProperty, value: 1 });
|
||||||
|
array.push({ property: scaleYProperty, value: 1 });
|
||||||
|
array.push({ property: translateXProperty, value: 0 });
|
||||||
|
array.push({ property: translateYProperty, value: 0 });
|
||||||
|
array.push({ property: rotateProperty, value: 0 });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
// register default shorthand callbacks.
|
// register default shorthand callbacks.
|
||||||
styleProperty.registerShorthandCallback("font", onFontChanged);
|
styleProperty.registerShorthandCallback("font", onFontChanged);
|
||||||
styleProperty.registerShorthandCallback("margin", onMarginChanged);
|
styleProperty.registerShorthandCallback("margin", onMarginChanged);
|
||||||
styleProperty.registerShorthandCallback("padding", onPaddingChanged);
|
styleProperty.registerShorthandCallback("padding", onPaddingChanged);
|
||||||
|
styleProperty.registerShorthandCallback("transform", onTransformChanged);
|
||||||
|
|
||||||
var _defaultNativeValuesCache = {};
|
var _defaultNativeValuesCache = {};
|
||||||
|
|
||||||
|
@ -1,31 +1,38 @@
|
|||||||
import viewModule = require("ui/core/view");
|
import viewModule = require("ui/core/view");
|
||||||
import observable = require("ui/core/dependency-observable");
|
import observable = require("ui/core/dependency-observable");
|
||||||
import styleProperty = require("ui/styling/style-property");
|
import styleProperty = require("ui/styling/style-property");
|
||||||
|
import cssSelector = require("ui/styling/css-selector");
|
||||||
import * as visualStateConstants from "ui/styling/visual-state-constants";
|
import * as visualStateConstants from "ui/styling/visual-state-constants";
|
||||||
|
|
||||||
export class VisualState {
|
export class VisualState {
|
||||||
private _setters: {};
|
private _setters: {}; // use css selector instead
|
||||||
|
private _animatedSelectors: cssSelector.CssVisualStateSelector[];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._setters = {};
|
this._setters = {};
|
||||||
|
this._animatedSelectors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get setters(): {} {
|
get setters(): {} {
|
||||||
return this._setters;
|
return this._setters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get animatedSelectors(): cssSelector.CssVisualStateSelector[] {
|
||||||
|
return this._animatedSelectors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export function goToState(view: viewModule.View, state: string): string {
|
export function goToState(view: viewModule.View, state: string): string {
|
||||||
var root = <any>view.page;
|
let root = <any>view.page;
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: this of optimization
|
//TODO: this of optimization
|
||||||
var allStates = root._getStyleScope().getVisualStates(view);
|
let allStates = root._getStyleScope().getVisualStates(view);
|
||||||
if (!allStates) {
|
if (!allStates) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -44,8 +51,8 @@ export function goToState(view: viewModule.View, state: string): string {
|
|||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
if (state !== view.visualState) {
|
if (state !== view.visualState) {
|
||||||
var newState: VisualState = allStates[state];
|
let newState: VisualState = allStates[state];
|
||||||
var oldState: VisualState = allStates[view.visualState];
|
let oldState: VisualState = allStates[view.visualState];
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
resetProperties(view, oldState, newState);
|
resetProperties(view, oldState, newState);
|
||||||
@ -62,9 +69,9 @@ function resetProperties(view: viewModule.View, oldState: VisualState, newState:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var property: styleProperty.Property;
|
let property: styleProperty.Property;
|
||||||
|
|
||||||
for (var name in oldState.setters) {
|
for (let name in oldState.setters) {
|
||||||
if (newState && (name in newState.setters)) {
|
if (newState && (name in newState.setters)) {
|
||||||
// Property will be altered by the new state, no need to reset it.
|
// Property will be altered by the new state, no need to reset it.
|
||||||
continue;
|
continue;
|
||||||
@ -75,6 +82,19 @@ function resetProperties(view: viewModule.View, oldState: VisualState, newState:
|
|||||||
view.style._resetValue(property, observable.ValueSource.VisualState);
|
view.style._resetValue(property, observable.ValueSource.VisualState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let selector of oldState.animatedSelectors) {
|
||||||
|
for (let animationInfo of selector.animations) {
|
||||||
|
for (let keyframe of animationInfo.keyframes) {
|
||||||
|
for (let declaration of keyframe.declarations) {
|
||||||
|
property = styleProperty.getPropertyByName(declaration.property);
|
||||||
|
if (property) {
|
||||||
|
view.style._resetValue(property, observable.ValueSource.VisualState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyProperties(view: viewModule.View, state: VisualState) {
|
function applyProperties(view: viewModule.View, state: VisualState) {
|
||||||
@ -82,12 +102,16 @@ function applyProperties(view: viewModule.View, state: VisualState) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var property: styleProperty.Property;
|
let property: styleProperty.Property;
|
||||||
|
|
||||||
for (var name in state.setters) {
|
for (let name in state.setters) {
|
||||||
property = styleProperty.getPropertyByName(name);
|
property = styleProperty.getPropertyByName(name);
|
||||||
if (property) {
|
if (property) {
|
||||||
view.style._setValue(property, state.setters[name], observable.ValueSource.VisualState);
|
view.style._setValue(property, state.setters[name], observable.ValueSource.VisualState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let selector of state.animatedSelectors) {
|
||||||
|
selector.apply(view, observable.ValueSource.VisualState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user