Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 44b8acd

Browse filesBrowse files
authored
feat(HMR): apply changes in page styles at runtime when app root is a frame (#6857)
* feat(HMR): apply changes in page styles at runtime * fix: livesync tests * test: changeCssFile method * refactor: address comments Add a comment. Update `let` to `const`. Update `changesCssFile` test. * test: add an assert
1 parent 8e9a13c commit 44b8acd
Copy full SHA for 44b8acd

File tree

10 files changed

+120
-59
lines changed
Filter options

10 files changed

+120
-59
lines changed

‎tests/app/ui/styling/style-tests.ts

Copy file name to clipboardExpand all lines: tests/app/ui/styling/style-tests.ts
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,23 @@ export function test_CSS_isAppliedOnPage_From_addCssFile() {
674674
});
675675
}
676676

677+
export function test_CSS_isAppliedOnPage_From_changeCssFile() {
678+
const testButton = new buttonModule.Button();
679+
testButton.text = "Test";
680+
681+
const testCss = "button { color: blue; }";
682+
683+
const testFunc = function (views: Array<viewModule.View>) {
684+
helper.assertViewColor(testButton, "#0000FF");
685+
const page: pageModule.Page = <pageModule.Page>views[1];
686+
page.changeCssFile("~/ui/styling/test.css");
687+
helper.assertViewBackgroundColor(page, "#FF0000");
688+
TKUnit.assert(testButton.style.color === undefined, "Color should not have a value");
689+
}
690+
691+
helper.buildUIAndRunTest(testButton, testFunc, { pageCss: testCss });
692+
}
693+
677694
const invalidCSS = ".invalid { " +
678695
"color: invalidValue; " +
679696
"background-color: invalidValue; " +

‎tns-core-modules/application/application-common.ts

Copy file name to clipboardExpand all lines: tns-core-modules/application/application-common.ts
+11-7Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,23 @@ export function setApplication(instance: iOSApplication | AndroidApplication): v
8282
export function livesync(rootView: View, context?: ModuleContext) {
8383
events.notify(<EventData>{ eventName: "livesync", object: app });
8484
const liveSyncCore = global.__onLiveSyncCore;
85-
let reapplyAppCss = false;
85+
let reapplyAppStyles = false;
86+
let reapplyLocalStyles = false;
8687

87-
if (context) {
88-
const fullFileName = getCssFileName();
89-
const fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".") + 1);
88+
if (context && context.path) {
9089
const extensions = ["css", "scss"];
91-
reapplyAppCss = extensions.some(ext => context.path === fileName.concat(ext));
90+
const appStylesFullFileName = getCssFileName();
91+
const appStylesFileName = appStylesFullFileName.substring(0, appStylesFullFileName.lastIndexOf(".") + 1);
92+
reapplyAppStyles = extensions.some(ext => context.path === appStylesFileName.concat(ext));
93+
if (!reapplyAppStyles) {
94+
reapplyLocalStyles = extensions.some(ext => context.path.endsWith(ext));
95+
}
9296
}
9397

94-
if (reapplyAppCss && rootView) {
98+
if (reapplyAppStyles && rootView) {
9599
rootView._onCssStateChange();
96100
} else if (liveSyncCore) {
97-
liveSyncCore();
101+
reapplyLocalStyles ? liveSyncCore(context) : liveSyncCore();
98102
}
99103
}
100104

‎tns-core-modules/application/application.ios.ts

Copy file name to clipboardExpand all lines: tns-core-modules/application/application.ios.ts
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,9 @@ class IOSApplication implements IOSApplicationDefinition {
225225
}
226226
}
227227

