project initialized
This commit is contained in:
commit
e1d820434e
13
.editorconfig
Normal file
13
.editorconfig
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
47
.gitignore
vendored
Normal file
47
.gitignore
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/docs
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"msjsdiag.debugger-for-chrome",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||||
|
"VisualStudioExptTeam.vscodeintellicode"
|
||||||
|
]
|
||||||
|
}
|
7
.vscode/launch.json
vendored
Normal file
7
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": []
|
||||||
|
}
|
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"editor.autoClosingBrackets": "languageDefined",
|
||||||
|
"editor.trimAutoWhitespace": true,
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.trimFinalNewlines": true,
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/dist": true
|
||||||
|
},
|
||||||
|
"debug.node.autoAttach": "on"
|
||||||
|
}
|
15
.vscode/tasks.json
vendored
Normal file
15
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "build:main:dev",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
6003
package-lock.json
generated
Normal file
6003
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
43
package.json
Normal file
43
package.json
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"name": "ucap-electron",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"clean:all": "rimraf dist/*",
|
||||||
|
"build:all": "npm-run-all -s build:core build:common build:notify-window build:updater-window",
|
||||||
|
"build:core": "node ./scripts/build.js core",
|
||||||
|
"build:common": "node ./scripts/build.js common",
|
||||||
|
"build:notify-window": "node ./scripts/build.js notify-window",
|
||||||
|
"build:updater-window": "node ./scripts/build.js updater-window",
|
||||||
|
"publish:all": "npm-run-all -s publish:core publish:notify-window publish:updater-window",
|
||||||
|
"publish:core": "cd ./dist/core && npm publish",
|
||||||
|
"publish:common": "cd ./dist/common && npm publish",
|
||||||
|
"publish:notify-window": "cd ./dist/core && npm publish",
|
||||||
|
"publish:updater-window": "cd ./dist/core && npm publish"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tsed/core": "^5.44.11",
|
||||||
|
"@tsed/di": "^5.44.11",
|
||||||
|
"@types/fs-extra": "^8.1.0",
|
||||||
|
"@types/node": "^12.11.1",
|
||||||
|
"@ucap/electron-core": "file:dist/core/ucap-electron-core-0.0.1.tgz",
|
||||||
|
"concurrently": "^5.1.0",
|
||||||
|
"electron": "^8.1.1",
|
||||||
|
"electron-log": "^4.1.0",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"rxjs": "^6.5.4",
|
||||||
|
"terser-webpack-plugin": "^2.3.5",
|
||||||
|
"ts-loader": "^6.2.1",
|
||||||
|
"ts-node": "^8.6.2",
|
||||||
|
"tslib": "^1.11.1",
|
||||||
|
"tslint": "^6.1.0",
|
||||||
|
"typedoc": "^0.16.11",
|
||||||
|
"typescript": "^3.8.3",
|
||||||
|
"webpack": "^4.42.0",
|
||||||
|
"webpack-merge": "^4.2.2",
|
||||||
|
"webpack-node-externals": "^1.7.2"
|
||||||
|
}
|
||||||
|
}
|
15
projects/common/package.json
Normal file
15
projects/common/package.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "@ucap/electron-common",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
|
||||||
|
},
|
||||||
|
"scripts": {},
|
||||||
|
"dependencies": {
|
||||||
|
"@tsed/core": "^5.44.11",
|
||||||
|
"@tsed/di": "^5.44.11",
|
||||||
|
"electron": "^8.0.0",
|
||||||
|
"rxjs": "^6.5.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
91
projects/common/src/lib/app/app.ts
Normal file
91
projects/common/src/lib/app/app.ts
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import { Type, constructorOf } from '@tsed/core';
|
||||||
|
import {
|
||||||
|
GlobalProviders,
|
||||||
|
InjectorService,
|
||||||
|
ProviderScope,
|
||||||
|
registerProvider
|
||||||
|
} from '@tsed/di';
|
||||||
|
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
|
||||||
|
import { AppOptions } from './decorators/app-settings';
|
||||||
|
import { AppSettingsService } from './services/app-settings.service';
|
||||||
|
import { ElectronApp } from './decorators/electron-app';
|
||||||
|
|
||||||
|
export abstract class App {
|
||||||
|
readonly injector: InjectorService;
|
||||||
|
private startedAt = new Date();
|
||||||
|
|
||||||
|
constructor(settings: Partial<AppOptions> = {}) {
|
||||||
|
// create injector with initial configuration
|
||||||
|
this.injector = this.createInjector(this.getConfiguration(this, settings));
|
||||||
|
|
||||||
|
this.createElectronApp(this.injector);
|
||||||
|
}
|
||||||
|
|
||||||
|
get settings(): AppSettingsService {
|
||||||
|
return this.injector.settings as AppSettingsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
get electronApp(): ElectronApp {
|
||||||
|
return this.injector.get<ElectronApp>(ElectronApp)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async bootstrap(
|
||||||
|
module: Type<App>,
|
||||||
|
settings: Partial<AppOptions> = {}
|
||||||
|
): Promise<App> {
|
||||||
|
const app = new module(settings);
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(): Promise<any> {
|
||||||
|
try {
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createInjector(settings: Partial<AppOptions> = {}) {
|
||||||
|
const injector = new InjectorService();
|
||||||
|
injector.settings = this.createSettingsService(injector);
|
||||||
|
// injector.logger = $log;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
injector.settings.set(settings);
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (injector.settings.env === 'test') {
|
||||||
|
injector.logger.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSettingsService(injector: InjectorService): AppSettingsService {
|
||||||
|
const provider = GlobalProviders.get(AppSettingsService)!.clone();
|
||||||
|
|
||||||
|
provider.instance = injector.invoke<AppSettingsService>(provider.useClass);
|
||||||
|
injector.addProvider(AppSettingsService, provider);
|
||||||
|
|
||||||
|
return provider.instance as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getConfiguration(module: any, configuration: any = {}) {
|
||||||
|
const provider = GlobalProviders.get(constructorOf(module))!;
|
||||||
|
|
||||||
|
return { ...provider.configuration, ...configuration };
|
||||||
|
}
|
||||||
|
|
||||||
|
private createElectronApp(injector: InjectorService): void {
|
||||||
|
injector.forkProvider(ElectronApp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerProvider({
|
||||||
|
provide: ElectronApp,
|
||||||
|
scope: ProviderScope.SINGLETON,
|
||||||
|
global: true,
|
||||||
|
useValue: Electron.app
|
||||||
|
});
|
10
projects/common/src/lib/app/decorators/app-settings.ts
Normal file
10
projects/common/src/lib/app/decorators/app-settings.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Type } from '@tsed/core';
|
||||||
|
import { IModuleOptions, Module } from '@tsed/di';
|
||||||
|
|
||||||
|
export interface AppOptions extends IModuleOptions {
|
||||||
|
bootstrap: Type<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AppSettings(settings: Partial<AppOptions> = {}): any {
|
||||||
|
return Module({ ...settings, root: true });
|
||||||
|
}
|
14
projects/common/src/lib/app/decorators/electron-app.ts
Normal file
14
projects/common/src/lib/app/decorators/electron-app.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Type } from '@tsed/core';
|
||||||
|
import { Inject } from '@tsed/di';
|
||||||
|
import * as Electron from 'electron';
|
||||||
|
|
||||||
|
export type ElectronApp = Electron.App;
|
||||||
|
|
||||||
|
export function ElectronApp(
|
||||||
|
target: Type<any>,
|
||||||
|
targetKey: string,
|
||||||
|
// tslint:disable-next-line: ban-types
|
||||||
|
descriptor: TypedPropertyDescriptor<Function> | number
|
||||||
|
) {
|
||||||
|
return Inject(ElectronApp)(target, targetKey, descriptor);
|
||||||
|
}
|
16
projects/common/src/lib/app/services/app-settings.service.ts
Normal file
16
projects/common/src/lib/app/services/app-settings.service.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import {
|
||||||
|
DIConfiguration,
|
||||||
|
Injectable,
|
||||||
|
ProviderScope,
|
||||||
|
ProviderType
|
||||||
|
} from '@tsed/di';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
scope: ProviderScope.SINGLETON,
|
||||||
|
global: true
|
||||||
|
})
|
||||||
|
export class AppSettingsService extends DIConfiguration {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
10
projects/common/src/public-api.ts
Normal file
10
projects/common/src/public-api.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of common
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/app/decorators/app-settings';
|
||||||
|
export * from './lib/app/decorators/electron-app';
|
||||||
|
|
||||||
|
export * from './lib/app/services/app-settings.service';
|
||||||
|
|
||||||
|
export * from './lib/app/app';
|
12
projects/common/tsconfig.lib.json
Normal file
12
projects/common/tsconfig.lib.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"declaration": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": ["dom", "es2018"]
|
||||||
|
},
|
||||||
|
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
||||||
|
}
|
3
projects/common/tsconfig.lib.prod.json
Normal file
3
projects/common/tsconfig.lib.prod.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.lib.json"
|
||||||
|
}
|
9
projects/common/tsconfig.spec.json
Normal file
9
projects/common/tsconfig.spec.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": ["jasmine", "node"]
|
||||||
|
},
|
||||||
|
"files": ["src/test.ts"],
|
||||||
|
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||||
|
}
|
3
projects/common/tslint.json
Normal file
3
projects/common/tslint.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tslint.json"
|
||||||
|
}
|
7
projects/common/ucap-package.json
Normal file
7
projects/common/ucap-package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"dest": "../../dist/common",
|
||||||
|
"docDest": "../../docs/common",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
10
projects/core/package.json
Normal file
10
projects/core/package.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"name": "@ucap/electron-core",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
|
||||||
|
},
|
||||||
|
"scripts": {},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
39
projects/core/src/lib/types/channel.type.ts
Normal file
39
projects/core/src/lib/types/channel.type.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
export enum AppChannel {
|
||||||
|
WillFinishLaunching = 'will-finish-launching',
|
||||||
|
Ready = 'ready',
|
||||||
|
WindowAllClosed = 'window-all-closed',
|
||||||
|
BeforeQuit = 'before-quit',
|
||||||
|
WillQuit = 'will-quit',
|
||||||
|
Quit = 'quit',
|
||||||
|
OpenFile = 'open-file',
|
||||||
|
OpenUrl = 'open-url',
|
||||||
|
Activate = 'activate',
|
||||||
|
ContinueActivity = 'continue-activity',
|
||||||
|
WillContinueActivity = 'will-continue-activity',
|
||||||
|
ContinueActivityError = 'continue-activity-error',
|
||||||
|
ActivityWasContinued = 'activity-was-continued',
|
||||||
|
SecondInstance = 'second-instance'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BrowserWindowChannel {
|
||||||
|
EnterFullScreen = 'enter-full-screen',
|
||||||
|
LeaveFullScreen = 'leave-full-screen',
|
||||||
|
Maximize = 'maximize',
|
||||||
|
Minimize = 'minimize',
|
||||||
|
Unmaximize = 'unmaximize',
|
||||||
|
Restore = 'restore',
|
||||||
|
Hide = 'hide',
|
||||||
|
Show = 'show',
|
||||||
|
Close = 'close',
|
||||||
|
Closed = 'closed',
|
||||||
|
ReadyToShow = 'ready-to-show',
|
||||||
|
Focus = 'focus',
|
||||||
|
Blur = 'blur'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WebContentsChannel {
|
||||||
|
DevtoolsOpened = 'devtools-opened',
|
||||||
|
DidStartLoading = 'did-start-loading',
|
||||||
|
DidFinishLoad = 'did-finish-load',
|
||||||
|
DidFailLoad = 'did-fail-load'
|
||||||
|
}
|
5
projects/core/src/public-api.ts
Normal file
5
projects/core/src/public-api.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of core
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/types/channel.type';
|
12
projects/core/tsconfig.lib.json
Normal file
12
projects/core/tsconfig.lib.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"declaration": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": ["dom", "es2018"]
|
||||||
|
},
|
||||||
|
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
||||||
|
}
|
3
projects/core/tsconfig.lib.prod.json
Normal file
3
projects/core/tsconfig.lib.prod.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.lib.json"
|
||||||
|
}
|
9
projects/core/tsconfig.spec.json
Normal file
9
projects/core/tsconfig.spec.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": ["jasmine", "node"]
|
||||||
|
},
|
||||||
|
"files": ["src/test.ts"],
|
||||||
|
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||||
|
}
|
3
projects/core/tslint.json
Normal file
3
projects/core/tslint.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tslint.json"
|
||||||
|
}
|
7
projects/core/ucap-package.json
Normal file
7
projects/core/ucap-package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"dest": "../../dist/core",
|
||||||
|
"docDest": "../../docs/core",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
16
projects/notify-window/package.json
Normal file
16
projects/notify-window/package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "@ucap/electron-notify-window",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
|
||||||
|
},
|
||||||
|
"scripts": {},
|
||||||
|
"dependencies": {
|
||||||
|
"@ucap/electron-core": "~0.0.1",
|
||||||
|
"electron": "^8.0.0",
|
||||||
|
"electron-log": "^4.1.0",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"rxjs": "^6.5.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
120
projects/notify-window/src/lib/models/notify-window-options.ts
Normal file
120
projects/notify-window/src/lib/models/notify-window-options.ts
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
import { BrowserWindowConstructorOptions } from 'electron';
|
||||||
|
|
||||||
|
export interface NotifyWindowOptions {
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
padding?: number;
|
||||||
|
borderRadius?: number;
|
||||||
|
displayTime?: number;
|
||||||
|
animationSteps?: number;
|
||||||
|
animationStepMs?: number;
|
||||||
|
animateInParallel?: boolean;
|
||||||
|
appIcon?: string;
|
||||||
|
pathToModule?: string;
|
||||||
|
logging?: boolean;
|
||||||
|
browserWindowPool?: {
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
};
|
||||||
|
defaultStyleContainer?: {
|
||||||
|
[attribute: string]: any;
|
||||||
|
};
|
||||||
|
defaultStyleAppIcon?: {
|
||||||
|
[attribute: string]: any;
|
||||||
|
};
|
||||||
|
defaultStyleImage?: {
|
||||||
|
[attribute: string]: any;
|
||||||
|
};
|
||||||
|
defaultStyleClose?: {
|
||||||
|
[attribute: string]: any;
|
||||||
|
};
|
||||||
|
defaultStyleText?: {
|
||||||
|
[attribute: string]: any;
|
||||||
|
};
|
||||||
|
defaultWindow?: BrowserWindowConstructorOptions;
|
||||||
|
templatePath?: string;
|
||||||
|
htmlTemplate?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DefaultNotifyWindowOptions: NotifyWindowOptions = {
|
||||||
|
width: 300,
|
||||||
|
height: 65,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 5,
|
||||||
|
displayTime: 5000,
|
||||||
|
animationSteps: 5,
|
||||||
|
animationStepMs: 20,
|
||||||
|
appIcon: null,
|
||||||
|
pathToModule: '',
|
||||||
|
logging: true,
|
||||||
|
browserWindowPool: {
|
||||||
|
min: 0,
|
||||||
|
max: 7
|
||||||
|
},
|
||||||
|
defaultStyleContainer: {
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
overflow: 'hidden',
|
||||||
|
padding: 8,
|
||||||
|
border: '1px solid #CCC',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: 12,
|
||||||
|
position: 'relative',
|
||||||
|
lineHeight: '15px'
|
||||||
|
},
|
||||||
|
defaultStyleAppIcon: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
float: 'left',
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
marginRight: 10
|
||||||
|
},
|
||||||
|
defaultStyleImage: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
float: 'right',
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
marginLeft: 10
|
||||||
|
},
|
||||||
|
defaultStyleClose: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 1,
|
||||||
|
right: 3,
|
||||||
|
fontSize: 11,
|
||||||
|
color: '#CCC'
|
||||||
|
},
|
||||||
|
defaultStyleText: {
|
||||||
|
margin: 0,
|
||||||
|
overflow: 'hidden',
|
||||||
|
cursor: 'default'
|
||||||
|
},
|
||||||
|
defaultWindow: {
|
||||||
|
alwaysOnTop: true,
|
||||||
|
skipTaskbar: true,
|
||||||
|
resizable: false,
|
||||||
|
show: false,
|
||||||
|
frame: false,
|
||||||
|
transparent: true,
|
||||||
|
acceptFirstMouse: true,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
|
webSecurity: false,
|
||||||
|
allowRunningInsecureContent: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
htmlTemplate:
|
||||||
|
'<html>\n' +
|
||||||
|
'<head></head>\n' +
|
||||||
|
'<body style="overflow: hidden; -webkit-user-select: none;">\n' +
|
||||||
|
'<div id="container">\n' +
|
||||||
|
' <img src="" id="appIcon" />\n' +
|
||||||
|
' <img src="" id="image" />\n' +
|
||||||
|
' <div id="text">\n' +
|
||||||
|
' <b id="title"></b>\n' +
|
||||||
|
' <p id="message"></p>\n' +
|
||||||
|
' </div>\n' +
|
||||||
|
' <div id="close">X</div>\n' +
|
||||||
|
'</div>\n' +
|
||||||
|
'</body>\n' +
|
||||||
|
'</html>'
|
||||||
|
};
|
20
projects/notify-window/src/lib/models/notify-window.ts
Normal file
20
projects/notify-window/src/lib/models/notify-window.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { NotifyWindowEventType } from '../types/event.type';
|
||||||
|
|
||||||
|
export interface NotifyWindowEvent {
|
||||||
|
type: NotifyWindowEventType;
|
||||||
|
id: number;
|
||||||
|
close?: (reason?: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotifyWindow {
|
||||||
|
id?: number;
|
||||||
|
displayTime?: number;
|
||||||
|
title?: string;
|
||||||
|
text?: string;
|
||||||
|
image?: string;
|
||||||
|
url?: string;
|
||||||
|
sound?: string;
|
||||||
|
onClick?: (e: NotifyWindowEvent) => void;
|
||||||
|
onShow?: (e: NotifyWindowEvent) => void;
|
||||||
|
onClose?: (e: NotifyWindowEvent) => void;
|
||||||
|
}
|
497
projects/notify-window/src/lib/services/notify-window.service.ts
Normal file
497
projects/notify-window/src/lib/services/notify-window.service.ts
Normal file
|
@ -0,0 +1,497 @@
|
||||||
|
import url from 'url';
|
||||||
|
import fse from 'fs-extra';
|
||||||
|
import log from 'electron-log';
|
||||||
|
|
||||||
|
import { WebContentsChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
import { AnimationQueue } from '../utils/animation-queue';
|
||||||
|
import {
|
||||||
|
NotifyWindowOptions,
|
||||||
|
DefaultNotifyWindowOptions
|
||||||
|
} from '../models/notify-window-options';
|
||||||
|
import { screen, BrowserWindow, ipcMain, IpcMainEvent, shell } from 'electron';
|
||||||
|
import { NotifyWindow } from '../models/notify-window';
|
||||||
|
import { NotifyWindowEventType } from '../types/event.type';
|
||||||
|
import { Channel } from '../types/channel.type';
|
||||||
|
|
||||||
|
const onClickNotifyWindow = 'onClickNotifyWindow';
|
||||||
|
const onCloseNotifyWindow = 'onCloseNotifyWindow';
|
||||||
|
|
||||||
|
interface ENPoint {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ENDimension {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BrowserWindowPooler {
|
||||||
|
private readonly inactiveWindows: BrowserWindow[];
|
||||||
|
|
||||||
|
constructor(private readonly minSize: number) {
|
||||||
|
this.minSize = 0 > this.minSize ? 0 : this.minSize;
|
||||||
|
this.inactiveWindows = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getLength() {
|
||||||
|
return this.inactiveWindows.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
push(...items: BrowserWindow[]): number {
|
||||||
|
const length = this.inactiveWindows.push(...items);
|
||||||
|
|
||||||
|
if (this.minSize < length) {
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(): BrowserWindow {
|
||||||
|
if (!this.inactiveWindows || 0 === this.inactiveWindows.length) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return this.inactiveWindows.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAll() {
|
||||||
|
while (this.inactiveWindows.length > 0) {
|
||||||
|
const w = this.inactiveWindows.pop();
|
||||||
|
w.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private start() {
|
||||||
|
setTimeout(() => {
|
||||||
|
while (this.minSize < this.inactiveWindows.length) {
|
||||||
|
const w = this.inactiveWindows.pop();
|
||||||
|
w.close();
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NotifyWindowService {
|
||||||
|
private animationQueue: AnimationQueue;
|
||||||
|
private customOptions: NotifyWindowOptions;
|
||||||
|
private nextInsertPosition: ENPoint;
|
||||||
|
private totalDimension: ENDimension;
|
||||||
|
private firstPosition: ENPoint;
|
||||||
|
private lowerRightCornerPosition: ENPoint;
|
||||||
|
private maxVisibleNotifications: number;
|
||||||
|
private activeNotifications: BrowserWindow[];
|
||||||
|
private browserWindowPooler: BrowserWindowPooler;
|
||||||
|
|
||||||
|
private notificationQueue: NotifyWindow[];
|
||||||
|
private closedNotifications: Map<number, boolean>;
|
||||||
|
private latestId: number;
|
||||||
|
private templateUrl: string;
|
||||||
|
|
||||||
|
constructor(options?: NotifyWindowOptions) {
|
||||||
|
this.customOptions = {
|
||||||
|
...DefaultNotifyWindowOptions
|
||||||
|
};
|
||||||
|
if (!!options) {
|
||||||
|
this.customOptions = {
|
||||||
|
...this.customOptions,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setup();
|
||||||
|
this.setupEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
setOptions(options: NotifyWindowOptions) {
|
||||||
|
if (!!options) {
|
||||||
|
this.customOptions = {
|
||||||
|
...this.customOptions,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.calcDimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(): NotifyWindowOptions {
|
||||||
|
return this.customOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTemplatePath(templatePath: string) {
|
||||||
|
if (!!templatePath) {
|
||||||
|
this.customOptions.templatePath = templatePath;
|
||||||
|
this.updateTemplatePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplatePath(): string {
|
||||||
|
if (!this.templateUrl) {
|
||||||
|
this.updateTemplatePath();
|
||||||
|
}
|
||||||
|
return this.templateUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
notify(notification: NotifyWindow): number {
|
||||||
|
notification.id = this.latestId++;
|
||||||
|
this.animationQueue.push({
|
||||||
|
context: this,
|
||||||
|
func: this.showNotification,
|
||||||
|
args: [notification]
|
||||||
|
});
|
||||||
|
return notification.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
this.animationQueue.clear();
|
||||||
|
this.activeNotifications.forEach(window => window.close());
|
||||||
|
this.browserWindowPooler.closeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAll(): void {
|
||||||
|
this.animationQueue.clear();
|
||||||
|
this.activeNotifications.forEach(window => window.close());
|
||||||
|
this.browserWindowPooler.closeAll();
|
||||||
|
|
||||||
|
this.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setup(): void {
|
||||||
|
this.nextInsertPosition = { x: 0, y: 0 };
|
||||||
|
this.totalDimension = { width: 0, height: 0 };
|
||||||
|
this.firstPosition = { x: 0, y: 0 };
|
||||||
|
this.activeNotifications = [];
|
||||||
|
this.browserWindowPooler = new BrowserWindowPooler(
|
||||||
|
this.getOptions().browserWindowPool.min
|
||||||
|
);
|
||||||
|
this.notificationQueue = [];
|
||||||
|
this.closedNotifications = new Map();
|
||||||
|
this.latestId = 0;
|
||||||
|
|
||||||
|
this.animationQueue = new AnimationQueue();
|
||||||
|
|
||||||
|
const display = screen.getPrimaryDisplay();
|
||||||
|
|
||||||
|
this.lowerRightCornerPosition = {
|
||||||
|
x: display.bounds.x + display.workArea.x + display.workAreaSize.width,
|
||||||
|
y: display.bounds.y + display.workArea.y + display.workAreaSize.height
|
||||||
|
};
|
||||||
|
|
||||||
|
this.calcDimensions();
|
||||||
|
|
||||||
|
this.maxVisibleNotifications = Math.floor(
|
||||||
|
display.workAreaSize.height / this.totalDimension.height
|
||||||
|
);
|
||||||
|
|
||||||
|
this.maxVisibleNotifications =
|
||||||
|
this.getOptions().browserWindowPool.max < this.maxVisibleNotifications
|
||||||
|
? this.getOptions().browserWindowPool.max
|
||||||
|
: this.maxVisibleNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupEvents(): void {
|
||||||
|
const self = this;
|
||||||
|
ipcMain.on(
|
||||||
|
Channel.close,
|
||||||
|
(event: IpcMainEvent, windowId: number, notification: NotifyWindow) => {
|
||||||
|
const onClose = self.buildCloseNotification(
|
||||||
|
BrowserWindow.fromId(windowId),
|
||||||
|
notification
|
||||||
|
);
|
||||||
|
self.buildCloseNotificationSafely(onClose)('close');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
Channel.click,
|
||||||
|
(event: IpcMainEvent, windowId: number, notification: NotifyWindow) => {
|
||||||
|
if (!!notification.url) {
|
||||||
|
shell.openExternal(notification.url);
|
||||||
|
}
|
||||||
|
const notificationWindow = BrowserWindow.fromId(windowId);
|
||||||
|
|
||||||
|
if (notificationWindow && notificationWindow[onClickNotifyWindow]) {
|
||||||
|
const onClose = self.buildCloseNotification(
|
||||||
|
BrowserWindow.fromId(windowId),
|
||||||
|
notification
|
||||||
|
);
|
||||||
|
notificationWindow[onClickNotifyWindow]({
|
||||||
|
type: NotifyWindowEventType.Click,
|
||||||
|
id: notification.id,
|
||||||
|
close: self.buildCloseNotificationSafely(onClose)
|
||||||
|
});
|
||||||
|
delete notificationWindow[onClickNotifyWindow];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private calcDimensions() {
|
||||||
|
this.totalDimension = {
|
||||||
|
width: this.customOptions.width + this.customOptions.padding,
|
||||||
|
height: this.customOptions.height + this.customOptions.padding
|
||||||
|
};
|
||||||
|
|
||||||
|
this.firstPosition = {
|
||||||
|
x: this.lowerRightCornerPosition.x - this.totalDimension.width,
|
||||||
|
y: this.lowerRightCornerPosition.y - this.totalDimension.height
|
||||||
|
};
|
||||||
|
|
||||||
|
this.nextInsertPosition = {
|
||||||
|
x: this.firstPosition.x,
|
||||||
|
y: this.firstPosition.y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private calcInsertPosition() {
|
||||||
|
if (this.activeNotifications.length < this.maxVisibleNotifications) {
|
||||||
|
this.nextInsertPosition.y =
|
||||||
|
this.lowerRightCornerPosition.y -
|
||||||
|
this.totalDimension.height * (this.activeNotifications.length + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateTemplatePath() {
|
||||||
|
try {
|
||||||
|
fse.statSync(this.customOptions.templatePath).isFile();
|
||||||
|
|
||||||
|
this.templateUrl = url.format({
|
||||||
|
pathname: this.customOptions.templatePath,
|
||||||
|
protocol: 'file:',
|
||||||
|
slashes: true
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log.error(
|
||||||
|
'electron-notify: Could not find template ("' +
|
||||||
|
this.customOptions.templatePath +
|
||||||
|
'").'
|
||||||
|
);
|
||||||
|
log.error(
|
||||||
|
'electron-notify: To use a different template you need to correct the config.templatePath or simply adapt config.htmlTemplate'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private showNotification(notification: NotifyWindow): Promise<any> {
|
||||||
|
const self = this;
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
if (this.activeNotifications.length < this.maxVisibleNotifications) {
|
||||||
|
self.getWindow().then(notificationWindow => {
|
||||||
|
self.calcInsertPosition();
|
||||||
|
notificationWindow.setPosition(
|
||||||
|
self.nextInsertPosition.x,
|
||||||
|
self.nextInsertPosition.y
|
||||||
|
);
|
||||||
|
self.activeNotifications.push(notificationWindow);
|
||||||
|
|
||||||
|
const displayTime = !!notification.displayTime
|
||||||
|
? notification.displayTime
|
||||||
|
: self.customOptions.displayTime;
|
||||||
|
let timeoutId: any;
|
||||||
|
const onClose = self.buildCloseNotification(
|
||||||
|
notificationWindow,
|
||||||
|
notification,
|
||||||
|
() => timeoutId
|
||||||
|
);
|
||||||
|
const onCloseNotificationSafely = self.buildCloseNotificationSafely(
|
||||||
|
onClose
|
||||||
|
);
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
if (notificationWindow.isDestroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onCloseNotificationSafely('timeout');
|
||||||
|
}, displayTime);
|
||||||
|
|
||||||
|
if (!!notification.onShow) {
|
||||||
|
notification.onShow({
|
||||||
|
type: NotifyWindowEventType.Show,
|
||||||
|
id: notification.id,
|
||||||
|
close: onCloseNotificationSafely
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!notification.onClick) {
|
||||||
|
notificationWindow[onClickNotifyWindow] = notification.onClick;
|
||||||
|
} else {
|
||||||
|
delete notificationWindow[onClickNotifyWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!notification.onClose) {
|
||||||
|
notificationWindow[onCloseNotifyWindow] = notification.onClose;
|
||||||
|
} else {
|
||||||
|
delete notificationWindow[onCloseNotifyWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationWindow.webContents.send(
|
||||||
|
Channel.browserWindowSetContents,
|
||||||
|
notification
|
||||||
|
);
|
||||||
|
notificationWindow.showInactive();
|
||||||
|
resolve(notificationWindow);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.notificationQueue.push(notification);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildCloseNotification(
|
||||||
|
notificationWindow: BrowserWindow,
|
||||||
|
notification: NotifyWindow,
|
||||||
|
timeoutIdFunc?: () => number
|
||||||
|
) {
|
||||||
|
const self = this;
|
||||||
|
return (e: NotifyWindowEventType): Promise<void> => {
|
||||||
|
if (notificationWindow.isDestroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.closedNotifications.has(notification.id)) {
|
||||||
|
self.closedNotifications.delete(notification.id);
|
||||||
|
return new Promise<void>(resolve => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.closedNotifications.set(notification.id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!notificationWindow[onCloseNotifyWindow]) {
|
||||||
|
notificationWindow[onCloseNotifyWindow]({
|
||||||
|
type: e,
|
||||||
|
id: notification.id
|
||||||
|
});
|
||||||
|
delete notificationWindow[onCloseNotifyWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationWindow.webContents.send(Channel.reset);
|
||||||
|
|
||||||
|
if (!!timeoutIdFunc) {
|
||||||
|
clearTimeout(timeoutIdFunc());
|
||||||
|
}
|
||||||
|
const i = self.activeNotifications.indexOf(notificationWindow);
|
||||||
|
self.activeNotifications.splice(i, 1);
|
||||||
|
self.browserWindowPooler.push(notificationWindow);
|
||||||
|
|
||||||
|
notificationWindow.hide();
|
||||||
|
self.checkForQueuedNotifications();
|
||||||
|
|
||||||
|
return self.moveOneDown(i);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildCloseNotificationSafely(
|
||||||
|
onClose: (e: NotifyWindowEventType) => any
|
||||||
|
) {
|
||||||
|
const self = this;
|
||||||
|
return (reason: any) => {
|
||||||
|
if (!reason) {
|
||||||
|
reason = 'closedByAPI';
|
||||||
|
}
|
||||||
|
self.animationQueue.push({
|
||||||
|
context: self,
|
||||||
|
func: onClose,
|
||||||
|
args: [reason]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkForQueuedNotifications(): void {
|
||||||
|
if (
|
||||||
|
0 < this.notificationQueue.length &&
|
||||||
|
this.activeNotifications.length < this.maxVisibleNotifications
|
||||||
|
) {
|
||||||
|
this.animationQueue.push({
|
||||||
|
context: this,
|
||||||
|
func: this.showNotification,
|
||||||
|
args: [this.notificationQueue.shift()]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getWindow(): Promise<BrowserWindow> {
|
||||||
|
const slef = this;
|
||||||
|
return new Promise<BrowserWindow>((resolve, reject) => {
|
||||||
|
if (0 < slef.browserWindowPooler.getLength()) {
|
||||||
|
resolve(slef.browserWindowPooler.pop());
|
||||||
|
} else {
|
||||||
|
const windowProperties = slef.customOptions.defaultWindow;
|
||||||
|
windowProperties.width = slef.customOptions.width;
|
||||||
|
windowProperties.height = slef.customOptions.height;
|
||||||
|
|
||||||
|
const notificationWindow = new BrowserWindow({
|
||||||
|
...windowProperties,
|
||||||
|
title: 'Notification'
|
||||||
|
});
|
||||||
|
notificationWindow.setVisibleOnAllWorkspaces(true);
|
||||||
|
notificationWindow.loadURL(slef.getTemplatePath());
|
||||||
|
notificationWindow.webContents.on(
|
||||||
|
WebContentsChannel.DidFinishLoad,
|
||||||
|
() => {
|
||||||
|
// Done
|
||||||
|
notificationWindow.webContents.send(
|
||||||
|
Channel.loadConfig,
|
||||||
|
slef.customOptions
|
||||||
|
);
|
||||||
|
resolve(notificationWindow);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
notificationWindow.webContents.on(
|
||||||
|
WebContentsChannel.DevtoolsOpened,
|
||||||
|
() => {
|
||||||
|
notificationWindow.webContents.closeDevTools();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveOneDown(startPos: number): Promise<void> {
|
||||||
|
const self = this;
|
||||||
|
return new Promise<void>(async (resolve, reject) => {
|
||||||
|
if (startPos >= self.activeNotifications.length || -1 === startPos) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aryNotificationPos: number[] = [];
|
||||||
|
for (let i = startPos; i < self.activeNotifications.length; i++) {
|
||||||
|
aryNotificationPos.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
aryNotificationPos.map(async index => {
|
||||||
|
await self.moveNotificationAnimation(index);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveNotificationAnimation(index: number): Promise<void> {
|
||||||
|
const self = this;
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
const notificationWindow = self.activeNotifications[index];
|
||||||
|
const newY =
|
||||||
|
self.lowerRightCornerPosition.y -
|
||||||
|
self.totalDimension.height * (index + 1);
|
||||||
|
const startY = notificationWindow.getPosition()[1];
|
||||||
|
const step = (newY - startY) / self.customOptions.animationSteps;
|
||||||
|
let curStep = 1;
|
||||||
|
const animationInterval = setInterval(() => {
|
||||||
|
// Abort condition
|
||||||
|
if (curStep === self.customOptions.animationSteps) {
|
||||||
|
notificationWindow.setPosition(self.firstPosition.x, newY);
|
||||||
|
clearInterval(animationInterval);
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
// Move one step down
|
||||||
|
notificationWindow.setPosition(
|
||||||
|
self.firstPosition.x,
|
||||||
|
Math.trunc(startY + curStep * step)
|
||||||
|
);
|
||||||
|
curStep++;
|
||||||
|
}, self.customOptions.animationStepMs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
7
projects/notify-window/src/lib/types/channel.type.ts
Normal file
7
projects/notify-window/src/lib/types/channel.type.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export enum Channel {
|
||||||
|
close = 'ucap::electron::notify-window::close',
|
||||||
|
click = 'ucap::electron::notify-window::click',
|
||||||
|
loadConfig = 'ucap::electron::notify-window::loadConfig',
|
||||||
|
reset = 'ucap::electron::notify-window::reset',
|
||||||
|
browserWindowSetContents = 'ucap::electron::notify-window::browserWindowSetContents'
|
||||||
|
}
|
5
projects/notify-window/src/lib/types/event.type.ts
Normal file
5
projects/notify-window/src/lib/types/event.type.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export enum NotifyWindowEventType {
|
||||||
|
Show = 'Show',
|
||||||
|
Click = 'Click',
|
||||||
|
Close = 'Close'
|
||||||
|
}
|
44
projects/notify-window/src/lib/utils/animation-queue.ts
Normal file
44
projects/notify-window/src/lib/utils/animation-queue.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import log from 'electron-log';
|
||||||
|
|
||||||
|
export interface AnimationQueueObject {
|
||||||
|
context: any;
|
||||||
|
func: (...args: any[]) => Promise<any>;
|
||||||
|
args: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AnimationQueue {
|
||||||
|
private running = false;
|
||||||
|
private queue: AnimationQueueObject[] = [];
|
||||||
|
|
||||||
|
push(o: AnimationQueueObject): void {
|
||||||
|
if (this.running) {
|
||||||
|
this.queue.push(o);
|
||||||
|
} else {
|
||||||
|
this.running = true;
|
||||||
|
this.animate(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animate(o: AnimationQueueObject): void {
|
||||||
|
const self = this;
|
||||||
|
try {
|
||||||
|
(o.func.apply(o.context, o.args) as Promise<any>)
|
||||||
|
.then(() => {
|
||||||
|
if (self.queue.length > 0) {
|
||||||
|
self.animate.call(self, self.queue.shift());
|
||||||
|
} else {
|
||||||
|
self.running = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(reason => {
|
||||||
|
log.error(reason);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.queue = [];
|
||||||
|
}
|
||||||
|
}
|
5
projects/notify-window/src/public-api.ts
Normal file
5
projects/notify-window/src/public-api.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of notification
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/types/channel.type';
|
12
projects/notify-window/tsconfig.lib.json
Normal file
12
projects/notify-window/tsconfig.lib.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"declaration": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": ["dom", "es2018"]
|
||||||
|
},
|
||||||
|
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
||||||
|
}
|
3
projects/notify-window/tsconfig.lib.prod.json
Normal file
3
projects/notify-window/tsconfig.lib.prod.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.lib.json"
|
||||||
|
}
|
9
projects/notify-window/tsconfig.spec.json
Normal file
9
projects/notify-window/tsconfig.spec.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": ["jasmine", "node"]
|
||||||
|
},
|
||||||
|
"files": ["src/test.ts"],
|
||||||
|
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||||
|
}
|
3
projects/notify-window/tslint.json
Normal file
3
projects/notify-window/tslint.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tslint.json"
|
||||||
|
}
|
7
projects/notify-window/ucap-package.json
Normal file
7
projects/notify-window/ucap-package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"dest": "../../dist/notify-window",
|
||||||
|
"docDest": "../../docs/notify-window",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
16
projects/updater-window/package.json
Normal file
16
projects/updater-window/package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "@ucap/electron-updater-window",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "http://10.81.13.221:8081/nexus/repository/npm-ucap/"
|
||||||
|
},
|
||||||
|
"scripts": {},
|
||||||
|
"dependencies": {
|
||||||
|
"@ucap/electron-core": "~0.0.1",
|
||||||
|
"electron": "^8.0.0",
|
||||||
|
"electron-log": "^4.1.0",
|
||||||
|
"fs-extra": "^8.1.0",
|
||||||
|
"rxjs": "^6.5.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { BrowserWindowConstructorOptions } from 'electron';
|
||||||
|
|
||||||
|
export interface UpdaterWindowOptions extends BrowserWindowConstructorOptions {
|
||||||
|
templatePath?: string;
|
||||||
|
onReady?: () => void;
|
||||||
|
onAcceptUpdate?: () => void;
|
||||||
|
onDenyUpdate?: () => void;
|
||||||
|
onCancelDownload?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DefaultUpdaterWindowOptions: UpdaterWindowOptions = {
|
||||||
|
width: 500,
|
||||||
|
height: 160,
|
||||||
|
frame: false,
|
||||||
|
skipTaskbar: true,
|
||||||
|
alwaysOnTop: true,
|
||||||
|
maximizable: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,129 @@
|
||||||
|
import { BrowserWindow, ipcMain } from 'electron';
|
||||||
|
import url from 'url';
|
||||||
|
import fse from 'fs-extra';
|
||||||
|
import log from 'electron-log';
|
||||||
|
import {
|
||||||
|
UpdaterWindowOptions,
|
||||||
|
DefaultUpdaterWindowOptions
|
||||||
|
} from '../models/updater-window-options';
|
||||||
|
|
||||||
|
import { Channel } from '../types/channel.type';
|
||||||
|
import { WebContentsChannel } from '@ucap/electron-core';
|
||||||
|
|
||||||
|
export class UpdaterWindowService {
|
||||||
|
private customOptions: UpdaterWindowOptions;
|
||||||
|
private browserWindow: BrowserWindow;
|
||||||
|
private templateUrl: string;
|
||||||
|
|
||||||
|
constructor(options: UpdaterWindowOptions) {
|
||||||
|
this.customOptions = {
|
||||||
|
...DefaultUpdaterWindowOptions
|
||||||
|
};
|
||||||
|
if (!!options) {
|
||||||
|
this.customOptions = {
|
||||||
|
...this.customOptions,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setOptions(options: UpdaterWindowOptions) {
|
||||||
|
if (!!options) {
|
||||||
|
this.customOptions = {
|
||||||
|
...this.customOptions,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(): UpdaterWindowOptions {
|
||||||
|
return this.customOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTemplatePath(templatePath: string) {
|
||||||
|
if (!!templatePath) {
|
||||||
|
this.customOptions.templatePath = templatePath;
|
||||||
|
this.updateTemplatePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplatePath(): string {
|
||||||
|
if (!this.templateUrl) {
|
||||||
|
this.updateTemplatePath();
|
||||||
|
}
|
||||||
|
return this.templateUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
show(versionInfo: { installed: string; latest: string }) {
|
||||||
|
this.browserWindow = new BrowserWindow(this.customOptions);
|
||||||
|
this.browserWindow.loadURL(this.getTemplatePath());
|
||||||
|
|
||||||
|
this.browserWindow.on('closed', () => {
|
||||||
|
this.browserWindow = null;
|
||||||
|
});
|
||||||
|
this.browserWindow.webContents.on(WebContentsChannel.DidFinishLoad, () => {
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this.browserWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
if (!!this.customOptions.onReady) {
|
||||||
|
this.customOptions.onReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.browserWindow.webContents.send(
|
||||||
|
Channel.browserWindowSetContents,
|
||||||
|
versionInfo
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(Channel.acceptUpdate, this._acceptUpdateHandler.bind(this));
|
||||||
|
ipcMain.on(Channel.denyUpdate, this._denyUpdateHandler.bind(this));
|
||||||
|
ipcMain.on(Channel.cancelDownload, this._cancelDownloadHandler.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
setDownloadValue(value: number, total: number) {
|
||||||
|
this.browserWindow.webContents.send(Channel.downloadProcess, value, total);
|
||||||
|
}
|
||||||
|
setDownloadComplete() {
|
||||||
|
this.browserWindow.webContents.send(Channel.downloadComplete);
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
if (!this.browserWindow || this.browserWindow.isDestroyed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.browserWindow.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
_acceptUpdateHandler() {
|
||||||
|
if (!!this.customOptions.onAcceptUpdate) {
|
||||||
|
this.customOptions.onAcceptUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_denyUpdateHandler() {
|
||||||
|
if (!!this.customOptions.onDenyUpdate) {
|
||||||
|
this.customOptions.onDenyUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_cancelDownloadHandler() {
|
||||||
|
if (!!this.customOptions.onCancelDownload) {
|
||||||
|
this.customOptions.onCancelDownload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateTemplatePath() {
|
||||||
|
try {
|
||||||
|
fse.statSync(this.customOptions.templatePath).isFile();
|
||||||
|
|
||||||
|
this.templateUrl = url.format({
|
||||||
|
pathname: this.customOptions.templatePath,
|
||||||
|
protocol: 'file:',
|
||||||
|
slashes: true
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log.error(
|
||||||
|
'electron-update-window: Could not find template ("' +
|
||||||
|
this.customOptions.templatePath +
|
||||||
|
'").'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
projects/updater-window/src/lib/types/channel.type.ts
Normal file
10
projects/updater-window/src/lib/types/channel.type.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
export enum Channel {
|
||||||
|
acceptUpdate = 'ucap::electron::updater-window::acceptUpdate',
|
||||||
|
denyUpdate = 'ucap::electron::updater-window::denyUpdate',
|
||||||
|
cancelDownload = 'ucap::electron::updater-window::cancelDownload',
|
||||||
|
|
||||||
|
downloadProcess = 'ucap::electron::updater-window::downloadProcess',
|
||||||
|
downloadComplete = 'ucap::electron::updater-window::downloadComplete',
|
||||||
|
|
||||||
|
browserWindowSetContents = 'ucap::electron::updater-window::browserWindowSetContents'
|
||||||
|
}
|
5
projects/updater-window/src/public-api.ts
Normal file
5
projects/updater-window/src/public-api.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/*
|
||||||
|
* Public API Surface of core
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './lib/types/channel.type';
|
12
projects/updater-window/tsconfig.lib.json
Normal file
12
projects/updater-window/tsconfig.lib.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/lib",
|
||||||
|
"target": "es2015",
|
||||||
|
"declaration": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": [],
|
||||||
|
"lib": ["dom", "es2018"]
|
||||||
|
},
|
||||||
|
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
||||||
|
}
|
3
projects/updater-window/tsconfig.lib.prod.json
Normal file
3
projects/updater-window/tsconfig.lib.prod.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.lib.json"
|
||||||
|
}
|
9
projects/updater-window/tsconfig.spec.json
Normal file
9
projects/updater-window/tsconfig.spec.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../out-tsc/spec",
|
||||||
|
"types": ["jasmine", "node"]
|
||||||
|
},
|
||||||
|
"files": ["src/test.ts"],
|
||||||
|
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||||
|
}
|
3
projects/updater-window/tslint.json
Normal file
3
projects/updater-window/tslint.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"extends": "../../tslint.json"
|
||||||
|
}
|
7
projects/updater-window/ucap-package.json
Normal file
7
projects/updater-window/ucap-package.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"dest": "../../dist/updater-window",
|
||||||
|
"docDest": "../../docs/updater-window",
|
||||||
|
"lib": {
|
||||||
|
"entryFile": "src/public-api.ts"
|
||||||
|
}
|
||||||
|
}
|
351
scripts/build.js
Normal file
351
scripts/build.js
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const path = require('path');
|
||||||
|
const fse = require('fs-extra');
|
||||||
|
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const webpackMerge = require('webpack-merge');
|
||||||
|
const webpackNodeExternals = require('webpack-node-externals');
|
||||||
|
const webpackNodeTerser = require('terser-webpack-plugin');
|
||||||
|
|
||||||
|
async function buildForProduction(args) {
|
||||||
|
const rootPath = path.join(__dirname, '..');
|
||||||
|
|
||||||
|
const projectName = args[0];
|
||||||
|
|
||||||
|
const projectPath = path.join(rootPath, 'projects', projectName);
|
||||||
|
|
||||||
|
const packageJson = require(path.join(projectPath, 'package.json'));
|
||||||
|
const ucapPackageJson = require(path.join(projectPath, 'ucap-package.json'));
|
||||||
|
|
||||||
|
const distPath = path.join(projectPath, ucapPackageJson.dest);
|
||||||
|
const docPath = path.join(projectPath, ucapPackageJson.docDest);
|
||||||
|
|
||||||
|
const webpackConfig = (overrideConfig, compilerOptions) => {
|
||||||
|
const commonConfig = {
|
||||||
|
name: projectName,
|
||||||
|
target: 'node',
|
||||||
|
mode: 'production',
|
||||||
|
context: path.join(projectPath, 'src'),
|
||||||
|
entry: path.join(projectPath, ucapPackageJson.lib.entryFile),
|
||||||
|
output: {
|
||||||
|
path: path.join(distPath, 'bundles'),
|
||||||
|
filename: `${projectName}.umd.js`,
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
library: projectName,
|
||||||
|
umdNamedDefine: true
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.ts', '.jsx', '.tsx', '.json'],
|
||||||
|
modules: ['node_modules', 'src']
|
||||||
|
},
|
||||||
|
externals: [webpackNodeExternals()],
|
||||||
|
devtool: 'source-map',
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
configFile: path.join(projectPath, 'tsconfig.lib.prod.json'),
|
||||||
|
compilerOptions: !!compilerOptions
|
||||||
|
? compilerOptions
|
||||||
|
: {
|
||||||
|
declaration: false,
|
||||||
|
module: 'ES2015',
|
||||||
|
target: 'es5'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
exclude: /node_modules/
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return webpackMerge(commonConfig, overrideConfig);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clean = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const _distPath = path.join(distPath);
|
||||||
|
console.log(`${projectName}: cleaning started [${_distPath}]`);
|
||||||
|
execSync(`rimraf ${_distPath}`, {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
console.log(`${projectName}: cleaning complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genDeclaration = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of declaration started`);
|
||||||
|
execSync(
|
||||||
|
`tsc --project ${path.join(
|
||||||
|
projectPath,
|
||||||
|
'tsconfig.lib.prod.json'
|
||||||
|
)} --module commonjs --target es5 --outDir ${path.join(
|
||||||
|
distPath,
|
||||||
|
'lib'
|
||||||
|
)} --emitDeclarationOnly true --declarationDir ${path.join(distPath)}`,
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
console.log(`${projectName}: generating of declaration complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genEs5 = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of es5 started`);
|
||||||
|
execSync(
|
||||||
|
`tsc --project ${path.join(
|
||||||
|
projectPath,
|
||||||
|
'tsconfig.lib.prod.json'
|
||||||
|
)} --module es2015 --target es5 --outDir ${path.join(
|
||||||
|
distPath,
|
||||||
|
'es5'
|
||||||
|
)} --declaration false --sourceMap false --inlineSourceMap true`,
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
console.log(`${projectName}: generating of es5 complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genEs2015 = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of es2015 started`);
|
||||||
|
execSync(
|
||||||
|
`tsc --project ${path.join(
|
||||||
|
projectPath,
|
||||||
|
'tsconfig.lib.prod.json'
|
||||||
|
)} --module es2015 --target es2015 --outDir ${path.join(
|
||||||
|
distPath,
|
||||||
|
'es2015'
|
||||||
|
)} --declaration false --sourceMap false --inlineSourceMap true`,
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
console.log(`${projectName}: generating of es2015 complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genBundles = () => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of bundle[umd] started`);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
webpack(
|
||||||
|
webpackConfig({ optimization: { minimize: false } }),
|
||||||
|
(err, status) => {
|
||||||
|
if (!!err) {
|
||||||
|
console.err(err);
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch(reason => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
webpack(
|
||||||
|
webpackConfig({
|
||||||
|
output: {
|
||||||
|
filename: `${projectName}.umd.min.js`
|
||||||
|
},
|
||||||
|
optimization: { minimizer: [new webpackNodeTerser()] }
|
||||||
|
}),
|
||||||
|
(err, status) => {
|
||||||
|
if (!!err) {
|
||||||
|
console.err(err);
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch(reason => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`${projectName}: generating of bundle[umd] complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genFes5 = () => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of fes5 started`);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
webpack(
|
||||||
|
webpackConfig(
|
||||||
|
{
|
||||||
|
output: {
|
||||||
|
path: path.join(distPath, 'fes5'),
|
||||||
|
filename: `${projectName}.js`,
|
||||||
|
library: projectName
|
||||||
|
},
|
||||||
|
optimization: { minimize: false }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
declaration: false,
|
||||||
|
module: 'es2015',
|
||||||
|
target: 'es5'
|
||||||
|
}
|
||||||
|
),
|
||||||
|
(err, status) => {
|
||||||
|
if (!!err) {
|
||||||
|
console.err(err);
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch(reason => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`${projectName}: generating of fes5 complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genFes2015 = () => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of fes2015 started`);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
webpack(
|
||||||
|
webpackConfig(
|
||||||
|
{
|
||||||
|
output: {
|
||||||
|
path: path.join(distPath, 'fes2015'),
|
||||||
|
filename: `${projectName}.js`,
|
||||||
|
library: projectName
|
||||||
|
},
|
||||||
|
optimization: { minimize: false }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
declaration: false,
|
||||||
|
module: 'es2015',
|
||||||
|
target: 'es2015'
|
||||||
|
}
|
||||||
|
),
|
||||||
|
(err, status) => {
|
||||||
|
if (!!err) {
|
||||||
|
console.err(err);
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch(reason => {
|
||||||
|
reject(reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`${projectName}: generating of fes2015 complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genPackageJson = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of package.json started`);
|
||||||
|
const projectpackageJson = {
|
||||||
|
...packageJson,
|
||||||
|
main: `bundles/${projectName}.umd.js`,
|
||||||
|
module: `fes5/${projectName}.js`,
|
||||||
|
es2015: `fes2015/${projectName}.js`,
|
||||||
|
esm5: `es5/public-api.js`,
|
||||||
|
esm2015: `es2016/public-api.js`,
|
||||||
|
fesm5: `fes5/${projectName}.js`,
|
||||||
|
fesm2015: `fes2015/${projectName}.js`,
|
||||||
|
typings: `public-api.d.ts`,
|
||||||
|
sideEffects: false
|
||||||
|
};
|
||||||
|
|
||||||
|
fse.writeFileSync(
|
||||||
|
path.join(distPath, 'package.json'),
|
||||||
|
JSON.stringify(projectpackageJson)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`${projectName}: generating of package.json complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const installPackage = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`${projectName}: installation for local started`);
|
||||||
|
process.chdir(path.join(distPath));
|
||||||
|
execSync(`npm pack`, { stdio: 'inherit' });
|
||||||
|
process.chdir(path.join(rootPath));
|
||||||
|
const projectVersion = require(path.join(distPath, 'package.json'))
|
||||||
|
.version;
|
||||||
|
|
||||||
|
execSync(
|
||||||
|
`npm install -D ${path.join(
|
||||||
|
distPath,
|
||||||
|
`ucap-electron-${projectName}-${projectVersion}.tgz`
|
||||||
|
)}`,
|
||||||
|
{
|
||||||
|
stdio: 'inherit'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
execSync(
|
||||||
|
`rimraf ${path.join(
|
||||||
|
distPath,
|
||||||
|
`ucap-electron-${projectName}-${projectVersion}.tgz`
|
||||||
|
)}`,
|
||||||
|
{
|
||||||
|
stdio: 'inherit'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`${projectName}: installation for local complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const genDoc = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(`${projectName}: generating of doc started`);
|
||||||
|
execSync(`rimraf ${path.join(docPath)}`, {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
execSync(
|
||||||
|
`typedoc --out ${path.join(docPath)} ${path.join(projectPath, 'src')}`,
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`${projectName}: generating of doc complete`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
await clean();
|
||||||
|
await genDeclaration();
|
||||||
|
await genEs5();
|
||||||
|
await genEs2015();
|
||||||
|
await genBundles();
|
||||||
|
await genFes5();
|
||||||
|
await genFes2015();
|
||||||
|
await genPackageJson();
|
||||||
|
await installPackage();
|
||||||
|
await genDoc();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForProduction(process.argv.slice(2));
|
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"target": "es5",
|
||||||
|
"typeRoots": ["node_modules/@types"],
|
||||||
|
"lib": ["es2018", "dom"],
|
||||||
|
"paths": {}
|
||||||
|
}
|
||||||
|
}
|
54
tslint.json
Normal file
54
tslint.json
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"extends": "tslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"array-type": false,
|
||||||
|
"arrow-parens": false,
|
||||||
|
"deprecation": {
|
||||||
|
"severity": "warning"
|
||||||
|
},
|
||||||
|
"import-blacklist": [true, "rxjs/Rx"],
|
||||||
|
"interface-name": false,
|
||||||
|
"max-classes-per-file": false,
|
||||||
|
"max-line-length": [true, 140],
|
||||||
|
"member-access": false,
|
||||||
|
"member-ordering": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"order": [
|
||||||
|
"static-field",
|
||||||
|
"instance-field",
|
||||||
|
"static-method",
|
||||||
|
"instance-method"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-consecutive-blank-lines": false,
|
||||||
|
"no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
|
||||||
|
"no-empty": false,
|
||||||
|
"no-inferrable-types": [true, "ignore-params"],
|
||||||
|
"no-non-null-assertion": false,
|
||||||
|
"no-redundant-jsdoc": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-var-requires": false,
|
||||||
|
"object-literal-key-quotes": [true, "as-needed"],
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"ordered-imports": false,
|
||||||
|
"quotemark": [true, "single"],
|
||||||
|
"trailing-comma": false,
|
||||||
|
"component-class-suffix": true,
|
||||||
|
"contextual-lifecycle": true,
|
||||||
|
"directive-class-suffix": true,
|
||||||
|
"no-conflicting-lifecycle": true,
|
||||||
|
"no-host-metadata-property": true,
|
||||||
|
"no-input-rename": true,
|
||||||
|
"no-inputs-metadata-property": true,
|
||||||
|
"no-output-native": true,
|
||||||
|
"no-output-on-prefix": true,
|
||||||
|
"no-output-rename": true,
|
||||||
|
"no-outputs-metadata-property": true,
|
||||||
|
"template-banana-in-box": true,
|
||||||
|
"template-no-negated-async": true,
|
||||||
|
"use-lifecycle-interface": true,
|
||||||
|
"use-pipe-transform-interface": true
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user