From 85b8c018a5eb344cd1e60c883a1df9060e1e4233 Mon Sep 17 00:00:00 2001 From: Nathanael Anderson Date: Thu, 2 Aug 2018 03:51:07 -0500 Subject: [PATCH] feat(styling): Added 2 functions to control applicationAdditionalSelectors (#6124) * Added getAdditionalSelectors function so that nativescript-theme can be functional again in NS 4.x * Change to a better more extensible additional css system. * removed redunant function on the name. * Fix lint issues * Adding mergeSelectors to the remove function * Added test of new add/remove css functions. * fix: revert testRunner.ts changes that disabled all tests except style * refactor: fix typo * chore: fix typo and change test to no not affect global styles --- tests/app/ui/styling/style-tests.ts | 32 ++++++++++++++++++- .../ui/styling/css-selector/css-selector.d.ts | 7 +++- tns-core-modules/ui/styling/style-scope.ts | 31 +++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/tests/app/ui/styling/style-tests.ts b/tests/app/ui/styling/style-tests.ts index 4b095ff22..9185bdfb7 100644 --- a/tests/app/ui/styling/style-tests.ts +++ b/tests/app/ui/styling/style-tests.ts @@ -9,7 +9,7 @@ import * as tabViewModule from "tns-core-modules/ui/tab-view"; import * as helper from "../../ui/helper"; import * as types from "tns-core-modules/utils/types"; import * as viewModule from "tns-core-modules/ui/core/view"; -import { resolveFileNameFromUrl } from "tns-core-modules/ui/styling/style-scope"; +import { resolveFileNameFromUrl, removeTaggedAdditionalCSS, addTaggedAdditionalCSS } from "tns-core-modules/ui/styling/style-scope"; import { unsetValue } from "tns-core-modules/ui/core/view"; import * as color from "tns-core-modules/color"; @@ -1479,6 +1479,36 @@ export function test_resolveFileNameFromUrl_unexisting_file() { TKUnit.assertNull(result, "Shouldn't resolve unexisting file"); } +export function test_checkAddRemoveCSS() { + const css1 = "#test_checkAddRemoveCSS_label { color: #FF0000; }"; + const css2 = "#test_checkAddRemoveCSS_label { color: #00FF00; }"; + const label = new labelModule.Label(); + label.text = "color coming from updated rules"; + label.id = "test_checkAddRemoveCSS_label"; + + helper.buildUIAndRunTest(label, function (views: Array) { + const page = views[1]; + + // Add Red, we have to then trigger the page's CSS state change, for it to refresh the label's css with the new global rule + addTaggedAdditionalCSS(css1, "red"); + page._onCssStateChange(); + helper.assertViewColor(label, "#FF0000"); + + // Add Green (should override red) + addTaggedAdditionalCSS(css2, "green"); + page._onCssStateChange(); + helper.assertViewColor(label, "#00FF00"); + + // Remove Green (Should revert to red, since we removed the green rule) + removeTaggedAdditionalCSS("green"); + page._onCssStateChange(); + helper.assertViewColor(label, "#FF0000"); + + //Cleanup + removeTaggedAdditionalCSS("red"); + }); +} + // // For information and example how to use style properties please refer to special [**Styling**](../../../styling.md) topic. // diff --git a/tns-core-modules/ui/styling/css-selector/css-selector.d.ts b/tns-core-modules/ui/styling/css-selector/css-selector.d.ts index 080e1c930..594bf8d56 100644 --- a/tns-core-modules/ui/styling/css-selector/css-selector.d.ts +++ b/tns-core-modules/ui/styling/css-selector/css-selector.d.ts @@ -43,6 +43,11 @@ export class RuleSet { * Gets the key-value list of declarations for the ruleset. */ declarations: Declaration[]; + + /** + * Optional Tag for rules + **/ + tag: string | Number; } export class SelectorsMap { @@ -68,7 +73,7 @@ export class SelectorsMatch { selectors: SelectorCore[]; /** - * Gets a map of nodes to attributes and pseudo classes, that may affect the state of the dynamic + * Gets a map of nodes to attributes and pseudo classes, that may affect the state of the dynamic */ changeMap: ChangeMap; } diff --git a/tns-core-modules/ui/styling/style-scope.ts b/tns-core-modules/ui/styling/style-scope.ts index 17a7b0ff7..c1028201e 100644 --- a/tns-core-modules/ui/styling/style-scope.ts +++ b/tns-core-modules/ui/styling/style-scope.ts @@ -262,6 +262,35 @@ class CSSSource { } } +export function removeTaggedAdditionalCSS(tag: String | Number): Boolean { + let changed = false; + for (let i = 0; i < applicationAdditionalSelectors.length; i++) { + if (applicationAdditionalSelectors[i].tag === tag) { + applicationAdditionalSelectors.splice(i, 1); + i--; + changed = true; + } + } + if (changed) { mergeCssSelectors(); } + return changed; +} + +export function addTaggedAdditionalCSS(cssText: string, tag?: string | Number): Boolean { + const parsed: RuleSet[] = CSSSource.fromSource(cssText, applicationKeyframes, undefined).selectors; + let changed = false; + if (parsed && parsed.length) { + changed = true; + if (tag != null) { + for (let i = 0; i < parsed.length; i++) { + parsed[i].tag = tag; + } + } + applicationAdditionalSelectors.push.apply(applicationAdditionalSelectors, parsed); + mergeCssSelectors(); + } + return changed; +} + const onCssChanged = profile("\"style-scope\".onCssChanged", (args: applicationCommon.CssChangedEventData) => { if (args.cssText) { const parsed = CSSSource.fromSource(args.cssText, applicationKeyframes, args.cssFile).selectors; @@ -414,7 +443,7 @@ export class CssState { * Calculate the difference between the previously applied property values, * and the new set of property values that have to be applied for the provided selectors. * Apply the values and ensure each property setter is called at most once to avoid excessive change notifications. - * @param matchingSelectors + * @param matchingSelectors */ private setPropertyValues(matchingSelectors: SelectorCore[]): void { const newPropertyValues = new this.view.style.PropertyBag();