228-
public _onLivesync(): void {
228+
public _onLivesync(context?: ModuleContext): void {
229229
// If view can't handle livesync set window controller.
230-
if (this._rootView && !this._rootView._onLivesync()) {
230+
if (this._rootView && !this._rootView._onLivesync(context)) {
231231
this.setWindowContent();
232232
}
233233
}
@@ -264,8 +264,8 @@ exports.ios = iosApp;
264264
setApplication(iosApp);
265265

266266
// attach on global, so it can be overwritten in NativeScript Angular
267-
(<any>global).__onLiveSyncCore = function () {
268-
iosApp._onLivesync();
267+
(<any>global).__onLiveSyncCore = function (context?: ModuleContext) {
268+
iosApp._onLivesync(context);
269269
}
270270

271271
let mainEntry: NavigationEntry;

‎tns-core-modules/module.d.ts

Copy file name to clipboardExpand all lines: tns-core-modules/module.d.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ declare namespace NodeJS {
5252
__inspector?: any;
5353
__extends: any;
5454
__onLiveSync: (context?: { type: string, path: string }) => void;
55-
__onLiveSyncCore: () => void;
55+
__onLiveSyncCore: (context?: { type: string, path: string }) => void;
5656
__onUncaughtError: (error: NativeScriptError) => void;
5757
__onDiscardedError: (error: NativeScriptError) => void;
5858
TNS_WEBPACK?: boolean;

‎tns-core-modules/ui/core/view/view-common.ts

Copy file name to clipboardExpand all lines: tns-core-modules/ui/core/view/view-common.ts
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
105105
this._updateStyleScope(cssFileName);
106106
}
107107

108+
public changeCssFile(cssFileName: string): void {
109+
const scope = this._styleScope;
110+
if (scope && cssFileName) {
111+
scope.changeCssFile(cssFileName);
112+
this._onCssStateChange();
113+
}
114+
}
115+
108116
public _updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void {
109117
let scope = this._styleScope;
110118
if (!scope) {

‎tns-core-modules/ui/core/view/view.d.ts

Copy file name to clipboardExpand all lines: tns-core-modules/ui/core/view/view.d.ts
+29-22Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ export function PseudoClassHandler(...pseudoClasses: string[]): MethodDecorator;
1818
/**
1919
* Specifies the type name for the instances of this View class,
2020
* that is used when matching CSS type selectors.
21-
*
21+
*
2222
* Usage:
2323
* ```
2424
* @CSSType("Button")
2525
* class Button extends View {
2626
* }
2727
* ```
28-
*
28+
*
2929
* Internally the decorator set `Button.prototype.cssType = "Button"`.
3030
* @param type The type name, e. g. "Button", "Label", etc.
3131
*/
@@ -50,8 +50,8 @@ export type px = number;
5050
export type percent = number;
5151

5252
/**
53-
* The Point interface describes a two dimensional location.
54-
* It has two properties x and y, representing the x and y coordinate of the location.
53+
* The Point interface describes a two dimensional location.
54+
* It has two properties x and y, representing the x and y coordinate of the location.
5555
*/
5656
export interface Point {
5757
/**
@@ -66,8 +66,8 @@ export interface Point {
6666
}
6767

6868
/**
69-
* The Size interface describes abstract dimensions in two dimensional space.
70-
* It has two properties width and height, representing the width and height values of the size.
69+
* The Size interface describes abstract dimensions in two dimensional space.
70+
* It has two properties width and height, representing the width and height values of the size.
7171
*/
7272
export interface Size {
7373
/**
@@ -99,8 +99,8 @@ export interface ShownModallyData extends EventData {
9999
}
100100

101101
/**
102-
* This class is the base class for all UI components.
103-
* A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within.
102+
* This class is the base class for all UI components.
103+
* A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within.
104104
*/
105105
export abstract class View extends ViewBase {
106106
/**
@@ -475,13 +475,13 @@ export abstract class View extends ViewBase {
475475
* [Deprecated. Please use the on() instead.] Adds a gesture observer.
476476
* @param type - Type of the gesture.
477477
* @param callback - A function that will be executed when gesture is received.
478-
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
478+
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
479479
*/
480480
observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any);
481481

482482
/**
483483
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
484-
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change") or you can use gesture types.
484+
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change") or you can use gesture types.
485485
* @param callback - Callback function which will be executed when event is raised.
486486
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
487487
*/
@@ -527,12 +527,12 @@ export abstract class View extends ViewBase {
527527
modal: View;
528528

529529
/**
530-
* Animates one or more properties of the view based on the supplied options.
530+
* Animates one or more properties of the view based on the supplied options.
531531
*/
532532
public animate(options: AnimationDefinition): AnimationPromise;
533533

534534
/**
535-
* Creates an Animation object based on the supplied options.
535+
* Creates an Animation object based on the supplied options.
536536
*/
537537
public createAnimation(options: AnimationDefinition): Animation;
538538

@@ -562,7 +562,7 @@ export abstract class View extends ViewBase {
562562
public getActualSize(): Size;
563563

564564
/**
565-
* Derived classes can override this method to handle Android back button press.
565+
* Derived classes can override this method to handle Android back button press.
566566
*/
567567
onBackPressed(): boolean;
568568

@@ -575,7 +575,7 @@ export abstract class View extends ViewBase {
575575
/**
576576
* @private
577577
* Adds a new values to current css.
578-
* @param cssString - A valid css which will be added to current css.
578+
* @param cssString - A valid css which will be added to current css.
579579
*/
580580
addCss(cssString: string): void;
581581

@@ -586,13 +586,20 @@ export abstract class View extends ViewBase {
586586
*/
587587
addCssFile(cssFileName: string): void;
588588

589+
/**
590+
* @private
591+
* Changes the current css to the content of the file.
592+
* @param cssFileName - A valid file name (from the application root) which contains a valid css.
593+
*/
594+
changeCssFile(cssFileName: string): void;
595+
589596
// Lifecycle events
590597
_getNativeViewsCount(): number;
591598

592599
_eachLayoutView(callback: (View) => void): void;
593-
600+
594601
/**
595-
* Iterates over children of type View.
602+
* Iterates over children of type View.
596603
* @param callback Called for each child of type View. Iteration stops if this method returns falsy value.
597604
*/
598605
public eachChildView(callback: (view: View) => boolean): void;
@@ -673,17 +680,17 @@ export abstract class View extends ViewBase {
673680
/**
674681
* @private
675682
*/
676-
_onLivesync(): boolean;
683+
_onLivesync(context?: { type: string, path: string }): boolean;
677684
/**
678685
* @private
679686
*/
680687
_getFragmentManager(): any; /* android.support.v4.app.FragmentManager */
681688

682689
/**
683690
* Updates styleScope or create new styleScope.
684-
* @param cssFileName
685-
* @param cssString
686-
* @param css
691+
* @param cssFileName
692+
* @param cssString
693+
* @param css
687694
*/
688695
_updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void;
689696

@@ -715,7 +722,7 @@ export abstract class View extends ViewBase {
715722
}
716723

717724
/**
718-
* Base class for all UI components that are containers.
725+
* Base class for all UI components that are containers.
719726
*/
720727
export class ContainerView extends View {
721728
/**
@@ -725,7 +732,7 @@ export class ContainerView extends View {
725732
}
726733

727734
/**
728-
* Base class for all UI components that implement custom layouts.
735+
* Base class for all UI components that implement custom layouts.
729736
*/
730737
export class CustomLayoutView extends ContainerView {
731738
//@private

‎tns-core-modules/ui/frame/frame-common.ts

Copy file name to clipboardExpand all lines: tns-core-modules/ui/frame/frame-common.ts
+17-6Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
7676
if (backstackIndex !== -1) {
7777
backstack = backstackIndex;
7878
} else {
79-
// NOTE: We don't search for entries in navigationQueue because there is no way for
79+
// NOTE: We don't search for entries in navigationQueue because there is no way for
8080
// developer to get reference to BackstackEntry unless transition is completed.
8181
// At that point the entry is put in the backstack array.
8282
// If we start to return Backstack entry from navigate method then
@@ -153,7 +153,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
153153
// }
154154

155155
// let currentPage = this._currentEntry.resolvedPage;
156-
// let currentNavigationEntry = this._currentEntry.entry;
156+
// let currentNavigationEntry = this._currentEntry.entry;
157157
// if (currentPage["isBiOrientational"] && currentNavigationEntry.moduleName) {
158158
// if (this.canGoBack()){
159159
// this.goBack();
@@ -162,7 +162,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
162162
// currentNavigationEntry.backstackVisible = false;
163163
// }
164164
// // Re-navigate to the same page so the other (.port or .land) xml is loaded.
165-
// this.navigate(currentNavigationEntry);
165+
// this.navigate(currentNavigationEntry);
166166
// }
167167
// }
168168

@@ -224,7 +224,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
224224
newPage.onNavigatedTo(isBack);
225225

226226
// Reset executing entry after NavigatedTo is raised;
227-
// we do not want to execute two navigations in parallel in case
227+
// we do not want to execute two navigations in parallel in case
228228
// additional navigation is triggered from the NavigatedTo handler.
229229
this._executingEntry = null;
230230
}
@@ -259,7 +259,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
259259
return true;
260260
}
261261
}
262-
262+
263263
return false;
264264
}
265265

@@ -563,14 +563,25 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
563563
return result;
564564
}
565565

566-
public _onLivesync(): boolean {
566+
public _onLivesync(context?: ModuleContext): boolean {
567567
super._onLivesync();
568568

569569
if (!this._currentEntry || !this._currentEntry.entry) {
570570
return false;
571571
}
572572

573573
const currentEntry = this._currentEntry.entry;
574+
if (context && context.path) {
575+
// Use topmost instead of this to cover nested frames scenario
576+
const topmostFrame = topmost();
577+
const moduleName = topmostFrame.currentEntry.moduleName;
578+
const reapplyStyles = context.path.includes(moduleName);
579+
if (reapplyStyles && moduleName) {
580+
topmostFrame.currentPage.changeCssFile(context.path);
581+
return true;
582+
}
583+
}
584+
574585
const newEntry: NavigationEntry = {
575586
animated: false,
576587
clearHistory: true,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.