mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 11:42:04 +08:00
Support for hierarchical and attribute css selectors.
This commit is contained in:
@ -3,6 +3,7 @@ import buttonModule = require("ui/button");
|
|||||||
import labelModule = require("ui/label");
|
import labelModule = require("ui/label");
|
||||||
import pageModule = require("ui/page");
|
import pageModule = require("ui/page");
|
||||||
import stackModule = require("ui/layouts/stack-layout");
|
import stackModule = require("ui/layouts/stack-layout");
|
||||||
|
import wrapModule = require("ui/layouts/wrap-layout");
|
||||||
import tabViewModule = require("ui/tab-view");
|
import tabViewModule = require("ui/tab-view");
|
||||||
import helper = require("../../ui/helper");
|
import helper = require("../../ui/helper");
|
||||||
import styling = require("ui/styling");
|
import styling = require("ui/styling");
|
||||||
@ -384,87 +385,66 @@ export function test_restore_original_values_when_state_is_changed() {
|
|||||||
helper.goBack();
|
helper.goBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Complex composite selectors are not supported yet
|
export var test_composite_selector_type_and_class = function () {
|
||||||
//export var test_composite_selector_type_and_class = function () {
|
// Arrange
|
||||||
// // Arrange
|
var testStack = new stackModule.StackLayout();
|
||||||
// var testPage = new page.Page();
|
|
||||||
// var testStack = new stack.StackLayout();
|
|
||||||
// testPage.content = testStack;
|
|
||||||
|
|
||||||
// var btnWithClass = new button.Button();
|
var btnWithClass = new buttonModule.Button();
|
||||||
// btnWithClass.className = "test";
|
btnWithClass.className = "test";
|
||||||
// testStack.addChild(btnWithClass);
|
testStack.addChild(btnWithClass);
|
||||||
|
|
||||||
// var btnWithNoClass = new button.Button();
|
var btnWithNoClass = new buttonModule.Button();
|
||||||
// testStack.addChild(btnWithNoClass);
|
testStack.addChild(btnWithNoClass);
|
||||||
|
|
||||||
// var lblWithClass = new label.Label();
|
var lblWithClass = new labelModule.Label();
|
||||||
// lblWithClass.className = "test";
|
lblWithClass.className = "test";
|
||||||
// testStack.addChild(lblWithClass);
|
testStack.addChild(lblWithClass);
|
||||||
|
|
||||||
// testPage.css = "button.test { color: red; }";
|
let testCss = "button.test { color: red; }";
|
||||||
|
|
||||||
|
let testFunc = function(views: Array<viewModule.View>) {
|
||||||
|
TKUnit.assert(btnWithClass.style.color, "Color property no applied correctly.");
|
||||||
|
TKUnit.assert(btnWithClass.style.color.hex === "#FF0000", "Color property no applied correctly.");
|
||||||
|
|
||||||
// // Act & Assert
|
TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value");
|
||||||
// var finished = false;
|
|
||||||
// testPage.onNavigatedTo = function (context) {
|
|
||||||
// TKUnit.assert(btnWithClass.style.color, "Color property no applied correctly.");
|
|
||||||
// TKUnit.assert(btnWithClass.style.color.hex === "#FF0000", "Color property no applied correctly.");
|
|
||||||
|
|
||||||
// TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value");
|
TKUnit.assert(lblWithClass.style.color === undefined, "Color should not have a value");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(testStack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
// TKUnit.assert(lblWithClass.style.color === undefined, "Color should not have a value");
|
export var test_composite_selector_type_class_state = function () {
|
||||||
|
// Arrange
|
||||||
|
var testStack = new stackModule.StackLayout();
|
||||||
|
|
||||||
|
var btnWithClass = new buttonModule.Button();
|
||||||
|
btnWithClass.className = "test";
|
||||||
|
testStack.addChild(btnWithClass);
|
||||||
|
|
||||||
// finished = true;
|
var btnWithNoClass = new buttonModule.Button();
|
||||||
// };
|
testStack.addChild(btnWithNoClass);
|
||||||
// frame.topmost().navigate(testPage);
|
|
||||||
|
|
||||||
// TKUnit.waitUntilReady(function () {
|
var lblWithClass = new labelModule.Label();
|
||||||
// return finished;
|
lblWithClass.className = "test";
|
||||||
// }, 3);
|
testStack.addChild(lblWithClass);
|
||||||
//}
|
|
||||||
|
|
||||||
// TODO: Complex composite selectors are not supported yet
|
let testCss = "button.test:pressed { color: red; }";
|
||||||
//export var test_composite_selector_type_class_state = function () {
|
|
||||||
// // Arrange
|
let testFunc = function(views: Array<viewModule.View>) {
|
||||||
// var testPage = new page.Page();
|
testButtonPressedStateIsRed(btnWithClass);
|
||||||
// var testStack = new stack.StackLayout();
|
|
||||||
// testPage.content = testStack;
|
|
||||||
|
|
||||||
// var btnWithClass = new button.Button();
|
// The button with no class should not react to state changes.
|
||||||
// btnWithClass.className = "test";
|
TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value.");
|
||||||
// testStack.addChild(btnWithClass);
|
btnWithNoClass._goToVisualState("pressed");
|
||||||
|
TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value.");
|
||||||
|
btnWithNoClass._goToVisualState("normal");
|
||||||
|
TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value.");
|
||||||
|
|
||||||
// var btnWithNoClass = new button.Button();
|
TKUnit.assert(lblWithClass.style.color === undefined, "Color should not have a value");
|
||||||
// testStack.addChild(btnWithNoClass);
|
}
|
||||||
|
helper.buildUIAndRunTest(testStack, testFunc, testCss);
|
||||||
// var lblWithClass = new label.Label();
|
}
|
||||||
// lblWithClass.className = "test";
|
|
||||||
// testStack.addChild(lblWithClass);
|
|
||||||
|
|
||||||
// testPage.css = "button.test:pressed { color: red; }";
|
|
||||||
|
|
||||||
// // Act & Assert
|
|
||||||
// var finished = false;
|
|
||||||
// testPage.onNavigatedTo = function (context) {
|
|
||||||
// testButtonPressedStateIsRed(btnWithClass);
|
|
||||||
|
|
||||||
// // The button with no class should not react to state changes.
|
|
||||||
// TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value.");
|
|
||||||
// btnWithNoClass._goToVisualState("pressed");
|
|
||||||
// TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value.");
|
|
||||||
// btnWithNoClass._goToVisualState("normal");
|
|
||||||
// TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value.");
|
|
||||||
|
|
||||||
// TKUnit.assert(lblWithClass.style.color === undefined, "Color should not have a value");
|
|
||||||
|
|
||||||
// finished = true;
|
|
||||||
// };
|
|
||||||
// frame.topmost().navigate(testPage);
|
|
||||||
|
|
||||||
// TKUnit.waitUntilReady(function () {
|
|
||||||
// return finished;
|
|
||||||
// }, 3);
|
|
||||||
//}
|
|
||||||
|
|
||||||
export var test_style_is_applied_when_control_is_added_after_load = function () {
|
export var test_style_is_applied_when_control_is_added_after_load = function () {
|
||||||
var page: pageModule.Page;
|
var page: pageModule.Page;
|
||||||
@ -843,6 +823,637 @@ export function test_set_mixed_CSS_cases_works() {
|
|||||||
}, casedCSS);
|
}, casedCSS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function test_basic_hierarchical_selectors() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "stacklayout button { background-color: #FF0000; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#FF0000");
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#FF0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_basic_hierarchical_direct_child_selectors() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "stacklayout > button { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#FF0000");
|
||||||
|
// only buttons that are direct children of StackLayout should have red background color
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#00FF00");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_basic_hierarchical_direct_child_more_levels_selectors() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "stacklayout > wraplayout > button { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#00FF00");
|
||||||
|
// only buttons that are direct children of StackLayout and WrapLayout should have red background color
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#FF0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_hierarchical_direct_child_more_levels_diff_selector_types() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
wrap.className = "wraplayoutClass";
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
testButton2.className = "buttonClass";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "stacklayout>.wraplayoutClass > .buttonClass { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#00FF00");
|
||||||
|
// only buttons that are direct children of StackLayout and WrapLayout should have red background color
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#FF0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_hierarchical_direct_child_more_levels_diff_selector_types2() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
stack.id = "stack";
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
wrap.className = "wraplayoutClass";
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
testButton2.className = "buttonClass";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "#stack>.wraplayoutClass>.buttonClass { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#00FF00");
|
||||||
|
// only buttons that are direct children of Layout with id stack and Layout with cssClass wraplayoutClass should have red background color
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#FF0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_hierarchical_direct_child_more_levels_diff_selector_types_invalid() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
stack.id = "stack";
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
wrap.className = "wraplayoutClass";
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
testButton2.className = "buttonClass";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "#stackErr > .wraplayoutClass > .buttonClass { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#00FF00");
|
||||||
|
// this is an invalid css so red style should not be applied
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#00FF00");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_hierarchical_direct_child_more_levels_diff_selector_types_invalid_middle() {
|
||||||
|
let stack = new stackModule.StackLayout();
|
||||||
|
stack.id = "stack";
|
||||||
|
let testButton1 = new buttonModule.Button();
|
||||||
|
testButton1.text = "Test 1";
|
||||||
|
testButton1.id = "testButton1";
|
||||||
|
|
||||||
|
let wrap = new wrapModule.WrapLayout();
|
||||||
|
wrap.className = "wraplayoutClass";
|
||||||
|
let testButton2 = new buttonModule.Button();
|
||||||
|
testButton2.text = "Test 2";
|
||||||
|
testButton2.id = "testButton2";
|
||||||
|
testButton2.className = "buttonClass";
|
||||||
|
|
||||||
|
wrap.addChild(testButton2);
|
||||||
|
stack.addChild(testButton1);
|
||||||
|
stack.addChild(wrap);
|
||||||
|
|
||||||
|
let testCss = "#stack > .wraplayoutClassErr > .buttonClass { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton1"), "#00FF00");
|
||||||
|
// this is an invalid css so red style should not be applied
|
||||||
|
helper.assertViewBackgroundColor(stack.getViewById("testButton2"), "#00FF00");
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.buildUIAndRunTest(stack, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_type_attr_selector() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "some value";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr] { background-color: #FF0000; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_class_attr_selector() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton.className = "button";
|
||||||
|
testButton["testAttr"] = "some value";
|
||||||
|
|
||||||
|
let testCss = ".button[testAttr] { background-color: #FF0000; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_id_attr_selector() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton.id = "myButton";
|
||||||
|
testButton["testAttr"] = "some value";
|
||||||
|
|
||||||
|
let testCss = "#myButton[testAttr] { background-color: #FF0000; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_type_attr_value_selector() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "somevalue";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr='somevalue'] { background-color: #FF0000; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_type_attr_invalid_value_selector() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "somevalue";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr='value'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_tilde_attr_selector_correct_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr~='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_tilde_attr_selector_correct_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "some flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr~='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_tilde_attr_selector_correct_syntax2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower new";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr~='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_tilde_attr_selector_incorrect_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "my-flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr~='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_tilde_attr_selector_incorrect_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowers";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr~='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_tilde_attr_selector_incorrect_syntax2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower-house";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr~='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_pipe_attr_selector_correct_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_pipe_attr_selector_correct_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower-house";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_pipe_attr_selector_incorrect_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowers";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_pipe_attr_selector_incorrect_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "myflower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_pipe_attr_selector_incorrect_syntax2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "my-flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_power_attr_selector_correct_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr^='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_power_attr_selector_correct_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower-house";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr^='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_power_attr_selector_correct_synta2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowers";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr^='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_power_attr_selector_incorrect_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "myflower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_power_attr_selector_incorrect_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "my-flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr|='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_dollar_attr_selector_correct_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr$='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_dollar_attr_selector_correct_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "myflower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr$='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_dollar_attr_selector_correct_syntax2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "my-flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr$='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_dollar_attr_selector_incorrect_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowers";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr$='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_dollar_attr_selector_incorrect_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowermy";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr$='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_dollar_attr_selector_incorrect_syntax2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower-my";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr$='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_correct_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_correct_syntax1() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "myflower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_correct_syntax2() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "my-flower";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_correct_syntax3() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowers";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_correct_syntax4() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flowermy";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_correct_syntax5() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flower-my";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } ";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#FF0000");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function test_star_attr_selector_incorrect_syntax() {
|
||||||
|
let testButton = new buttonModule.Button();
|
||||||
|
testButton["testAttr"] = "flow";
|
||||||
|
|
||||||
|
let testCss = "button[testAttr*='flower'] { background-color: #FF0000; } button { background-color: #00FF00; }";
|
||||||
|
|
||||||
|
let testFunc = function (views: Array<viewModule.View>) {
|
||||||
|
// style from correct type css should be applied
|
||||||
|
helper.assertViewBackgroundColor(testButton, "#00FF00");
|
||||||
|
}
|
||||||
|
helper.buildUIAndRunTest(testButton, testFunc, testCss);
|
||||||
|
}
|
||||||
// <snippet module="ui/styling" title="styling">
|
// <snippet module="ui/styling" title="styling">
|
||||||
// For information and example how to use style properties please refer to special [**Styling**](../../../styling.md) topic.
|
// For information and example how to use style properties please refer to special [**Styling**](../../../styling.md) topic.
|
||||||
// </snippet>
|
// </snippet>
|
||||||
|
@ -9,6 +9,7 @@ import viewModule = require("ui/core/view");
|
|||||||
import * as applicationModule from "application";
|
import * as applicationModule from "application";
|
||||||
import * as polymerExpressionsModule from "js-libs/polymer-expressions";
|
import * as polymerExpressionsModule from "js-libs/polymer-expressions";
|
||||||
import * as specialPropertiesModule from "ui/builder/special-properties";
|
import * as specialPropertiesModule from "ui/builder/special-properties";
|
||||||
|
import * as utils from "utils/utils";
|
||||||
|
|
||||||
//late import
|
//late import
|
||||||
var application: typeof applicationModule;
|
var application: typeof applicationModule;
|
||||||
@ -332,8 +333,7 @@ export class Binding {
|
|||||||
// text="{{ sourceProperty = $parents['ListView'].test, expression = $parents['ListView'].test + 2}}"
|
// text="{{ sourceProperty = $parents['ListView'].test, expression = $parents['ListView'].test + 2}}"
|
||||||
// update expression will be '$newPropertyValue + 2'
|
// update expression will be '$newPropertyValue + 2'
|
||||||
// then on expression execution the new value will be taken and target property will be updated with the value of the expression.
|
// then on expression execution the new value will be taken and target property will be updated with the value of the expression.
|
||||||
var escapeRegex = /[-\/\\^$*+?.()|[\]{}]/g;
|
var escapedSourceProperty = utils.escapeRegexSymbols(this.options.sourceProperty);
|
||||||
var escapedSourceProperty = this.options.sourceProperty.replace(escapeRegex, '\\$&');
|
|
||||||
var expRegex = new RegExp(escapedSourceProperty, 'g');
|
var expRegex = new RegExp(escapedSourceProperty, 'g');
|
||||||
var resultExp = this.options.expression.replace(expRegex, bc.newPropertyValueKey);
|
var resultExp = this.options.expression.replace(expRegex, bc.newPropertyValueKey);
|
||||||
return resultExp;
|
return resultExp;
|
||||||
|
1
ui/styling/css-selector.d.ts
vendored
1
ui/styling/css-selector.d.ts
vendored
@ -7,6 +7,7 @@
|
|||||||
constructor(expression: string, declarations: cssParser.Declaration[]);
|
constructor(expression: string, declarations: cssParser.Declaration[]);
|
||||||
|
|
||||||
expression: string;
|
expression: string;
|
||||||
|
attrExpression: string;
|
||||||
|
|
||||||
declarations(): Array<{ property: string; value: any }>;
|
declarations(): Array<{ property: string; value: any }>;
|
||||||
|
|
||||||
|
@ -3,23 +3,45 @@ import observable = require("ui/core/dependency-observable");
|
|||||||
import cssParser = require("css");
|
import cssParser = require("css");
|
||||||
import * as trace from "trace";
|
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 utils from "utils/utils";
|
||||||
|
|
||||||
var ID_SPECIFICITY = 10000;
|
var ID_SPECIFICITY = 1000000;
|
||||||
|
var ATTR_SPECIFITY = 10000;
|
||||||
var CLASS_SPECIFICITY = 100;
|
var CLASS_SPECIFICITY = 100;
|
||||||
var TYPE_SPECIFICITY = 1;
|
var TYPE_SPECIFICITY = 1;
|
||||||
|
|
||||||
export class CssSelector {
|
export class CssSelector {
|
||||||
private _expression: string;
|
private _expression: string;
|
||||||
private _declarations: cssParser.Declaration[];
|
private _declarations: cssParser.Declaration[];
|
||||||
|
private _attrExpression: string;
|
||||||
|
|
||||||
constructor(expression: string, declarations: cssParser.Declaration[]) {
|
constructor(expression: string, declarations: cssParser.Declaration[]) {
|
||||||
this._expression = expression;
|
if (expression) {
|
||||||
|
let leftSquareBracketIndex = expression.indexOf(LSBRACKET);
|
||||||
|
if (leftSquareBracketIndex > 0) {
|
||||||
|
// extracts what is inside square brackets ([target = 'test'] will extract "target = 'test'")
|
||||||
|
var paramsRegex = /\[\s*(.*)\s*\]/;
|
||||||
|
let attrParams = paramsRegex.exec(expression);
|
||||||
|
if (attrParams && attrParams.length > 1) {
|
||||||
|
this._attrExpression = attrParams[1].trim();
|
||||||
|
}
|
||||||
|
this._expression = expression.substr(0, leftSquareBracketIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._expression = expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
this._declarations = declarations;
|
this._declarations = declarations;
|
||||||
}
|
}
|
||||||
|
|
||||||
get expression(): string {
|
get expression(): string {
|
||||||
return this._expression;
|
return this._expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get attrExpression(): string {
|
||||||
|
return this._attrExpression;
|
||||||
|
}
|
||||||
|
|
||||||
get declarations(): Array<{ property: string; value: any }> {
|
get declarations(): Array<{ property: string; value: any }> {
|
||||||
return this._declarations;
|
return this._declarations;
|
||||||
@ -74,13 +96,33 @@ class CssTypeSelector extends CssSelector {
|
|||||||
return TYPE_SPECIFICITY;
|
return TYPE_SPECIFICITY;
|
||||||
}
|
}
|
||||||
public matches(view: view.View): boolean {
|
public matches(view: view.View): boolean {
|
||||||
return matchesType(this.expression, view);
|
let result = matchesType(this.expression, view);
|
||||||
|
if (result && this.attrExpression) {
|
||||||
|
return matchesAttr(this.attrExpression, view);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function matchesType(expression: string, view: view.View): boolean {
|
function matchesType(expression: string, view: view.View): boolean {
|
||||||
return expression.toLowerCase() === view.typeName.toLowerCase() ||
|
let exprArr = expression.split(".");
|
||||||
expression.toLowerCase() === view.typeName.split(/(?=[A-Z])/).join("-").toLowerCase();
|
let exprTypeName = exprArr[0];
|
||||||
|
let exprClassName = exprArr[1];
|
||||||
|
|
||||||
|
let typeCheck = exprTypeName.toLowerCase() === view.typeName.toLowerCase() ||
|
||||||
|
exprTypeName.toLowerCase() === view.typeName.split(/(?=[A-Z])/).join("-").toLowerCase();
|
||||||
|
|
||||||
|
if (typeCheck) {
|
||||||
|
if (exprClassName) {
|
||||||
|
return view._cssClasses.some((cssClass, i, arr) => { return cssClass === exprClassName });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return typeCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CssIdSelector extends CssSelector {
|
class CssIdSelector extends CssSelector {
|
||||||
@ -88,7 +130,11 @@ class CssIdSelector extends CssSelector {
|
|||||||
return ID_SPECIFICITY;
|
return ID_SPECIFICITY;
|
||||||
}
|
}
|
||||||
public matches(view: view.View): boolean {
|
public matches(view: view.View): boolean {
|
||||||
return this.expression === view.id;
|
let result = this.expression === view.id;
|
||||||
|
if (result && this.attrExpression) {
|
||||||
|
return matchesAttr(this.attrExpression, view);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,10 +144,151 @@ class CssClassSelector extends CssSelector {
|
|||||||
}
|
}
|
||||||
public matches(view: view.View): boolean {
|
public matches(view: view.View): boolean {
|
||||||
var expectedClass = this.expression;
|
var expectedClass = this.expression;
|
||||||
return view._cssClasses.some((cssClass, i, arr) => { return cssClass === expectedClass });
|
let result = view._cssClasses.some((cssClass, i, arr) => { return cssClass === expectedClass });
|
||||||
|
if (result && this.attrExpression) {
|
||||||
|
return matchesAttr(this.attrExpression, view);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CssCompositeSelector extends CssSelector {
|
||||||
|
get specificity(): number {
|
||||||
|
let result = 0;
|
||||||
|
for(let i = 0; i < this.parentCssSelectors.length; i++) {
|
||||||
|
result += this.parentCssSelectors[i].selector.specificity;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parentCssSelectors: [{ selector: CssSelector, onlyDirectParent: boolean}];
|
||||||
|
|
||||||
|
private splitExpression(expression) {
|
||||||
|
let result = [];
|
||||||
|
let tempArr = [];
|
||||||
|
let validSpace = true;
|
||||||
|
for (let i = 0; i < expression.length; i++) {
|
||||||
|
if (expression[i] === LSBRACKET) {
|
||||||
|
validSpace = false;
|
||||||
|
}
|
||||||
|
if (expression[i] === RSBRACKET) {
|
||||||
|
validSpace = true;
|
||||||
|
}
|
||||||
|
if ((expression[i] === SPACE && validSpace) || (expression[i] === GTHAN)) {
|
||||||
|
if (tempArr.length > 0) {
|
||||||
|
result.push(tempArr.join(""));
|
||||||
|
tempArr = [];
|
||||||
|
}
|
||||||
|
if (expression[i] === GTHAN) {
|
||||||
|
result.push(GTHAN);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tempArr.push(expression[i]);
|
||||||
|
}
|
||||||
|
if (tempArr.length > 0) {
|
||||||
|
result.push(tempArr.join(""));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(expr: string, declarations: cssParser.Declaration[]) {
|
||||||
|
super(expr, declarations);
|
||||||
|
let expressions = this.splitExpression(expr);
|
||||||
|
let onlyParent = false;
|
||||||
|
this.parentCssSelectors = <any>[];
|
||||||
|
for(let i = expressions.length - 1; i >= 0; i--) {
|
||||||
|
if (expressions[i].trim() === GTHAN) {
|
||||||
|
onlyParent = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.parentCssSelectors.push({selector: createSelector(expressions[i].trim(), null), onlyDirectParent: onlyParent});
|
||||||
|
onlyParent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public matches(view: view.View): boolean {
|
||||||
|
let result = this.parentCssSelectors[0].selector.matches(view);
|
||||||
|
if (!result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
let tempView = view.parent;
|
||||||
|
for(let i = 1; i < this.parentCssSelectors.length; i++) {
|
||||||
|
let parentCounter = 0;
|
||||||
|
while (tempView && parentCounter === 0) {
|
||||||
|
result = this.parentCssSelectors[i].selector.matches(tempView);
|
||||||
|
if (result) {
|
||||||
|
tempView = tempView.parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this.parentCssSelectors[i].onlyDirectParent) {
|
||||||
|
parentCounter++;
|
||||||
|
}
|
||||||
|
tempView = tempView.parent;
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
break;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CssAttrSelector extends CssSelector {
|
||||||
|
get specificity(): number {
|
||||||
|
return ATTR_SPECIFITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public matches(view: view.View): boolean {
|
||||||
|
return matchesAttr(this.attrExpression, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesAttr(attrExpression: string, view: view.View): boolean {
|
||||||
|
let equalSignIndex = attrExpression.indexOf(EQUAL);
|
||||||
|
if (equalSignIndex > 0) {
|
||||||
|
let nameValueRegex = /(.*[^~|\^\$\*])[~|\^\$\*]?=(.*)/;
|
||||||
|
let nameValueRegexRes = nameValueRegex.exec(attrExpression);
|
||||||
|
let attrName;
|
||||||
|
let attrValue;
|
||||||
|
if (nameValueRegexRes && nameValueRegexRes.length > 2) {
|
||||||
|
attrName = nameValueRegexRes[1].trim();
|
||||||
|
attrValue = nameValueRegexRes[2].trim().replace(/^(["'])*(.*)\1$/, '$2');
|
||||||
|
}
|
||||||
|
// extract entire sign (=, ~=, |=, ^=, $=, *=)
|
||||||
|
let escapedAttrValue = utils.escapeRegexSymbols(attrValue);
|
||||||
|
let attrCheckRegex;
|
||||||
|
switch (attrExpression.charAt(equalSignIndex - 1)) {
|
||||||
|
case "~":
|
||||||
|
attrCheckRegex = new RegExp("(^|[^a-zA-Z-])" + escapedAttrValue + "([^a-zA-Z-]|$)");
|
||||||
|
break;
|
||||||
|
case "|":
|
||||||
|
attrCheckRegex = new RegExp("^" + escapedAttrValue + "\\b");
|
||||||
|
break;
|
||||||
|
case "^":
|
||||||
|
attrCheckRegex = new RegExp("^" + escapedAttrValue);
|
||||||
|
break;
|
||||||
|
case "$":
|
||||||
|
attrCheckRegex = new RegExp(escapedAttrValue + "$");
|
||||||
|
break;
|
||||||
|
case "*":
|
||||||
|
attrCheckRegex = new RegExp(escapedAttrValue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// only = (EQUAL)
|
||||||
|
default:
|
||||||
|
attrCheckRegex = new RegExp("^"+escapedAttrValue+"$");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return !types.isNullOrUndefined(view[attrName]) && attrCheckRegex.test(view[attrName]+"");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return !types.isNullOrUndefined(view[attrExpression]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export class CssVisualStateSelector extends CssSelector {
|
export class CssVisualStateSelector extends CssSelector {
|
||||||
private _key: string;
|
private _key: string;
|
||||||
private _match: string;
|
private _match: string;
|
||||||
@ -109,9 +296,11 @@ export class CssVisualStateSelector extends CssSelector {
|
|||||||
private _isById: boolean;
|
private _isById: boolean;
|
||||||
private _isByClass: boolean;
|
private _isByClass: boolean;
|
||||||
private _isByType: boolean;
|
private _isByType: boolean;
|
||||||
|
private _isByAttr: boolean;
|
||||||
|
|
||||||
get specificity(): number {
|
get specificity(): number {
|
||||||
return (this._isById ? ID_SPECIFICITY : 0) +
|
return (this._isById ? ID_SPECIFICITY : 0) +
|
||||||
|
(this._isByAttr ? ATTR_SPECIFITY : 0) +
|
||||||
(this._isByClass ? CLASS_SPECIFICITY : 0) +
|
(this._isByClass ? CLASS_SPECIFICITY : 0) +
|
||||||
(this._isByType ? TYPE_SPECIFICITY : 0);
|
(this._isByType ? TYPE_SPECIFICITY : 0);
|
||||||
}
|
}
|
||||||
@ -131,12 +320,15 @@ export class CssVisualStateSelector extends CssSelector {
|
|||||||
this._key = args[0];
|
this._key = args[0];
|
||||||
this._state = args[1];
|
this._state = args[1];
|
||||||
|
|
||||||
if (this._key.charAt(0) === AMP) {
|
if (this._key.charAt(0) === HASH) {
|
||||||
this._match = this._key.substring(1);
|
this._match = this._key.substring(1);
|
||||||
this._isById = true;
|
this._isById = true;
|
||||||
} else if (this._key.charAt(0) === DOT) {
|
} else if (this._key.charAt(0) === DOT) {
|
||||||
this._match = this._key.substring(1);
|
this._match = this._key.substring(1);
|
||||||
this._isByClass = true;
|
this._isByClass = true;
|
||||||
|
} else if (this._key.charAt(0) === LSBRACKET) {
|
||||||
|
this._match = this._key;
|
||||||
|
this._isByAttr = true;
|
||||||
}
|
}
|
||||||
else if (this._key.length > 0) { // handle the case when there is no key. E.x. ":pressed" selector
|
else if (this._key.length > 0) { // handle the case when there is no key. E.x. ":pressed" selector
|
||||||
this._match = this._key;
|
this._match = this._key;
|
||||||
@ -158,31 +350,51 @@ export class CssVisualStateSelector extends CssSelector {
|
|||||||
if (this._isByType) {
|
if (this._isByType) {
|
||||||
matches = matchesType(this._match, view);
|
matches = matchesType(this._match, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._isByAttr) {
|
||||||
|
matches = matchesAttr(this._key, view);
|
||||||
|
}
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var AMP = "#",
|
var HASH = "#";
|
||||||
DOT = ".",
|
var DOT = ".";
|
||||||
COLON = ":";
|
var COLON = ":";
|
||||||
|
var SPACE = " ";
|
||||||
|
var GTHAN = ">";
|
||||||
|
var LSBRACKET = "[";
|
||||||
|
var RSBRACKET = "]";
|
||||||
|
var EQUAL = "=";
|
||||||
|
|
||||||
export function createSelector(expression: string, declarations: cssParser.Declaration[]): CssSelector {
|
export function createSelector(expression: string, declarations: cssParser.Declaration[]): CssSelector {
|
||||||
var colonIndex = expression.indexOf(COLON);
|
let goodExpr = expression.replace(/>/g, " > ").replace(/\s\s+/g, " ");
|
||||||
|
var spaceIndex = goodExpr.indexOf(SPACE);
|
||||||
|
if (spaceIndex >= 0) {
|
||||||
|
return new CssCompositeSelector(goodExpr, declarations);
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftSquareBracketIndex = goodExpr.indexOf(LSBRACKET);
|
||||||
|
if (leftSquareBracketIndex === 0) {
|
||||||
|
return new CssAttrSelector(goodExpr, declarations);
|
||||||
|
}
|
||||||
|
|
||||||
|
var colonIndex = goodExpr.indexOf(COLON);
|
||||||
if (colonIndex >= 0) {
|
if (colonIndex >= 0) {
|
||||||
return new CssVisualStateSelector(expression, declarations);
|
return new CssVisualStateSelector(goodExpr, declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression.charAt(0) === AMP) {
|
if (goodExpr.charAt(0) === HASH) {
|
||||||
return new CssIdSelector(expression.substring(1), declarations);
|
return new CssIdSelector(goodExpr.substring(1), declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression.charAt(0) === DOT) {
|
if (goodExpr.charAt(0) === DOT) {
|
||||||
// TODO: Combinations like label.center
|
// TODO: Combinations like label.center
|
||||||
return new CssClassSelector(expression.substring(1), declarations);
|
return new CssClassSelector(goodExpr.substring(1), declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CssTypeSelector(expression, declarations);
|
return new CssTypeSelector(goodExpr, declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
class InlineStyleSelector extends CssSelector {
|
class InlineStyleSelector extends CssSelector {
|
||||||
|
@ -29,6 +29,11 @@ export function parseJSON(source: string): any {
|
|||||||
return JSON.parse(src);
|
return JSON.parse(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function escapeRegexSymbols(source: string): string {
|
||||||
|
let escapeRegex = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;
|
||||||
|
return source.replace(escapeRegex, "\\$&");
|
||||||
|
}
|
||||||
|
|
||||||
export module layout {
|
export module layout {
|
||||||
|
|
||||||
var MODE_SHIFT = 30;
|
var MODE_SHIFT = 30;
|
||||||
|
6
utils/utils.d.ts
vendored
6
utils/utils.d.ts
vendored
@ -229,4 +229,10 @@
|
|||||||
* @param url The url.
|
* @param url The url.
|
||||||
*/
|
*/
|
||||||
export function openUrl(url: string): boolean
|
export function openUrl(url: string): boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes special regex symbols (., *, ^, $ and so on) in string in order to create a valid regex from it.
|
||||||
|
* @param source The original value.
|
||||||
|
*/
|
||||||
|
export function escapeRegexSymbols(source: string): string
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user