| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + Button | ||
| 2 | + /* | ||
| 3 | + TODO: uncomment and investigate a livesync test failure | ||
| 4 | + , Label */ | ||
| 5 | + { | ||
| 6 | + color: green; | ||
| 7 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,6 +15,7 @@ const mainPageCssFileName = "./app/main-page.css"; | |||
| 15 | 15 | const mainPageHtmlFileName = "./app/main-page.html"; | |
| 16 | 16 | const mainPageXmlFileName = "./app/main-page.xml"; | |
| 17 | 17 | ||
| 18 | + const black = new Color("black"); | ||
| 18 | 19 | const green = new Color("green"); | |
| 19 | 20 | ||
| 20 | 21 | const mainPageTemplate = ` | |
@@ -56,7 +57,7 @@ export function test_onLiveSync_ModuleContext_Script_AppTs() { | |||
| 56 | 57 | } | |
| 57 | 58 | ||
| 58 | 59 | export function test_onLiveSync_ModuleContext_Style_MainPageCss() { | |
| 59 | - _test_onLiveSync_ModuleContext({ type: "style", path: mainPageCssFileName }); | ||
| 60 | + _test_onLiveSync_ModuleContext_TypeStyle({ type: "style", path: mainPageCssFileName }); | ||
| 60 | 61 | } | |
| 61 | 62 | ||
| 62 | 63 | export function test_onLiveSync_ModuleContext_Markup_MainPageHtml() { | |
@@ -110,4 +111,29 @@ function _test_onLiveSync_ModuleContext(context: { type, path }) { | |||
| 110 | 111 | const topmostFrame = frame.topmost(); | |
| 111 | 112 | TKUnit.waitUntilReady(() => topmostFrame.currentPage && topmostFrame.currentPage.isLoaded && !topmostFrame.canGoBack()); | |
| 112 | 113 | TKUnit.assertTrue(topmostFrame.currentPage.getViewById("label").isLoaded); | |
| 114 | + } | ||
| 115 | + | ||
| 116 | + function _test_onLiveSync_ModuleContext_TypeStyle(context: { type, path }) { | ||
| 117 | + const pageBeforeNavigation = helper.getCurrentPage(); | ||
| 118 | + | ||
| 119 | + const page = <Page>parse(pageTemplate); | ||
| 120 | + helper.navigateWithHistory(() => page); | ||
| 121 | + | ||
| 122 | + const pageBeforeLiveSync = helper.getCurrentPage(); | ||
| 123 | + pageBeforeLiveSync._rootOfModule = "main-page"; | ||
| 124 | + global.__onLiveSync({ type: context.type, path: context.path }); | ||
| 125 | + | ||
| 126 | + const pageAfterLiveSync = helper.getCurrentPage(); | ||
| 127 | + TKUnit.waitUntilReady(() => pageAfterLiveSync.getViewById("button").style.color.toString() === green.toString()); | ||
| 128 | + | ||
| 129 | + TKUnit.assertTrue(pageAfterLiveSync.frame.canGoBack(), "Local styles NOT applied - livesync navigation executed!"); | ||
| 130 | + TKUnit.assertEqual(pageAfterLiveSync, pageBeforeLiveSync, "Pages are different - livesync navigation executed!"); | ||
| 131 | + TKUnit.assertTrue(pageAfterLiveSync._cssState.isSelectorsLatestVersionApplied(), "Latest selectors version NOT applied!"); | ||
| 132 | + | ||
| 133 | + helper.goBack(); | ||
| 134 | + | ||
| 135 | + const pageAfterNavigationBack = helper.getCurrentPage(); | ||
| 136 | + TKUnit.assertEqual(pageAfterNavigationBack.getViewById("label").style.color, black, "App styles applied on back navigation!"); | ||
| 137 | + TKUnit.assertEqual(pageBeforeNavigation, pageAfterNavigationBack, "Pages are different - livesync navigation executed!"); | ||
| 138 | + TKUnit.assertTrue(pageAfterNavigationBack._cssState.isSelectorsLatestVersionApplied(), "Latest selectors version is NOT applied!"); | ||
| 113 | 139 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -168,12 +168,15 @@ allTests["VISUAL-STATE"] = visualStateTests; | |||
| 168 | 168 | import * as valueSourceTests from "./ui/styling/value-source-tests"; | |
| 169 | 169 | allTests["VALUE-SOURCE"] = valueSourceTests; | |
| 170 | 170 | ||
| 171 | - import * as buttonTests from "./ui/button/button-tests"; | ||
| 172 | - allTests["BUTTON"] = buttonTests; | ||
| 173 | - | ||
| 174 | 171 | import * as borderTests from "./ui/border/border-tests"; | |
| 175 | 172 | allTests["BORDER"] = borderTests; | |
| 176 | 173 | ||
| 174 | + import * as builderTests from "./ui/builder/builder-tests"; | ||
| 175 | + allTests["BUILDER"] = builderTests; | ||
| 176 | + | ||
| 177 | + import * as buttonTests from "./ui/button/button-tests"; | ||
| 178 | + allTests["BUTTON"] = buttonTests; | ||
| 179 | + | ||
| 177 | 180 | import * as labelTests from "./ui/label/label-tests"; | |
| 178 | 181 | allTests["LABEL"] = labelTests; | |
| 179 | 182 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,26 @@ | |||
| 1 | + import { path } from "tns-core-modules/file-system"; | ||
| 2 | + import { loadPage } from "tns-core-modules/ui/builder"; | ||
| 3 | + import { assertEqual, assertNull } from "../../TKUnit"; | ||
| 4 | + | ||
| 5 | + const COMPONENT_MODULE = "component-module"; | ||
| 6 | + const LABEL = "label"; | ||
| 7 | + | ||
| 8 | + function getViewComponent() { | ||
| 9 | + const moduleNamePath = path.join(__dirname, COMPONENT_MODULE); | ||
| 10 | + const fileName = path.join(__dirname, `${COMPONENT_MODULE}.xml`); | ||
| 11 | + const view = loadPage(moduleNamePath, fileName); | ||
| 12 | + return view; | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + export function test_view_is_module_root_component() { | ||
| 16 | + const view = getViewComponent(); | ||
| 17 | + const actualModule = view._rootOfModule; | ||
| 18 | + assertEqual(actualModule, COMPONENT_MODULE, `View<${view}> is NOT root component of module <${COMPONENT_MODULE}>.`); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + export function test_view_is_NOT_module_root_component() { | ||
| 22 | + const view = getViewComponent(); | ||
| 23 | + const nestedView = view.getViewById(`${LABEL}`); | ||
| 24 | + const undefinedModule = nestedView._rootOfModule; | ||
| 25 | + assertNull(undefinedModule, `View<${nestedView}> should NOT be a root component of a module.`); | ||
| 26 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + <StackLayout> | ||
| 2 | + <Label id="label"></Label> | ||
| 3 | + </StackLayout> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -59,7 +59,9 @@ export function load(pathOrOptions: string | LoadOptions, context?: any): View { | |||
| 59 | 59 | ||
| 60 | 60 | export function loadPage(moduleNamePath: string, fileName: string, context?: any): View { | |
| 61 | 61 | const componentModule = loadInternal(fileName, context, moduleNamePath); | |
| 62 | - return componentModule && componentModule.component; | ||
| 62 | + const componentView = componentModule && componentModule.component; | ||
| 63 | + setRootOfModule(componentView, moduleNamePath); | ||
| 64 | + return componentView; | ||
| 63 | 65 | } | |
| 64 | 66 | ||
| 65 | 67 | const loadModule = profile("loadModule", (moduleNamePath: string, entry: ViewEntry): ModuleExports => { | |
@@ -96,7 +98,7 @@ export const createViewFromEntry = profile("createViewFromEntry", (entry: ViewEn | |||
| 96 | 98 | } else if (entry.moduleName) { | |
| 97 | 99 | // Current app full path. | |
| 98 | 100 | const currentAppPath = knownFolders.currentApp().path; | |
| 99 | - | ||
| 101 | + | ||
| 100 | 102 | // Full path of the module = current app full path + module name. | |
| 101 | 103 | const moduleNamePath = path.join(currentAppPath, entry.moduleName); | |
| 102 | 104 | const moduleExports = loadModule(moduleNamePath, entry); | |
@@ -108,7 +110,7 @@ export const createViewFromEntry = profile("createViewFromEntry", (entry: ViewEn | |||
| 108 | 110 | return viewFromBuilder(moduleNamePath, moduleExports); | |
| 109 | 111 | } | |
| 110 | 112 | } | |
| 111 | - | ||
| 113 | + | ||
| 112 | 114 | throw new Error("Failed to load page XML file for module: " + entry.moduleName); | |
| 113 | 115 | }); | |
| 114 | 116 | ||
@@ -128,14 +130,20 @@ interface ModuleExports { | |||
| 128 | 130 | const moduleCreateView = profile("module.createView", (moduleNamePath: string, moduleExports: ModuleExports): View => { | |
| 129 | 131 | const view = moduleExports.createPage(); | |
| 130 | 132 | const cssFileName = resolveFileName(moduleNamePath, "css"); | |
| 131 | - | ||
| 133 | + | ||
| 132 | 134 | // If there is no cssFile only appCss will be applied at loaded. | |
| 133 | 135 | if (cssFileName) { | |
| 134 | 136 | view.addCssFile(cssFileName); | |
| 135 | 137 | } | |
| 136 | 138 | return view; | |
| 137 | 139 | }); | |
| 138 | 140 | ||
| 141 | + function setRootOfModule(componentView: View, moduleNamePath: string): void { | ||
| 142 | + const lastIndexOfSeparator = moduleNamePath.lastIndexOf(path.separator); | ||
| 143 | + const moduleName = moduleNamePath.substring(lastIndexOfSeparator + 1); | ||
| 144 | + componentView._rootOfModule = moduleName; | ||
| 145 | + } | ||
| 146 | + | ||
| 139 | 147 | function loadInternal(fileName: string, context?: any, moduleNamePath?: string): ComponentModule { | |
| 140 | 148 | let componentModule: ComponentModule; | |
| 141 | 149 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -108,6 +108,12 @@ export abstract class ViewBase extends Observable { | |||
| 108 | 108 | flexWrapBefore: FlexWrapBefore; | |
| 109 | 109 | alignSelf: AlignSelf; | |
| 110 | 110 | ||
| 111 | + /** | ||
| 112 | + * @private | ||
| 113 | + * Module name when the view is a module root. Otherwise, it is undefined. | ||
| 114 | + */ | ||
| 115 | + _rootOfModule?: string; | ||
| 116 | + | ||
| 111 | 117 | //@private | |
| 112 | 118 | /** | |
| 113 | 119 | * @private | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -244,6 +244,8 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition | |||
| 244 | 244 | public _defaultPaddingLeft: number; | |
| 245 | 245 | public _isPaddingRelative: boolean; | |
| 246 | 246 | ||
| 247 | + public _rootOfModule: string; | ||
| 248 | + | ||
| 247 | 249 | constructor() { | |
| 248 | 250 | super(); | |
| 249 | 251 | this._domId = viewIdCounter++; | |
@@ -651,7 +653,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition | |||
| 651 | 653 | } | |
| 652 | 654 | ||
| 653 | 655 | public resetNativeView(): void { | |
| 654 | - // | ||
| 656 | + // | ||
| 655 | 657 | } | |
| 656 | 658 | ||
| 657 | 659 | private resetNativeViewInternal(): void { | |
@@ -688,7 +690,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition | |||
| 688 | 690 | ||
| 689 | 691 | this._context = context; | |
| 690 | 692 | ||
| 691 | - // This will account for nativeView that is created in createNativeView, recycled | ||
| 693 | + // This will account for nativeView that is created in createNativeView, recycled | ||
| 692 | 694 | // or for backward compatability - set before _setupUI in iOS contructor. | |
| 693 | 695 | let nativeView = this.nativeViewProtected; | |
| 694 | 696 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,7 +8,8 @@ import { | |||
| 8 | 8 | ViewBase, Property, booleanConverter, EventData, layout, | |
| 9 | 9 | getEventOrGestureName, traceEnabled, traceWrite, traceCategories, | |
| 10 | 10 | InheritedProperty, | |
| 11 | - ShowModalOptions | ||
| 11 | + ShowModalOptions, | ||
| 12 | + eachDescendant | ||
| 12 | 13 | } from "../view-base"; | |
| 13 | 14 | ||
| 14 | 15 | import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties"; | |
@@ -136,6 +137,36 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { | |||
| 136 | 137 | } | |
| 137 | 138 | } | |
| 138 | 139 | ||
| 140 | + public _onLivesync(context?: ModuleContext): boolean { | ||
| 141 | + _rootModalViews.forEach(v => v.closeModal()); | ||
| 142 | + _rootModalViews.length = 0; | ||
| 143 | + | ||
| 144 | + // Currently, we pass `context` only for style modules | ||
| 145 | + if (context && context.path) { | ||
| 146 | + return this.changeLocalStyles(context.path); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + return false; | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + private changeLocalStyles(contextPath: string): boolean { | ||
| 153 | + if (!this.changeStyles(this, contextPath)) { | ||
| 154 | + eachDescendant(this, (child: ViewBase) => { | ||
| 155 | + this.changeStyles(child, contextPath); | ||
| 156 | + return true; | ||
| 157 | + }); | ||
| 158 | + } | ||
| 159 | + return true; | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + private changeStyles(view: ViewBase, contextPath: string): boolean { | ||
| 163 | + if (view._rootOfModule && contextPath.includes(view._rootOfModule)) { | ||
| 164 | + (<this>view).changeCssFile(contextPath); | ||
| 165 | + return true; | ||
| 166 | + } | ||
| 167 | + return false; | ||
| 168 | + } | ||
| 169 | + | ||
| 139 | 170 | _setupAsRootView(context: any): void { | |
| 140 | 171 | super._setupAsRootView(context); | |
| 141 | 172 | if (!this._styleScope) { | |
@@ -210,12 +241,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { | |||
| 210 | 241 | } | |
| 211 | 242 | } | |
| 212 | 243 | ||
| 213 | - _onLivesync(): boolean { | ||
| 214 | - _rootModalViews.forEach(v => v.closeModal()); | ||
| 215 | - _rootModalViews.length = 0; | ||
| 216 | - return false; | ||
| 217 | - } | ||
| 218 | - | ||
| 219 | 244 | public onBackPressed(): boolean { | |
| 220 | 245 | return false; | |
| 221 | 246 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -720,6 +720,12 @@ export abstract class View extends ViewBase { | |||
| 720 | 720 | * __Obsolete:__ There is a new property system that does not rely on _setValue. | |
| 721 | 721 | */ | |
| 722 | 722 | _setValue(property: any, value: any): never; | |
| 723 | + | ||
| 724 | + /** | ||
| 725 | + * @private | ||
| 726 | + * Module name in case the view is a root. Otherwise, it is undefined. | ||
| 727 | + */ | ||
| 728 | + _rootOfModule?: string; | ||
| 723 | 729 | } | |
| 724 | 730 | ||
| 725 | 731 | /** | |
| Back | FazBrowse Home | New Git URL |
0 commit comments