mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 03:31:45 +08:00
fix(module-name-resolver): livesync page qualifier handling (#8637)
closes https://github.com/NativeScript/NativeScript/issues/8622 Co-authored-by: Dimitris - Rafail Katsampas <katsampasdr@gmail.com>
This commit is contained in:
@ -39,6 +39,7 @@ export function pageLoaded(args: EventData) {
|
|||||||
examples.set("progress-bar", "progress-bar/main-page");
|
examples.set("progress-bar", "progress-bar/main-page");
|
||||||
examples.set("date-picker", "date-picker/date-picker-page");
|
examples.set("date-picker", "date-picker/date-picker-page");
|
||||||
examples.set("nested-frames", "nested-frames/main-page");
|
examples.set("nested-frames", "nested-frames/main-page");
|
||||||
|
examples.set("screen-qualifiers", "screen-qualifiers/main-page");
|
||||||
page.bindingContext = new MainPageViewModel(wrapLayout, examples);
|
page.bindingContext = new MainPageViewModel(wrapLayout, examples);
|
||||||
|
|
||||||
const parent = page.getViewById("parentLayout");
|
const parent = page.getViewById("parentLayout");
|
||||||
|
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.ios.xml
Normal file
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.ios.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
|
||||||
|
<ActionBar>
|
||||||
|
<Label text="Screen Qualifiers"></Label>
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<StackLayout>
|
||||||
|
<Label text="{{ currentDate }}" fontSize="20"/>
|
||||||
|
<Label text="IOS Page" backgroundColor="deepskyblue" fontSize="20"/>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.land.xml
Normal file
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.land.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
|
||||||
|
<ActionBar>
|
||||||
|
<Label text="Screen Qualifiers"></Label>
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<StackLayout>
|
||||||
|
<Label text="{{ currentDate }}" fontSize="20"/>
|
||||||
|
<Label text="LandScape Page" backgroundColor="deepskyblue" fontSize="20"/>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
@ -0,0 +1,10 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
|
||||||
|
<ActionBar>
|
||||||
|
<Label text="Screen Qualifiers"></Label>
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<StackLayout>
|
||||||
|
<Label text="{{ currentDate }}" fontSize="20"/>
|
||||||
|
<Label text="minWH 120 DIP Portrait Page" backgroundColor="deepskyblue" fontSize="20"/>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.minWH360.ts
Normal file
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.minWH360.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { EventData } from "tns-core-modules/data/observable";
|
||||||
|
import { Observable } from "tns-core-modules/data/observable";
|
||||||
|
import { Page } from "tns-core-modules/ui/page";
|
||||||
|
|
||||||
|
export function pageLoaded(args: EventData) {
|
||||||
|
const page = <Page>args.object;
|
||||||
|
|
||||||
|
page.bindingContext = new Observable();
|
||||||
|
page.bindingContext.set("currentDate", "No date for alternate screens!");
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
|
||||||
|
<ActionBar>
|
||||||
|
<Label text="Screen Qualifiers"></Label>
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<StackLayout>
|
||||||
|
<Label text="{{ currentDate }}" fontSize="20"/>
|
||||||
|
<Label text="minWH 360 DIP Page" backgroundColor="deepskyblue" fontSize="20"/>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.ts
Normal file
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { EventData } from "tns-core-modules/data/observable";
|
||||||
|
import { Observable } from "tns-core-modules/data/observable";
|
||||||
|
import { Page } from "tns-core-modules/ui/page";
|
||||||
|
|
||||||
|
export function pageLoaded(args: EventData) {
|
||||||
|
const page = <Page>args.object;
|
||||||
|
|
||||||
|
page.bindingContext = new Observable();
|
||||||
|
page.bindingContext.set("currentDate", new Date());
|
||||||
|
}
|
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.xml
Normal file
10
e2e/ui-tests-app/app/screen-qualifiers/main-page.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
|
||||||
|
<ActionBar>
|
||||||
|
<Label text="Screen Qualifiers"></Label>
|
||||||
|
</ActionBar>
|
||||||
|
|
||||||
|
<StackLayout>
|
||||||
|
<Label text="{{ currentDate }}" fontSize="20"/>
|
||||||
|
<Label text="Default Page" backgroundColor="yellow" fontSize="20"/>
|
||||||
|
</StackLayout>
|
||||||
|
</Page>
|
@ -1,7 +1,7 @@
|
|||||||
import { ModuleNameResolver as ModuleNameResolverDefinition, ModuleListProvider } from "./";
|
import { ModuleNameResolver as ModuleNameResolverDefinition, ModuleListProvider } from "./";
|
||||||
import { screen, device } from "../platform/platform";
|
import { screen, device } from "../platform/platform";
|
||||||
import * as appCommonModule from "../application/application-common";
|
import * as appCommonModule from "../application/application-common";
|
||||||
import { PlatformContext, findMatch } from "./qualifier-matcher";
|
import { PlatformContext, findMatch, stripQualifiers } from "./qualifier-matcher";
|
||||||
import { registerModulesFromFileSystem } from "./non-bundle-workflow-compat";
|
import { registerModulesFromFileSystem } from "./non-bundle-workflow-compat";
|
||||||
import {
|
import {
|
||||||
isEnabled as traceEnabled,
|
isEnabled as traceEnabled,
|
||||||
@ -44,6 +44,9 @@ export class ModuleNameResolver implements ModuleNameResolverDefinition {
|
|||||||
registerModulesFromFileSystem(path);
|
registerModulesFromFileSystem(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This call will return a clean path without qualifiers
|
||||||
|
path = stripQualifiers(path);
|
||||||
|
|
||||||
let candidates = this.getCandidates(path, ext);
|
let candidates = this.getCandidates(path, ext);
|
||||||
result = findMatch(path, ext, candidates, this.context);
|
result = findMatch(path, ext, candidates, this.context);
|
||||||
|
|
||||||
|
@ -11,3 +11,5 @@ export interface PlatformContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function findMatch(path: string, ext: string, candidates: Array<string>, context: PlatformContext): string;
|
export function findMatch(path: string, ext: string, candidates: Array<string>, context: PlatformContext): string;
|
||||||
|
|
||||||
|
export function stripQualifiers(path: string): string
|
||||||
|
@ -5,17 +5,20 @@ const MIN_H: string = "minH";
|
|||||||
const PRIORITY_STEP = 10000;
|
const PRIORITY_STEP = 10000;
|
||||||
|
|
||||||
interface QualifierSpec {
|
interface QualifierSpec {
|
||||||
isMatch(value: string): boolean;
|
isMatch(path: string): boolean;
|
||||||
|
getMatchOccurences(path: string): Array<string>;
|
||||||
getMatchValue(value: string, context: PlatformContext): number;
|
getMatchValue(value: string, context: PlatformContext): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const minWidthHeightQualifier: QualifierSpec = {
|
const minWidthHeightQualifier: QualifierSpec = {
|
||||||
isMatch: function (value: string): boolean {
|
isMatch: function (path: string): boolean {
|
||||||
return value.indexOf(MIN_WH) === 0;
|
return (new RegExp(`.${MIN_WH}\\d+`).test(path));
|
||||||
|
},
|
||||||
|
getMatchOccurences: function (path: string): Array<string> {
|
||||||
|
return path.match(new RegExp(`.${MIN_WH}\\d+`));
|
||||||
},
|
},
|
||||||
getMatchValue(value: string, context: PlatformContext): number {
|
getMatchValue(value: string, context: PlatformContext): number {
|
||||||
const numVal = parseInt(value.substr(MIN_WH.length));
|
const numVal = parseInt(value.substr(MIN_WH.length + 1));
|
||||||
if (isNaN(numVal)) {
|
if (isNaN(numVal)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -30,12 +33,14 @@ const minWidthHeightQualifier: QualifierSpec = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const minWidthQualifier: QualifierSpec = {
|
const minWidthQualifier: QualifierSpec = {
|
||||||
isMatch: function (value: string): boolean {
|
isMatch: function (path: string): boolean {
|
||||||
return value.indexOf(MIN_W) === 0 && value.indexOf(MIN_WH) < 0;
|
return (new RegExp(`.${MIN_W}\\d+`).test(path)) && !(new RegExp(`.${MIN_WH}\\d+`).test(path));
|
||||||
|
},
|
||||||
|
getMatchOccurences: function (path: string): Array<string> {
|
||||||
|
return path.match(new RegExp(`.${MIN_W}\\d+`));
|
||||||
},
|
},
|
||||||
getMatchValue(value: string, context: PlatformContext): number {
|
getMatchValue(value: string, context: PlatformContext): number {
|
||||||
const numVal = parseInt(value.substr(MIN_W.length));
|
const numVal = parseInt(value.substr(MIN_W.length + 1));
|
||||||
if (isNaN(numVal)) {
|
if (isNaN(numVal)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -50,12 +55,14 @@ const minWidthQualifier: QualifierSpec = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const minHeightQualifier: QualifierSpec = {
|
const minHeightQualifier: QualifierSpec = {
|
||||||
isMatch: function (value: string): boolean {
|
isMatch: function (path: string): boolean {
|
||||||
return value.indexOf(MIN_H) === 0 && value.indexOf(MIN_WH) < 0;
|
return (new RegExp(`.${MIN_H}\\d+`).test(path)) && !(new RegExp(`.${MIN_WH}\\d+`).test(path));
|
||||||
|
},
|
||||||
|
getMatchOccurences: function (path: string): Array<string> {
|
||||||
|
return path.match(new RegExp(`.${MIN_H}\\d+`));
|
||||||
},
|
},
|
||||||
getMatchValue(value: string, context: PlatformContext): number {
|
getMatchValue(value: string, context: PlatformContext): number {
|
||||||
const numVal = parseInt(value.substr(MIN_H.length));
|
const numVal = parseInt(value.substr(MIN_H.length + 1));
|
||||||
if (isNaN(numVal)) {
|
if (isNaN(numVal)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -70,26 +77,31 @@ const minHeightQualifier: QualifierSpec = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const platformQualifier: QualifierSpec = {
|
const platformQualifier: QualifierSpec = {
|
||||||
isMatch: function (value: string): boolean {
|
isMatch: function (path: string): boolean {
|
||||||
return value === "android" ||
|
return path.includes(".android") || path.includes(".ios");
|
||||||
value === "ios";
|
},
|
||||||
|
getMatchOccurences: function (path: string): Array<string> {
|
||||||
|
return [".android", ".ios"];
|
||||||
},
|
},
|
||||||
getMatchValue(value: string, context: PlatformContext): number {
|
getMatchValue(value: string, context: PlatformContext): number {
|
||||||
return value === context.os.toLowerCase() ? 1 : -1;
|
const val = value.substr(1);
|
||||||
|
|
||||||
|
return val === context.os.toLowerCase() ? 1 : -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const orientationQualifier: QualifierSpec = {
|
const orientationQualifier: QualifierSpec = {
|
||||||
isMatch: function (value: string): boolean {
|
isMatch: function (path: string): boolean {
|
||||||
return value === "land" ||
|
return path.includes(".land") || path.includes(".port");
|
||||||
value === "port";
|
},
|
||||||
|
getMatchOccurences: function (path: string): Array<string> {
|
||||||
|
return [".land", ".port"];
|
||||||
},
|
},
|
||||||
getMatchValue(value: string, context: PlatformContext): number {
|
getMatchValue(value: string, context: PlatformContext): number {
|
||||||
|
const val = value.substr(1);
|
||||||
const isLandscape: number = (context.width > context.height) ? 1 : -1;
|
const isLandscape: number = (context.width > context.height) ? 1 : -1;
|
||||||
|
|
||||||
return (value === "land") ? isLandscape : -isLandscape;
|
return (val === "land") ? isLandscape : -isLandscape;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,51 +114,63 @@ const supportedQualifiers: Array<QualifierSpec> = [
|
|||||||
platformQualifier
|
platformQualifier
|
||||||
];
|
];
|
||||||
|
|
||||||
function checkQualifiers(qualifiers: Array<string>, context: PlatformContext): number {
|
function checkQualifiers(path: string, context: PlatformContext): number {
|
||||||
let result = 0;
|
let result = 0;
|
||||||
let value: number;
|
for (let i = 0; i < supportedQualifiers.length; i++) {
|
||||||
for (let i = 0; i < qualifiers.length; i++) {
|
let qualifier = supportedQualifiers[i];
|
||||||
if (qualifiers[i]) {
|
if (qualifier.isMatch(path))
|
||||||
value = checkQualifier(qualifiers[i], context);
|
{
|
||||||
if (value < 0) {
|
let occurences = qualifier.getMatchOccurences(path);
|
||||||
|
// Always get the last qualifier among identical occurences
|
||||||
|
result = qualifier.getMatchValue(occurences[occurences.length - 1], context);
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
// Non of the supported qualifiers matched this or the match was not satisfied
|
// Non of the supported qualifiers matched this or the match was not satisfied
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
result += value;
|
result += (supportedQualifiers.length - i) * PRIORITY_STEP;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkQualifier(value: string, context: PlatformContext) {
|
export function stripQualifiers(path: string): string {
|
||||||
let result: number;
|
// Strip qualifiers from path if any
|
||||||
for (let i = 0; i < supportedQualifiers.length; i++) {
|
for (let i = 0; i < supportedQualifiers.length; i++) {
|
||||||
if (supportedQualifiers[i].isMatch(value)) {
|
let qualifier = supportedQualifiers[i];
|
||||||
result = supportedQualifiers[i].getMatchValue(value, context);
|
if (qualifier.isMatch(path))
|
||||||
if (result > 0) {
|
{
|
||||||
result += (supportedQualifiers.length - i) * PRIORITY_STEP;
|
let occurences = qualifier.getMatchOccurences(path);
|
||||||
|
for (let j = 0; j < occurences.length; j++)
|
||||||
|
{
|
||||||
|
path = path.replace(occurences[j], "");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findMatch(path: string, ext: string, candidates: Array<string>, context: PlatformContext): string {
|
export function findMatch(path: string, ext: string, candidates: Array<string>, context: PlatformContext): string {
|
||||||
|
let fullPath: string = ext ? (path + ext) : path;
|
||||||
let bestValue = -1;
|
let bestValue = -1;
|
||||||
let result: string = null;
|
let result: string = null;
|
||||||
|
|
||||||
for (let i = 0; i < candidates.length; i++) {
|
for (let i = 0; i < candidates.length; i++) {
|
||||||
const filePath = candidates[i];
|
const filePath = candidates[i];
|
||||||
const qualifiersStr: string = filePath.substr(path.length, filePath.length - path.length - (ext ? ext.length : 0));
|
|
||||||
|
|
||||||
const qualifiers = qualifiersStr.split(".");
|
// Check if candidate is correct for given path
|
||||||
|
const cleanFilePath: string = stripQualifiers(filePath);
|
||||||
|
if (cleanFilePath !== fullPath)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const value = checkQualifiers(qualifiers, context);
|
const value = checkQualifiers(filePath, context);
|
||||||
|
|
||||||
if (value >= 0 && value > bestValue) {
|
if (value >= 0 && value > bestValue) {
|
||||||
bestValue = value;
|
bestValue = value;
|
||||||
|
Reference in New Issue
Block a user