mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Housekeeping node tests, renamed to unit-tests (#4936)
Add parsers for the background css shorthand property, make ViewBase unit testable in node environment
Add background parser and linear-gradient parser
Use sticky regexes
Simplify some types, introduce generic Parsed<T> instead of & TokenRange
Apply each parser to return a { start, end, value } object
Move the css selector parser to the css/parser and unify types
Add the first steps toward building homegrown css parser
Add somewhat standards compliant tokenizer, add baseline, rework and shady css parsers
Enable all tests again, skip flaky perf test
Improve css parser tokenizer by converting some char token types to simple string
Implement 'parse a stylesheet'
Add gonzales css-parser
Add parseLib and css-tree perf
Add a thin parser layer that will convert CSS3 tokens to values, for now output is compatible with rework
Make root tsc green
Return the requires of tns-core-modules to use relative paths for webpack to work
Implement support for '@import 'url-string';
Fix function parser, function-token is no-longer neglected
Make the style-scope be able to load from "css" and "css-ast" modules
Add a loadAppCss event so theme can be added to snapshot separately from loaded
This commit is contained in:
committed by
Hristo Hristov
parent
2eba7c66e4
commit
f7a3a36b9c
@@ -17,7 +17,7 @@ export function hasLaunched(): boolean {
|
||||
|
||||
export { Observable };
|
||||
|
||||
import { UnhandledErrorEventData, iOSApplication, AndroidApplication, CssChangedEventData } from ".";
|
||||
import { UnhandledErrorEventData, iOSApplication, AndroidApplication, CssChangedEventData, LoadAppCSSEventData } from ".";
|
||||
|
||||
export const launchEvent = "launch";
|
||||
export const suspendEvent = "suspend";
|
||||
@@ -66,6 +66,10 @@ export function getCssFileName(): string {
|
||||
return cssFile;
|
||||
}
|
||||
|
||||
export function loadAppCss(): void {
|
||||
events.notify(<LoadAppCSSEventData>{ eventName: "loadAppCss", object: app, cssFile: getCssFileName() });
|
||||
}
|
||||
|
||||
export function addCss(cssText: string): void {
|
||||
events.notify(<CssChangedEventData>{ eventName: "cssChanged", object: app, cssText: cssText });
|
||||
}
|
||||
|
||||
12
tns-core-modules/application/application.d.ts
vendored
12
tns-core-modules/application/application.d.ts
vendored
@@ -141,6 +141,14 @@ export function setCssFileName(cssFile: string): void;
|
||||
*/
|
||||
export function getCssFileName(): string;
|
||||
|
||||
/**
|
||||
* Loads immediately the app.css.
|
||||
* By default the app.css file is loaded shortly after "loaded".
|
||||
* For the Android snapshot the CSS can be parsed during the snapshot generation,
|
||||
* as the CSS does not depend on runtime APIs, and loadAppCss will be called explicitly.
|
||||
*/
|
||||
export function loadAppCss();
|
||||
|
||||
export function addCss(cssText: string): void;
|
||||
|
||||
/**
|
||||
@@ -553,3 +561,7 @@ export function getNativeApplication(): any;
|
||||
* Indicates if the application is allready launched. See also the `application.on("launch", handler)` event.
|
||||
*/
|
||||
export function hasLaunched(): boolean;
|
||||
|
||||
export interface LoadAppCSSEventData extends EventData {
|
||||
cssFile: string;
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
import { iOSApplication as IOSApplicationDefinition, LaunchEventData, ApplicationEventData, OrientationChangedEventData } from ".";
|
||||
import {
|
||||
iOSApplication as IOSApplicationDefinition,
|
||||
LaunchEventData,
|
||||
ApplicationEventData,
|
||||
OrientationChangedEventData,
|
||||
LoadAppCSSEventData
|
||||
} from ".";
|
||||
|
||||
import {
|
||||
notify, launchEvent, resumeEvent, suspendEvent, exitEvent, lowMemoryEvent,
|
||||
orientationChangedEvent, setApplication, livesync, displayedEvent
|
||||
orientationChangedEvent, setApplication, livesync, displayedEvent, getCssFileName
|
||||
} from "./application-common";
|
||||
|
||||
// First reexport so that app module is initialized.
|
||||
@@ -117,6 +123,7 @@ class IOSApplication implements IOSApplicationDefinition {
|
||||
};
|
||||
|
||||
notify(args);
|
||||
notify(<LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: getCssFileName() });
|
||||
|
||||
let rootView = createRootView(args.root);
|
||||
this._window.content = rootView;
|
||||
|
||||
@@ -5,6 +5,8 @@ const enum MessageType {
|
||||
error = 3
|
||||
}
|
||||
|
||||
declare function __time(): number;
|
||||
|
||||
function __message(message: any, level: string) {
|
||||
if ((<any>global).__consoleMessage) {
|
||||
(<any>global).__consoleMessage(message, level);
|
||||
@@ -227,7 +229,7 @@ export class Console {
|
||||
}
|
||||
|
||||
private timeMillis() {
|
||||
return java.lang.System.nanoTime() / 1000000; // 1 ms = 1000000 ns
|
||||
return __time(); // 1 ms = 1000000 ns
|
||||
}
|
||||
|
||||
public time(reportName: string): void {
|
||||
|
||||
1544
tns-core-modules/css/parser.ts
Normal file
1544
tns-core-modules/css/parser.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,20 +19,11 @@ function ensurePlatform() {
|
||||
}
|
||||
}
|
||||
|
||||
// we are defining these as private variables within the IO scope and will use them to access the corresponding properties for each FSEntity instance.
|
||||
// this allows us to encapsulate (hide) the explicit property setters and force the users go through the exposed APIs to receive FSEntity instances.
|
||||
var nameProperty = "_name";
|
||||
var pathProperty = "_path";
|
||||
var isKnownProperty = "_isKnown";
|
||||
var fileLockedProperty = "_locked";
|
||||
var extensionProperty = "_extension";
|
||||
var lastModifiedProperty = "_lastModified";
|
||||
|
||||
var createFile = function (info: { path: string; name: string; extension: string }) {
|
||||
var file = new File();
|
||||
file[pathProperty] = info.path;
|
||||
file[nameProperty] = info.name;
|
||||
file[extensionProperty] = info.extension;
|
||||
file._path = info.path;
|
||||
file._name = info.name;
|
||||
file._extension = info.extension;
|
||||
|
||||
return file;
|
||||
};
|
||||
@@ -50,13 +41,20 @@ var createFolder = function (info: { path: string; name: string; }) {
|
||||
|
||||
var folder = new Folder();
|
||||
|
||||
folder[pathProperty] = info.path;
|
||||
folder[nameProperty] = info.name;
|
||||
folder._path = info.path;
|
||||
folder._name = info.name;
|
||||
|
||||
return folder;
|
||||
};
|
||||
|
||||
export class FileSystemEntity {
|
||||
_path: string;
|
||||
_name: string;
|
||||
_extension: string;
|
||||
_locked: boolean;
|
||||
_lastModified: Date;
|
||||
_isKnown: boolean;
|
||||
|
||||
get parent(): Folder {
|
||||
var onError = function (error) {
|
||||
throw error;
|
||||
@@ -86,7 +84,7 @@ export class FileSystemEntity {
|
||||
}
|
||||
|
||||
public removeSync(onError?: (error: any) => any): void {
|
||||
if (this[isKnownProperty]) {
|
||||
if (this._isKnown) {
|
||||
if (onError) {
|
||||
onError({ message: "Cannot delete known folder." });
|
||||
}
|
||||
@@ -120,7 +118,7 @@ export class FileSystemEntity {
|
||||
}
|
||||
|
||||
public renameSync(newName: string, onError?: (error: any) => any): void {
|
||||
if (this[isKnownProperty]) {
|
||||
if (this._isKnown) {
|
||||
if (onError) {
|
||||
onError(new Error("Cannot rename known folder."));
|
||||
}
|
||||
@@ -149,26 +147,26 @@ export class FileSystemEntity {
|
||||
}
|
||||
|
||||
fileAccess.rename(this.path, newPath, localError);
|
||||
this[pathProperty] = newPath;
|
||||
this[nameProperty] = newName;
|
||||
this._path = newPath;
|
||||
this._name = newName;
|
||||
|
||||
if (this instanceof File) {
|
||||
this[extensionProperty] = fileAccess.getFileExtension(newPath);
|
||||
this._extension = fileAccess.getFileExtension(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this[nameProperty];
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get path(): string {
|
||||
return this[pathProperty];
|
||||
return this._path;
|
||||
}
|
||||
|
||||
get lastModified(): Date {
|
||||
var value = this[lastModifiedProperty];
|
||||
if (!this[lastModifiedProperty]) {
|
||||
value = this[lastModifiedProperty] = getFileAccess().getLastModified(this.path);
|
||||
var value = this._lastModified;
|
||||
if (!this._lastModified) {
|
||||
value = this._lastModified = getFileAccess().getLastModified(this.path);
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -194,22 +192,22 @@ export class File extends FileSystemEntity {
|
||||
}
|
||||
|
||||
get extension(): string {
|
||||
return this[extensionProperty];
|
||||
return this._extension;
|
||||
}
|
||||
|
||||
get isLocked(): boolean {
|
||||
// !! is a boolean conversion/cast, handling undefined as well
|
||||
return !!this[fileLockedProperty];
|
||||
return !!this._locked;
|
||||
}
|
||||
|
||||
public readSync(onError?: (error: any) => any): any {
|
||||
this.checkAccess();
|
||||
|
||||
this[fileLockedProperty] = true;
|
||||
this._locked = true;
|
||||
|
||||
var that = this;
|
||||
var localError = (error) => {
|
||||
that[fileLockedProperty] = false;
|
||||
that._locked = false;
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
@@ -217,7 +215,7 @@ export class File extends FileSystemEntity {
|
||||
|
||||
var content = getFileAccess().read(this.path, localError);
|
||||
|
||||
this[fileLockedProperty] = false;
|
||||
this._locked = false;
|
||||
|
||||
return content;
|
||||
|
||||
@@ -227,11 +225,11 @@ export class File extends FileSystemEntity {
|
||||
this.checkAccess();
|
||||
|
||||
try {
|
||||
this[fileLockedProperty] = true;
|
||||
this._locked = true;
|
||||
|
||||
var that = this;
|
||||
var localError = function (error) {
|
||||
that[fileLockedProperty] = false;
|
||||
that._locked = false;
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
@@ -239,7 +237,7 @@ export class File extends FileSystemEntity {
|
||||
|
||||
getFileAccess().write(this.path, content, localError);
|
||||
} finally {
|
||||
this[fileLockedProperty] = false;
|
||||
this._locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,18 +260,18 @@ export class File extends FileSystemEntity {
|
||||
public readTextSync(onError?: (error: any) => any, encoding?: string): string {
|
||||
this.checkAccess();
|
||||
|
||||
this[fileLockedProperty] = true;
|
||||
this._locked = true;
|
||||
|
||||
var that = this;
|
||||
var localError = (error) => {
|
||||
that[fileLockedProperty] = false;
|
||||
that._locked = false;
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
};
|
||||
|
||||
var content = getFileAccess().readText(this.path, localError, encoding);
|
||||
this[fileLockedProperty] = false;
|
||||
this._locked = false;
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -297,11 +295,11 @@ export class File extends FileSystemEntity {
|
||||
this.checkAccess();
|
||||
|
||||
try {
|
||||
this[fileLockedProperty] = true;
|
||||
this._locked = true;
|
||||
|
||||
var that = this;
|
||||
var localError = function (error) {
|
||||
that[fileLockedProperty] = false;
|
||||
that._locked = false;
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
@@ -310,7 +308,7 @@ export class File extends FileSystemEntity {
|
||||
// TODO: Asyncronous
|
||||
getFileAccess().writeText(this.path, content, localError, encoding);
|
||||
} finally {
|
||||
this[fileLockedProperty] = false;
|
||||
this._locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +368,7 @@ export class Folder extends FileSystemEntity {
|
||||
}
|
||||
|
||||
get isKnown(): boolean {
|
||||
return this[isKnownProperty];
|
||||
return this._isKnown;
|
||||
}
|
||||
|
||||
public getFile(name: string): File {
|
||||
@@ -473,8 +471,8 @@ export module knownFolders {
|
||||
if (!_documents) {
|
||||
var path = getFileAccess().getDocumentsFolderPath();
|
||||
_documents = new Folder();
|
||||
_documents[pathProperty] = path;
|
||||
_documents[isKnownProperty] = true;
|
||||
_documents._path = path;
|
||||
_documents._isKnown = true;
|
||||
}
|
||||
|
||||
return _documents;
|
||||
@@ -484,8 +482,8 @@ export module knownFolders {
|
||||
if (!_temp) {
|
||||
var path = getFileAccess().getTempFolderPath();
|
||||
_temp = new Folder();
|
||||
_temp[pathProperty] = path;
|
||||
_temp[isKnownProperty] = true;
|
||||
_temp._path = path;
|
||||
_temp._isKnown = true;
|
||||
}
|
||||
|
||||
return _temp;
|
||||
@@ -495,8 +493,8 @@ export module knownFolders {
|
||||
if (!_app) {
|
||||
var path = getFileAccess().getCurrentAppPath();
|
||||
_app = new Folder();
|
||||
_app[pathProperty] = path;
|
||||
_app[isKnownProperty] = true;
|
||||
_app._path = path;
|
||||
_app._isKnown = true;
|
||||
}
|
||||
|
||||
return _app;
|
||||
@@ -518,8 +516,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_library = existingFolderInfo.folder;
|
||||
_library[pathProperty] = existingFolderInfo.path;
|
||||
_library[isKnownProperty] = true;
|
||||
_library._path = existingFolderInfo.path;
|
||||
_library._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,8 +532,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_developer = existingFolderInfo.folder;
|
||||
_developer[pathProperty] = existingFolderInfo.path;
|
||||
_developer[isKnownProperty] = true;
|
||||
_developer._path = existingFolderInfo.path;
|
||||
_developer._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,8 +548,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_desktop = existingFolderInfo.folder;
|
||||
_desktop[pathProperty] = existingFolderInfo.path;
|
||||
_desktop[isKnownProperty] = true;
|
||||
_desktop._path = existingFolderInfo.path;
|
||||
_desktop._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,8 +564,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_downloads = existingFolderInfo.folder;
|
||||
_downloads[pathProperty] = existingFolderInfo.path;
|
||||
_downloads[isKnownProperty] = true;
|
||||
_downloads._path = existingFolderInfo.path;
|
||||
_downloads._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,8 +580,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_movies = existingFolderInfo.folder;
|
||||
_movies[pathProperty] = existingFolderInfo.path;
|
||||
_movies[isKnownProperty] = true;
|
||||
_movies._path = existingFolderInfo.path;
|
||||
_movies._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,8 +596,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_music = existingFolderInfo.folder;
|
||||
_music[pathProperty] = existingFolderInfo.path;
|
||||
_music[isKnownProperty] = true;
|
||||
_music._path = existingFolderInfo.path;
|
||||
_music._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,8 +612,8 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_pictures = existingFolderInfo.folder;
|
||||
_pictures[pathProperty] = existingFolderInfo.path;
|
||||
_pictures[isKnownProperty] = true;
|
||||
_pictures._path = existingFolderInfo.path;
|
||||
_pictures._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,15 +628,15 @@ export module knownFolders {
|
||||
|
||||
if (existingFolderInfo) {
|
||||
_sharedPublic = existingFolderInfo.folder;
|
||||
_sharedPublic[pathProperty] = existingFolderInfo.path;
|
||||
_sharedPublic[isKnownProperty] = true;
|
||||
_sharedPublic._path = existingFolderInfo.path;
|
||||
_sharedPublic._isKnown = true;
|
||||
}
|
||||
}
|
||||
|
||||
return _sharedPublic;
|
||||
};
|
||||
|
||||
function getExistingFolderInfo(pathDirectory: NSSearchPathDirectory): { folder: Folder; path: string } {
|
||||
function getExistingFolderInfo(pathDirectory: any /* NSSearchPathDirectory */): { folder: Folder; path: string } {
|
||||
var fileAccess = (<any>getFileAccess());
|
||||
var folderPath = fileAccess.getKnownPath(pathDirectory);
|
||||
var folderInfo = fileAccess.getExistingFolder(folderPath);
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
require("./decorators");
|
||||
|
||||
// Required by V8 snapshot generator
|
||||
global.__extends = global.__extends || function (d, b) {
|
||||
for (var p in b) {
|
||||
if (b.hasOwnProperty(p)) {
|
||||
d[p] = b[p];
|
||||
if (!global.__extends) {
|
||||
global.__extends = function (d, b) {
|
||||
for (var p in b) {
|
||||
if (b.hasOwnProperty(p)) {
|
||||
d[p] = b[p];
|
||||
}
|
||||
}
|
||||
}
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
}
|
||||
|
||||
// This method iterates all the keys in the source exports object and copies them to the destination exports one.
|
||||
// Note: the method will not check for naming collisions and will override any already existing entries in the destination exports.
|
||||
@@ -26,6 +28,8 @@ import * as dialogsModule from "../ui/dialogs";
|
||||
type ModuleLoader = (name?: string) => any;
|
||||
const modules: Map<string, ModuleLoader> = new Map<string, ModuleLoader>();
|
||||
|
||||
(<any>global).moduleResolvers = [global.require];
|
||||
|
||||
global.registerModule = function(name: string, loader: ModuleLoader): void {
|
||||
modules.set(name, loader);
|
||||
}
|
||||
@@ -38,10 +42,13 @@ global.loadModule = function(name: string): any {
|
||||
const loader = modules.get(name);
|
||||
if (loader) {
|
||||
return loader();
|
||||
} else {
|
||||
let result = global.require(name);
|
||||
modules.set(name, () => result);
|
||||
return result;
|
||||
}
|
||||
for (let resolver of (<any>global).moduleResolvers) {
|
||||
const result = resolver(name);
|
||||
if (result) {
|
||||
modules.set(name, () => result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +78,6 @@ function registerOnGlobalContext(name: string, module: string): void {
|
||||
get: function () {
|
||||
// We do not need to cache require() call since it is already cached in the runtime.
|
||||
let m = global.loadModule(module);
|
||||
if (!__tnsGlobalMergedModules.has(module)) {
|
||||
__tnsGlobalMergedModules.set(module, true);
|
||||
global.moduleMerge(m, global);
|
||||
}
|
||||
|
||||
// Redefine the property to make sure the above code is executed only once.
|
||||
let resolvedValue = m[name];
|
||||
@@ -106,6 +109,8 @@ export function install() {
|
||||
alert: dialogs.alert,
|
||||
confirm: dialogs.confirm,
|
||||
prompt: dialogs.prompt,
|
||||
login: dialogs.login,
|
||||
action: dialogs.action,
|
||||
|
||||
XMLHttpRequest: xhr.XMLHttpRequest,
|
||||
FormData: xhr.FormData,
|
||||
@@ -124,12 +129,20 @@ export function install() {
|
||||
registerOnGlobalContext("clearTimeout", "timer");
|
||||
registerOnGlobalContext("setInterval", "timer");
|
||||
registerOnGlobalContext("clearInterval", "timer");
|
||||
|
||||
registerOnGlobalContext("alert", "ui/dialogs");
|
||||
registerOnGlobalContext("confirm", "ui/dialogs");
|
||||
registerOnGlobalContext("prompt", "ui/dialogs");
|
||||
registerOnGlobalContext("login", "ui/dialogs");
|
||||
registerOnGlobalContext("action", "ui/dialogs");
|
||||
|
||||
registerOnGlobalContext("XMLHttpRequest", "xhr");
|
||||
registerOnGlobalContext("FormData", "xhr");
|
||||
|
||||
registerOnGlobalContext("fetch", "fetch");
|
||||
registerOnGlobalContext("Headers", "fetch");
|
||||
registerOnGlobalContext("Request", "fetch");
|
||||
registerOnGlobalContext("Response", "fetch");
|
||||
|
||||
// check whether the 'android' namespace is exposed
|
||||
// if positive - the current device is an Android
|
||||
|
||||
@@ -4,9 +4,10 @@ import * as platform from "../platform";
|
||||
|
||||
export class ImageAsset extends observable.Observable implements definition.ImageAsset {
|
||||
private _options: definition.ImageAssetOptions;
|
||||
private _ios: PHAsset;
|
||||
private _nativeImage: any;
|
||||
private _android: string; //file name of the image
|
||||
|
||||
ios: PHAsset;
|
||||
android: string;
|
||||
|
||||
get options(): definition.ImageAssetOptions {
|
||||
return this._options;
|
||||
@@ -16,22 +17,6 @@ export class ImageAsset extends observable.Observable implements definition.Ima
|
||||
this._options = value;
|
||||
}
|
||||
|
||||
get ios(): PHAsset {
|
||||
return this._ios;
|
||||
}
|
||||
|
||||
set ios(value: PHAsset) {
|
||||
this._ios = value;
|
||||
}
|
||||
|
||||
get android(): string {
|
||||
return this._android;
|
||||
}
|
||||
|
||||
set android(value: string) {
|
||||
this._android = value;
|
||||
}
|
||||
|
||||
get nativeImage(): any {
|
||||
return this._nativeImage;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,21 @@ import * as common from "./image-asset-common";
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
export class ImageAsset extends common.ImageAsset {
|
||||
private _android: string; //file name of the image
|
||||
|
||||
constructor(asset: string) {
|
||||
super();
|
||||
this.android = asset;
|
||||
}
|
||||
|
||||
get android(): string {
|
||||
return this._android;
|
||||
}
|
||||
|
||||
set android(value: string) {
|
||||
this._android = value;
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image, error) => void) {
|
||||
let bitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as common from "./image-asset-common";
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
export class ImageAsset extends common.ImageAsset {
|
||||
private _ios: PHAsset;
|
||||
|
||||
constructor(asset: PHAsset | UIImage) {
|
||||
super();
|
||||
if (asset instanceof UIImage) {
|
||||
@@ -13,6 +15,14 @@ export class ImageAsset extends common.ImageAsset {
|
||||
}
|
||||
}
|
||||
|
||||
get ios(): PHAsset {
|
||||
return this._ios;
|
||||
}
|
||||
|
||||
set ios(value: PHAsset) {
|
||||
this._ios = value;
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image, error) => void) {
|
||||
let srcWidth = this.nativeImage ? this.nativeImage.size.width : this.ios.pixelWidth;
|
||||
let srcHeight = this.nativeImage ? this.nativeImage.size.height : this.ios.pixelHeight;
|
||||
|
||||
21
tns-core-modules/module.d.ts
vendored
21
tns-core-modules/module.d.ts
vendored
@@ -1,11 +1,32 @@
|
||||
declare var global: NodeJS.Global;
|
||||
|
||||
interface ModuleResolver {
|
||||
/**
|
||||
* A function used to resolve the exports for a module.
|
||||
* @param uri The name of the module to be resolved.
|
||||
*/
|
||||
(uri: string): any;
|
||||
}
|
||||
|
||||
//Augment the NodeJS global type with our own extensions
|
||||
declare namespace NodeJS {
|
||||
interface Global {
|
||||
android?: any;
|
||||
require(id: string): any;
|
||||
registerModule(name: string, loader: ((name: string) => any)): void;
|
||||
/**
|
||||
* The NativeScript XML builder, style-scope, application modules use various resources such as:
|
||||
* app.css, page.xml files and modules during the application life-cycle.
|
||||
* The moduleResolvers can be used to provide additional mechanisms to locate such resources.
|
||||
* For example:
|
||||
* ```
|
||||
* global.moduleResolvers.unshift(uri => uri === "main-page" ? require("main-page") : null);
|
||||
* ```
|
||||
* More advanced scenarios will allow for specific bundlers to integrate their module resolving mechanisms.
|
||||
* When adding resolvers at the start of the array, avoid throwing and return null instead so subsequent resolvers may try to resolve the resource.
|
||||
* By default the only member of the array is global.require, as last resort - if it fails to find a module it will throw.
|
||||
*/
|
||||
readonly moduleResolvers: ModuleResolver[];
|
||||
loadModule(name: string): any;
|
||||
moduleExists(name: string): boolean;
|
||||
moduleMerge(sourceExports: any, destExports: any): void;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"files": [
|
||||
"**/*.d.ts",
|
||||
"**/*.js",
|
||||
"**/package.json",
|
||||
"!android17.d.ts",
|
||||
"!ios.d.ts",
|
||||
"!bin/",
|
||||
|
||||
@@ -85,7 +85,7 @@ export function isRunning(name: string): boolean {
|
||||
return !!(info && info.runCount);
|
||||
}
|
||||
|
||||
function countersProfileFunctionFactory<F extends Function>(fn: F, name: string): F {
|
||||
function countersProfileFunctionFactory<F extends Function>(fn: F, name: string, type: MemberType = MemberType.Instance): F {
|
||||
profileNames.push(name);
|
||||
return <any>function() {
|
||||
start(name);
|
||||
@@ -97,8 +97,8 @@ function countersProfileFunctionFactory<F extends Function>(fn: F, name: string)
|
||||
}
|
||||
}
|
||||
|
||||
function timelineProfileFunctionFactory<F extends Function>(fn: F, name: string): F {
|
||||
return <any>function() {
|
||||
function timelineProfileFunctionFactory<F extends Function>(fn: F, name: string, type: MemberType = MemberType.Instance): F {
|
||||
return type === MemberType.Instance ? <any>function() {
|
||||
const start = time();
|
||||
try {
|
||||
return fn.apply(this, arguments);
|
||||
@@ -106,10 +106,23 @@ function timelineProfileFunctionFactory<F extends Function>(fn: F, name: string)
|
||||
const end = time();
|
||||
console.log(`Timeline: Modules: ${name} ${this} (${start}ms. - ${end}ms.)`);
|
||||
}
|
||||
}
|
||||
} : function() {
|
||||
const start = time();
|
||||
try {
|
||||
return fn.apply(this, arguments);
|
||||
} finally {
|
||||
const end = time();
|
||||
console.log(`Timeline: Modules: ${name} (${start}ms. - ${end}ms.)`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let profileFunctionFactory: <F extends Function>(fn: F, name: string) => F;
|
||||
const enum MemberType {
|
||||
Static,
|
||||
Instance
|
||||
}
|
||||
|
||||
let profileFunctionFactory: <F extends Function>(fn: F, name: string, type?: MemberType) => F;
|
||||
export function enable(mode: InstrumentationMode = "counters") {
|
||||
profileFunctionFactory = mode && {
|
||||
counters: countersProfileFunctionFactory,
|
||||
@@ -154,7 +167,28 @@ const profileMethodUnnamed = (target, key, descriptor) => {
|
||||
let name = className + key;
|
||||
|
||||
//editing the descriptor/value parameter
|
||||
descriptor.value = profileFunctionFactory(originalMethod, name);
|
||||
descriptor.value = profileFunctionFactory(originalMethod, name, MemberType.Instance);
|
||||
|
||||
// return edited descriptor as opposed to overwriting the descriptor
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
const profileStaticMethodUnnamed = (ctor, key, descriptor) => {
|
||||
// save a reference to the original method this way we keep the values currently in the
|
||||
// descriptor and don't overwrite what another decorator might have done to the descriptor.
|
||||
if (descriptor === undefined) {
|
||||
descriptor = Object.getOwnPropertyDescriptor(ctor, key);
|
||||
}
|
||||
var originalMethod = descriptor.value;
|
||||
|
||||
let className = "";
|
||||
if (ctor && ctor.name) {
|
||||
className = ctor.name + ".";
|
||||
}
|
||||
let name = className + key;
|
||||
|
||||
//editing the descriptor/value parameter
|
||||
descriptor.value = profileFunctionFactory(originalMethod, name, MemberType.Static);
|
||||
|
||||
// return edited descriptor as opposed to overwriting the descriptor
|
||||
return descriptor;
|
||||
@@ -188,6 +222,11 @@ export function profile(nameFnOrTarget?: string | Function | Object, fnOrKey?: F
|
||||
return;
|
||||
}
|
||||
return profileMethodUnnamed(nameFnOrTarget, fnOrKey, descriptor);
|
||||
} else if (typeof nameFnOrTarget === "function" && (typeof fnOrKey === "string" || typeof fnOrKey === "symbol")) {
|
||||
if (!profileFunctionFactory) {
|
||||
return;
|
||||
}
|
||||
return profileStaticMethodUnnamed(nameFnOrTarget, fnOrKey, descriptor);
|
||||
} else if (typeof nameFnOrTarget === "string" && typeof fnOrKey === "function") {
|
||||
if (!profileFunctionFactory) {
|
||||
return fnOrKey;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { isString, isDefined } from "../../utils/types";
|
||||
import { ComponentModule, setPropertyValue, getComponentModule } from "./component-builder";
|
||||
import { platformNames, device } from "../../platform";
|
||||
import { resolveFileName } from "../../file-system/file-name-resolver";
|
||||
import { profile } from "tns-core-modules/profiling";
|
||||
import { profile } from "../../profiling";
|
||||
import * as traceModule from "../../trace";
|
||||
|
||||
const ios = platformNames.ios.toLowerCase();
|
||||
|
||||
@@ -7,7 +7,7 @@ import { isEventOrGesture } from "../../core/bindable";
|
||||
import { File, path, knownFolders } from "../../../file-system";
|
||||
import { getBindingOptions, bindingConstants } from "../binding-builder";
|
||||
import { resolveFileName } from "../../../file-system/file-name-resolver";
|
||||
import { profile } from "tns-core-modules/profiling";
|
||||
import { profile } from "../../../profiling";
|
||||
import * as debugModule from "../../../utils/debug";
|
||||
import * as platform from "../../../platform";
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface CssPropertyOptions<T extends Style, U> extends PropertyOptions<
|
||||
export interface ShorthandPropertyOptions<P> {
|
||||
readonly name: string,
|
||||
readonly cssName: string;
|
||||
readonly converter: (value: string | P) => [CssProperty<any, any>, any][],
|
||||
readonly converter: (value: string | P) => [CssProperty<any, any> | CssAnimationProperty<any, any>, any][],
|
||||
readonly getter: (this: Style) => string | P
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ export * from "../bindable";
|
||||
export * from "../properties";
|
||||
|
||||
import * as ssm from "../../styling/style-scope";
|
||||
|
||||
let styleScopeModule: typeof ssm;
|
||||
function ensureStyleScopeModule() {
|
||||
if (!styleScopeModule) {
|
||||
@@ -588,7 +589,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
// }
|
||||
|
||||
if (!nativeView) {
|
||||
nativeView = <android.view.View>this.createNativeView();
|
||||
nativeView = this.createNativeView();
|
||||
}
|
||||
|
||||
this._androidView = nativeView;
|
||||
@@ -597,7 +598,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
this._isPaddingRelative = nativeView.isPaddingRelative();
|
||||
}
|
||||
|
||||
let result: android.graphics.Rect = (<any>nativeView).defaultPaddings;
|
||||
let result: any /* android.graphics.Rect */ = (<any>nativeView).defaultPaddings;
|
||||
if (result === undefined) {
|
||||
result = org.nativescript.widgets.ViewHelper.getPadding(nativeView);
|
||||
(<any>nativeView).defaultPaddings = result;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { resolveFileName } from "../../file-system/file-name-resolver";
|
||||
import { knownFolders, path } from "../../file-system";
|
||||
import { parse, loadPage } from "../builder";
|
||||
import * as application from "../../application";
|
||||
import { profile } from "tns-core-modules/profiling";
|
||||
import { profile } from "../../profiling";
|
||||
|
||||
export { application };
|
||||
|
||||
|
||||
@@ -715,6 +715,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
||||
private notifyLaunch(intent: android.content.Intent, savedInstanceState: android.os.Bundle): View {
|
||||
const launchArgs: application.LaunchEventData = { eventName: application.launchEvent, object: application.android, android: intent, savedInstanceState };
|
||||
application.notify(launchArgs);
|
||||
application.notify(<application.LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: application.getCssFileName() });
|
||||
return launchArgs.root;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { FrameBase, View, application, layout, traceEnabled, traceWrite, traceCa
|
||||
import { _createIOSAnimatedTransitioning } from "./fragment.transitions";
|
||||
// HACK: Webpack. Use a fully-qualified import to allow resolve.extensions(.ios.js) to
|
||||
// kick in. `../utils` doesn't seem to trigger the webpack extensions mechanism.
|
||||
import * as uiUtils from "tns-core-modules/ui/utils";
|
||||
import * as uiUtils from "../../ui/utils";
|
||||
import * as utils from "../../utils/utils";
|
||||
|
||||
export * from "./frame-common";
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ios as iosApp } from "../../application";
|
||||
import { device } from "../../platform";
|
||||
// HACK: Webpack. Use a fully-qualified import to allow resolve.extensions(.ios.js) to
|
||||
// kick in. `../utils` doesn't seem to trigger the webpack extensions mechanism.
|
||||
import * as uiUtils from "tns-core-modules/ui/utils";
|
||||
import * as uiUtils from "../../ui/utils";
|
||||
import { profile } from "../../profiling";
|
||||
|
||||
export * from "./page-common";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { isDataURI, isFileOrResourcePath, layout, RESOURCE_PREFIX, FILE_PREFIX }
|
||||
import { parse } from "../../css-value";
|
||||
import { path, knownFolders } from "../../file-system";
|
||||
import * as application from "../../application";
|
||||
import { profile } from "tns-core-modules/profiling";
|
||||
import { profile } from "../../profiling";
|
||||
export * from "./background-common"
|
||||
|
||||
interface AndroidView {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* @module "ui/styling/css-selector-parser"
|
||||
* @private
|
||||
*/ /** */
|
||||
|
||||
//@private
|
||||
export interface SimpleSelector {
|
||||
pos: number;
|
||||
type: "" | "*" | "#" | "." | ":" | "[]";
|
||||
comb?: "+" | "~" | ">" | " ";
|
||||
}
|
||||
export interface SimpleIdentifierSelector extends SimpleSelector {
|
||||
ident: string;
|
||||
}
|
||||
export interface UniversalSelector extends SimpleSelector {
|
||||
type: "*";
|
||||
}
|
||||
export interface TypeSelector extends SimpleIdentifierSelector {
|
||||
type: "";
|
||||
}
|
||||
export interface ClassSelector extends SimpleIdentifierSelector {
|
||||
type: ".";
|
||||
}
|
||||
export interface IdSelector extends SimpleIdentifierSelector {
|
||||
type: "#";
|
||||
}
|
||||
export interface PseudoClassSelector extends SimpleIdentifierSelector {
|
||||
type: ":";
|
||||
}
|
||||
export interface AttributeSelector extends SimpleSelector {
|
||||
type: "[]";
|
||||
prop: string;
|
||||
test?: "=" | "^=" | "$=" | "*=" | "=" | "~=" | "|=";
|
||||
value?: string;
|
||||
}
|
||||
export function isUniversal(sel: SimpleSelector): sel is UniversalSelector;
|
||||
export function isType(sel: SimpleSelector): sel is TypeSelector;
|
||||
export function isClass(sel: SimpleSelector): sel is ClassSelector;
|
||||
export function isId(sel: SimpleSelector): sel is IdSelector;
|
||||
export function isPseudo(sel: SimpleSelector): sel is PseudoClassSelector;
|
||||
export function isAttribute(sel: SimpleSelector): sel is AttributeSelector;
|
||||
export function parse(selector: string): SimpleSelector[];
|
||||
@@ -1,125 +0,0 @@
|
||||
/// <reference path="./css-selector-parser.d.ts" />
|
||||
export interface SimpleSelector {
|
||||
pos: number;
|
||||
type: "" | "*" | "#" | "." | ":" | "[]";
|
||||
comb?: "+" | "~" | ">" | " ";
|
||||
}
|
||||
export interface SimpleIdentifierSelector extends SimpleSelector {
|
||||
ident: string;
|
||||
}
|
||||
export interface UniversalSelector extends SimpleSelector {
|
||||
type: "*";
|
||||
}
|
||||
export interface TypeSelector extends SimpleIdentifierSelector {
|
||||
type: "";
|
||||
}
|
||||
export interface ClassSelector extends SimpleIdentifierSelector {
|
||||
type: ".";
|
||||
}
|
||||
export interface IdSelector extends SimpleIdentifierSelector {
|
||||
type: "#";
|
||||
}
|
||||
export interface PseudoClassSelector extends SimpleIdentifierSelector {
|
||||
type: ":";
|
||||
}
|
||||
export interface AttributeSelector extends SimpleSelector {
|
||||
type: "[]";
|
||||
prop: string;
|
||||
test?: "=" | "^=" | "$=" | "*=" | "=" | "~=" | "|=";
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export function isUniversal(sel: SimpleSelector): sel is UniversalSelector {
|
||||
return sel.type === "*";
|
||||
}
|
||||
export function isType(sel: SimpleSelector): sel is TypeSelector {
|
||||
return sel.type === "";
|
||||
}
|
||||
export function isClass(sel: SimpleSelector): sel is ClassSelector {
|
||||
return sel.type === ".";
|
||||
}
|
||||
export function isId(sel: SimpleSelector): sel is IdSelector {
|
||||
return sel.type === "#";
|
||||
}
|
||||
export function isPseudo(sel: SimpleSelector): sel is PseudoClassSelector {
|
||||
return sel.type === ":";
|
||||
}
|
||||
export function isAttribute(sel: SimpleSelector): sel is AttributeSelector {
|
||||
return sel.type === "[]";
|
||||
}
|
||||
|
||||
var regex = /(\s*)(?:(\*)|(#|\.|:|\b)([_-\w][_-\w\d]*)|\[\s*([_-\w][_-\w\d]*)\s*(?:(=|\^=|\$=|\*=|\~=|\|=)\s*(?:([_-\w][_-\w\d]*)|"((?:[^\\"]|\\(?:"|n|r|f|\\|0-9a-f))*)"|'((?:[^\\']|\\(?:'|n|r|f|\\|0-9a-f))*)')\s*)?\])(?:\s*(\+|~|>|\s))?/g;
|
||||
// no lead ws univ type pref and ident [ prop = ident -or- "string escapes \" \00aaff" -or- 'string escapes \' urf-8: \00aaff' ] combinator
|
||||
|
||||
export function parse(selector: string): SimpleSelector[] {
|
||||
let selectors: any[] = [];
|
||||
|
||||
var result: RegExpExecArray;
|
||||
var lastIndex = regex.lastIndex = 0;
|
||||
while (result = regex.exec(selector)) {
|
||||
let pos = result.index;
|
||||
if (lastIndex !== pos) {
|
||||
throw new Error(`Unexpected characters at index, near: ${lastIndex}: ${result.input.substr(lastIndex, 32)}`);
|
||||
} else if (!result[0] || result[0].length === 0) {
|
||||
throw new Error(`Last selector match got zero character result at index ${lastIndex}, near: ${result.input.substr(lastIndex, 32)}`);
|
||||
}
|
||||
pos += getLeadingWhiteSpace(result).length;
|
||||
lastIndex = regex.lastIndex;
|
||||
|
||||
var type = getType(result);
|
||||
let selector: SimpleSelector | SimpleIdentifierSelector | AttributeSelector;
|
||||
switch (type) {
|
||||
case "*":
|
||||
selector = { pos, type };
|
||||
break;
|
||||
case "#":
|
||||
case ".":
|
||||
case ":":
|
||||
case "":
|
||||
let ident = getIdentifier(result);
|
||||
selector = { pos, type, ident };
|
||||
break;
|
||||
case "[]":
|
||||
let prop = getProperty(result);
|
||||
let test = getPropertyTest(result);
|
||||
// TODO: Unescape escape sequences. Unescape UTF-8 characters.
|
||||
let value = getPropertyValue(result);
|
||||
selector = test ? { pos, type, prop, test, value } : { pos, type, prop };
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unhandled type.");
|
||||
}
|
||||
|
||||
let comb = getCombinator(result);
|
||||
if (comb) {
|
||||
selector.comb = comb;
|
||||
}
|
||||
selectors.push(selector);
|
||||
}
|
||||
|
||||
if (selectors.length > 0) {
|
||||
delete selectors[selectors.length - 1].comb;
|
||||
}
|
||||
return selectors;
|
||||
}
|
||||
function getLeadingWhiteSpace(result: RegExpExecArray): string {
|
||||
return result[1] || "";
|
||||
}
|
||||
function getType(result: RegExpExecArray): "" | "*" | "." | "#" | ":" | "[]" {
|
||||
return <"[]">(result[5] && "[]") || <"*">result[2] || <"" | "." | "#" | ":">result[3];
|
||||
}
|
||||
function getIdentifier(result: RegExpExecArray): string {
|
||||
return result[4];
|
||||
}
|
||||
function getProperty(result: RegExpExecArray): string {
|
||||
return result[5];
|
||||
}
|
||||
function getPropertyTest(result: RegExpExecArray): string {
|
||||
return result[6] || undefined;
|
||||
}
|
||||
function getPropertyValue(result: RegExpExecArray): string {
|
||||
return result[7] || result[8] || result[9];
|
||||
}
|
||||
function getCombinator(result: RegExpExecArray): "+" | "~" | ">" | " " {
|
||||
return <("+" | "~" | ">" | " ")>result[result.length - 1] || undefined;
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Node, Declaration, Changes, ChangeMap } from ".";
|
||||
import { isNullOrUndefined } from "../../../utils/types";
|
||||
import { escapeRegexSymbols } from "../../../utils/utils";
|
||||
import { escapeRegexSymbols } from "../../../utils/utils-common";
|
||||
|
||||
import * as cssParser from "../../../css";
|
||||
import * as selectorParser from "../css-selector-parser";
|
||||
import * as parser from "../../../css/parser";
|
||||
|
||||
const enum Specificity {
|
||||
Inline = 0x01000000,
|
||||
@@ -60,7 +60,7 @@ function SelectorProperties(specificity: Specificity, rarity: Rarity, dynamic: b
|
||||
return cls => {
|
||||
cls.prototype.specificity = specificity;
|
||||
cls.prototype.rarity = rarity;
|
||||
cls.prototype.combinator = "";
|
||||
cls.prototype.combinator = undefined;
|
||||
cls.prototype.dynamic = dynamic;
|
||||
return cls;
|
||||
}
|
||||
@@ -408,61 +408,55 @@ function createDeclaration(decl: cssParser.Declaration): any {
|
||||
return { property: decl.property.toLowerCase(), value: decl.value };
|
||||
}
|
||||
|
||||
export function createSelector(sel: string): SimpleSelector | SimpleSelectorSequence | Selector {
|
||||
try {
|
||||
let ast = selectorParser.parse(sel);
|
||||
if (ast.length === 0) {
|
||||
return new InvalidSelector(new Error("Empty selector"));
|
||||
}
|
||||
|
||||
let selectors = ast.map(createSimpleSelector);
|
||||
let sequences: (SimpleSelector | SimpleSelectorSequence)[] = [];
|
||||
// Join simple selectors into sequences, set combinators
|
||||
for (let seqStart = 0, seqEnd = 0, last = selectors.length - 1; seqEnd <= last; seqEnd++) {
|
||||
let sel = selectors[seqEnd];
|
||||
let astComb = ast[seqEnd].comb;
|
||||
if (astComb || seqEnd === last) {
|
||||
if (seqStart === seqEnd) {
|
||||
// This is a sequnce with single SimpleSelector, so we will not combine it into SimpleSelectorSequence.
|
||||
sel.combinator = astComb;
|
||||
sequences.push(sel);
|
||||
} else {
|
||||
let sequence = new SimpleSelectorSequence(selectors.slice(seqStart, seqEnd + 1));
|
||||
sequence.combinator = astComb;
|
||||
sequences.push(sequence);
|
||||
}
|
||||
seqStart = seqEnd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sequences.length === 1) {
|
||||
// This is a selector with a single SinmpleSelectorSequence so we will not combine it into Selector.
|
||||
return sequences[0];
|
||||
} else {
|
||||
return new Selector(sequences);
|
||||
}
|
||||
} catch(e) {
|
||||
return new InvalidSelector(e);
|
||||
function createSimpleSelectorFromAst(ast: parser.SimpleSelector): SimpleSelector {
|
||||
switch(ast.type) {
|
||||
case "*": return new UniversalSelector();
|
||||
case "#": return new IdSelector(ast.identifier);
|
||||
case "": return new TypeSelector(ast.identifier.replace(/-/, '').toLowerCase());
|
||||
case ".": return new ClassSelector(ast.identifier);
|
||||
case ":": return new PseudoClassSelector(ast.identifier);
|
||||
case "[]": return ast.test ? new AttributeSelector(ast.property, ast.test, ast.value) : new AttributeSelector(ast.property);
|
||||
}
|
||||
}
|
||||
|
||||
function createSimpleSelector(sel: selectorParser.SimpleSelector): SimpleSelector {
|
||||
if (selectorParser.isUniversal(sel)) {
|
||||
return new UniversalSelector();
|
||||
} else if (selectorParser.isId(sel)) {
|
||||
return new IdSelector(sel.ident);
|
||||
} else if (selectorParser.isType(sel)) {
|
||||
return new TypeSelector(sel.ident.replace(/-/, '').toLowerCase());
|
||||
} else if (selectorParser.isClass(sel)) {
|
||||
return new ClassSelector(sel.ident);
|
||||
} else if (selectorParser.isPseudo(sel)) {
|
||||
return new PseudoClassSelector(sel.ident);
|
||||
} else if (selectorParser.isAttribute(sel)) {
|
||||
if (sel.test) {
|
||||
return new AttributeSelector(sel.prop, sel.test, sel.value);
|
||||
} else {
|
||||
return new AttributeSelector(sel.prop)
|
||||
function createSimpleSelectorSequenceFromAst(ast: parser.SimpleSelectorSequence): SimpleSelectorSequence | SimpleSelector {
|
||||
if (ast.length === 0) {
|
||||
return new InvalidSelector(new Error("Empty simple selector sequence."));
|
||||
} else if (ast.length === 1) {
|
||||
return createSimpleSelectorFromAst(ast[0]);
|
||||
} else {
|
||||
return new SimpleSelectorSequence(ast.map(createSimpleSelectorFromAst));
|
||||
}
|
||||
}
|
||||
|
||||
function createSelectorFromAst(ast: parser.Selector): SimpleSelector | SimpleSelectorSequence | Selector {
|
||||
if (ast.length === 0) {
|
||||
return new InvalidSelector(new Error("Empty selector."));
|
||||
} else if (ast.length <= 2) {
|
||||
return createSimpleSelectorSequenceFromAst(ast[0]);
|
||||
} else {
|
||||
let simpleSelectorSequences = [];
|
||||
for (var i = 0; i < ast.length; i += 2) {
|
||||
const simpleSelectorSequence = createSimpleSelectorSequenceFromAst(<parser.SimpleSelectorSequence>ast[i]);
|
||||
const combinator = <parser.Combinator>ast[i + 1];
|
||||
if (combinator) {
|
||||
simpleSelectorSequence.combinator = combinator;
|
||||
}
|
||||
simpleSelectorSequences.push(simpleSelectorSequence);
|
||||
}
|
||||
return new Selector(simpleSelectorSequences);
|
||||
}
|
||||
}
|
||||
|
||||
export function createSelector(sel: string): SimpleSelector | SimpleSelectorSequence | Selector {
|
||||
try {
|
||||
let parsedSelector = parser.parseSelector(sel);
|
||||
if (!parsedSelector) {
|
||||
return new InvalidSelector(new Error("Empty selector"));
|
||||
}
|
||||
return createSelectorFromAst(parsedSelector.value);
|
||||
} catch(e) {
|
||||
return new InvalidSelector(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Font as FontDefinition, ParsedFont } from "./font";
|
||||
import { makeValidator, makeParser } from "../core/properties";
|
||||
|
||||
export abstract class FontBase implements FontDefinition {
|
||||
export abstract class Font implements FontDefinition {
|
||||
public static default = undefined;
|
||||
|
||||
get isItalic(): boolean {
|
||||
@@ -23,14 +23,14 @@ export abstract class FontBase implements FontDefinition {
|
||||
public readonly fontWeight: FontWeight) {
|
||||
}
|
||||
|
||||
public abstract getAndroidTypeface(): android.graphics.Typeface;
|
||||
public abstract getUIFont(defaultFont: UIFont): UIFont;
|
||||
public abstract withFontFamily(family: string): FontBase;
|
||||
public abstract withFontStyle(style: string): FontBase;
|
||||
public abstract withFontWeight(weight: string): FontBase;
|
||||
public abstract withFontSize(size: number): FontBase;
|
||||
public abstract getAndroidTypeface(): any /* android.graphics.Typeface */;
|
||||
public abstract getUIFont(defaultFont: any /* UIFont */): any /* UIFont */;
|
||||
public abstract withFontFamily(family: string): Font;
|
||||
public abstract withFontStyle(style: string): Font;
|
||||
public abstract withFontWeight(weight: string): Font;
|
||||
public abstract withFontSize(size: number): Font;
|
||||
|
||||
public static equals(value1: FontBase, value2: FontBase): boolean {
|
||||
public static equals(value1: Font, value2: Font): boolean {
|
||||
// both values are falsy
|
||||
if (!value1 && !value2) {
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FontBase, parseFontFamily, genericFontFamilies, FontWeight } from "./font-common";
|
||||
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontWeight } from "./font-common";
|
||||
import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceMessageType } from "../../trace";
|
||||
import * as application from "../../application";
|
||||
import * as fs from "../../file-system";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FontBase, parseFontFamily, genericFontFamilies, FontStyle, FontWeight } from "./font-common";
|
||||
import { Font as FontBase, parseFontFamily, genericFontFamilies, FontStyle, FontWeight } from "./font-common";
|
||||
import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceMessageType } from "../../trace";
|
||||
import { device } from "../../platform"
|
||||
import * as fs from "../../file-system";
|
||||
|
||||
@@ -8,9 +8,9 @@ import {
|
||||
import { dip, px, percent } from "../core/view";
|
||||
|
||||
import { Color } from "../../color";
|
||||
import { Font, parseFont, FontStyle, FontWeight } from "./font";
|
||||
import { Font, parseFont, FontStyle, FontWeight } from "../../ui/styling/font";
|
||||
import { layout } from "../../utils/utils";
|
||||
import { Background } from "./background";
|
||||
import { Background } from "../../ui/styling/background";
|
||||
import { isIOS } from "../../platform";
|
||||
|
||||
import { Style } from "./style";
|
||||
|
||||
@@ -8,6 +8,11 @@ import {
|
||||
parse as parseCss,
|
||||
Node as CssNode,
|
||||
} from "../../css";
|
||||
import {
|
||||
CSS3Parser,
|
||||
CSSNativeScript
|
||||
} from "../../css/parser";
|
||||
|
||||
import {
|
||||
RuleSet,
|
||||
SelectorsMap,
|
||||
@@ -42,6 +47,16 @@ function ensureCssAnimationParserModule() {
|
||||
}
|
||||
}
|
||||
|
||||
let parser: "rework" | "nativescript" = "rework";
|
||||
try {
|
||||
const appConfig = require("~/package.json");
|
||||
if (appConfig && appConfig.cssParser === "nativescript") {
|
||||
parser = "nativescript";
|
||||
}
|
||||
} catch(e) {
|
||||
//
|
||||
}
|
||||
|
||||
export function mergeCssSelectors(): void {
|
||||
applicationCssSelectors = applicationSelectors.slice();
|
||||
applicationCssSelectors.push.apply(applicationCssSelectors, applicationAdditionalSelectors);
|
||||
@@ -58,25 +73,49 @@ const pattern: RegExp = /('|")(.*?)\1/;
|
||||
|
||||
class CSSSource {
|
||||
private _selectors: RuleSet[] = [];
|
||||
private _ast: SyntaxTree;
|
||||
|
||||
private static cssFilesCache: { [path: string]: CSSSource } = {};
|
||||
|
||||
private constructor(private _url: string, private _file: string, private _keyframes: KeyframesMap, private _source?: string) {
|
||||
if (this._file && !this._source) {
|
||||
this.load();
|
||||
}
|
||||
private constructor(private _ast: SyntaxTree, private _url: string, private _file: string, private _keyframes: KeyframesMap, private _source: string) {
|
||||
this.parse();
|
||||
}
|
||||
|
||||
public static fromURI(uri: string, keyframes: KeyframesMap): CSSSource {
|
||||
try {
|
||||
const cssOrAst = global.loadModule(uri);
|
||||
if (cssOrAst) {
|
||||
if (typeof cssOrAst === "string") {
|
||||
return CSSSource.fromSource(cssOrAst, keyframes, uri);
|
||||
} else if (typeof cssOrAst === "object" && cssOrAst.type === "stylesheet" && cssOrAst.stylesheet && cssOrAst.stylesheet.rules) {
|
||||
return CSSSource.fromAST(cssOrAst, keyframes, uri);
|
||||
} else {
|
||||
// Probably a webpack css-loader exported object.
|
||||
return CSSSource.fromSource(cssOrAst.toString(), keyframes, uri);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
//
|
||||
}
|
||||
return CSSSource.fromFile(uri, keyframes);
|
||||
}
|
||||
|
||||
public static fromFile(url: string, keyframes: KeyframesMap): CSSSource {
|
||||
const file = CSSSource.resolveCSSPathFromURL(url);
|
||||
return new CSSSource(undefined, url, file, keyframes, undefined);
|
||||
}
|
||||
|
||||
@profile
|
||||
public static resolveCSSPathFromURL(url: string): string {
|
||||
const app = knownFolders.currentApp().path;
|
||||
const file = resolveFileNameFromUrl(url, app, File.exists);
|
||||
return new CSSSource(url, file, keyframes, undefined);
|
||||
return file;
|
||||
}
|
||||
|
||||
public static fromSource(source: string, keyframes: KeyframesMap, url?: string): CSSSource {
|
||||
return new CSSSource(url, undefined, keyframes, source);
|
||||
return new CSSSource(undefined, url, undefined, keyframes, source);
|
||||
}
|
||||
|
||||
public static fromAST(ast: SyntaxTree, keyframes: KeyframesMap, url?: string): CSSSource {
|
||||
return new CSSSource(ast, url, undefined, keyframes, undefined);
|
||||
}
|
||||
|
||||
get selectors(): RuleSet[] { return this._selectors; }
|
||||
@@ -90,24 +129,53 @@ class CSSSource {
|
||||
|
||||
@profile
|
||||
private parse(): void {
|
||||
if (this._source) {
|
||||
try {
|
||||
this._ast = this._source ? parseCss(this._source, { source: this._file }) : null;
|
||||
// TODO: Don't merge arrays, instead chain the css files.
|
||||
if (this._ast) {
|
||||
this._selectors = [
|
||||
...this.createSelectorsFromImports(),
|
||||
...this.createSelectorsFromSyntaxTree()
|
||||
];
|
||||
try {
|
||||
if (!this._ast) {
|
||||
if (!this._source && this._file) {
|
||||
this.load();
|
||||
}
|
||||
if (this._source) {
|
||||
this.parseCSSAst();
|
||||
}
|
||||
} catch (e) {
|
||||
traceWrite("Css styling failed: " + e, traceCategories.Error, traceMessageType.error);
|
||||
}
|
||||
} else {
|
||||
if (this._ast) {
|
||||
this.createSelectors();
|
||||
} else {
|
||||
this._selectors = [];
|
||||
}
|
||||
} catch (e) {
|
||||
traceWrite("Css styling failed: " + e, traceCategories.Error, traceMessageType.error);
|
||||
this._selectors = [];
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
private parseCSSAst() {
|
||||
if (this._source) {
|
||||
switch(parser) {
|
||||
case "nativescript":
|
||||
const cssparser = new CSS3Parser(this._source);
|
||||
const stylesheet = cssparser.parseAStylesheet();
|
||||
const cssNS = new CSSNativeScript();
|
||||
this._ast = cssNS.parseStylesheet(stylesheet);
|
||||
return;
|
||||
case "rework":
|
||||
this._ast = parseCss(this._source, { source: this._file });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
private createSelectors() {
|
||||
if (this._ast) {
|
||||
this._selectors = [
|
||||
...this.createSelectorsFromImports(),
|
||||
...this.createSelectorsFromSyntaxTree()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private createSelectorsFromImports(): RuleSet[] {
|
||||
let selectors: RuleSet[] = [];
|
||||
const imports = this._ast["stylesheet"]["rules"].filter(r => r.type === "import");
|
||||
@@ -118,7 +186,7 @@ class CSSSource {
|
||||
const url = match && match[2];
|
||||
|
||||
if (url !== null && url !== undefined) {
|
||||
const cssFile = CSSSource.fromFile(url, this._keyframes);
|
||||
const cssFile = CSSSource.fromURI(url, this._keyframes);
|
||||
selectors = selectors.concat(cssFile.selectors);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +237,7 @@ const loadCss = profile(`"style-scope".loadCss`, (cssFile: string) => {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = CSSSource.fromFile(cssFile, applicationKeyframes).selectors;
|
||||
const result = CSSSource.fromURI(cssFile, applicationKeyframes).selectors;
|
||||
if (result.length > 0) {
|
||||
applicationSelectors = result;
|
||||
mergeCssSelectors();
|
||||
@@ -179,15 +247,15 @@ const loadCss = profile(`"style-scope".loadCss`, (cssFile: string) => {
|
||||
application.on("cssChanged", onCssChanged);
|
||||
application.on("livesync", onLiveSync);
|
||||
|
||||
export const loadCssOnLaunch = profile('"style-scope".loadCssOnLaunch', () => {
|
||||
loadCss(application.getCssFileName());
|
||||
application.off("launch", loadCssOnLaunch);
|
||||
export const loadAppCSS = profile('"style-scope".loadAppCSS', (args: application.LoadAppCSSEventData) => {
|
||||
loadCss(args.cssFile);
|
||||
application.off("loadAppCss", loadAppCSS);
|
||||
});
|
||||
|
||||
if (application.hasLaunched()) {
|
||||
loadCssOnLaunch();
|
||||
loadAppCSS({ eventName: "loadAppCss", object: <any>application, cssFile: application.getCssFileName() });
|
||||
} else {
|
||||
application.on("launch", loadCssOnLaunch);
|
||||
application.on("loadAppCss", loadAppCSS);
|
||||
}
|
||||
|
||||
export class CssState {
|
||||
|
||||
1
tns-core-modules/ui/styling/style/style.d.ts
vendored
1
tns-core-modules/ui/styling/style/style.d.ts
vendored
@@ -62,6 +62,7 @@ export class Style extends Observable {
|
||||
public tintColor: Color;
|
||||
public placeholderColor: Color;
|
||||
|
||||
public background: string | Color;
|
||||
public backgroundColor: Color;
|
||||
public backgroundImage: string;
|
||||
public backgroundRepeat: BackgroundRepeat;
|
||||
|
||||
@@ -35,6 +35,7 @@ export class Style extends Observable implements StyleDefinition {
|
||||
public tintColor: Color;
|
||||
public placeholderColor: Color;
|
||||
|
||||
public background: string | Color;
|
||||
public backgroundColor: Color;
|
||||
public backgroundImage: string;
|
||||
public backgroundRepeat: BackgroundRepeat;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Source } from "./debug-common";
|
||||
export * from "./debug-common";
|
||||
|
||||
export class ScopeError extends Error {
|
||||
constructor(inner: Error, message?: string) {
|
||||
let formattedMessage;
|
||||
if (message && inner.message) {
|
||||
formattedMessage = message + "\n > " + inner.message.replace("\n", "\n ");
|
||||
} else {
|
||||
formattedMessage = message || inner.message || undefined;
|
||||
}
|
||||
super(formattedMessage);
|
||||
this.stack = "Error: " + this.message + "\n" + inner.stack.substr(inner.stack.indexOf("\n") + 1);
|
||||
this.message = formattedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
export class SourceError extends ScopeError {
|
||||
constructor(child: Error, source: Source, message?: string) {
|
||||
super(child, message ? message + " @" + source + "" : source + "");
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Source } from "./debug-common";
|
||||
export * from "./debug-common";
|
||||
|
||||
export class ScopeError extends Error {
|
||||
constructor(inner: Error, message?: string) {
|
||||
let formattedMessage;
|
||||
if (message && inner.message) {
|
||||
formattedMessage = message + "\n > " + inner.message.replace("\n", "\n ");
|
||||
} else {
|
||||
formattedMessage = message || inner.message || undefined;
|
||||
}
|
||||
super(formattedMessage);
|
||||
this.stack = inner.stack;
|
||||
this.message = formattedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
export class SourceError extends ScopeError {
|
||||
constructor(child: Error, source: Source, message?: string) {
|
||||
super(child, message ? message + " @" + source + "" : source + "");
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { knownFolders } from "../file-system"
|
||||
import { isAndroid } from "../platform"
|
||||
|
||||
export var debug = true;
|
||||
|
||||
@@ -45,3 +46,23 @@ export class Source {
|
||||
object[Source._source] = src;
|
||||
}
|
||||
}
|
||||
|
||||
export class ScopeError extends Error {
|
||||
constructor(inner: Error, message?: string) {
|
||||
let formattedMessage;
|
||||
if (message && inner.message) {
|
||||
formattedMessage = message + "\n > " + inner.message.replace("\n", "\n ");
|
||||
} else {
|
||||
formattedMessage = message || inner.message || undefined;
|
||||
}
|
||||
super(formattedMessage);
|
||||
this.stack = isAndroid ? "Error: " + this.message + "\n" + inner.stack.substr(inner.stack.indexOf("\n") + 1) : inner.stack;
|
||||
this.message = formattedMessage;
|
||||
}
|
||||
}
|
||||
|
||||
export class SourceError extends ScopeError {
|
||||
constructor(child: Error, source: Source, message?: string) {
|
||||
super(child, message ? message + " @" + source + "" : source + "");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user