Commit 37117a2d authored by 李维's avatar 李维

Upgrade to new template

parent 8a3161f7
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
# dependencies # dependencies
/node_modules /node_modules
/publish
# profiling files # profiling files
chrome-profiler-events*.json chrome-profiler-events*.json
......
# ng-template-generator # ng-template-generator
angularjs技术框架下的H5互动模板框架脚手架 angularjs技术框架下的H5互动模板框架脚手架,基于NG-ZORRO实现快速开发基于绘玩云的H5互动课件。
\ No newline at end of file
# 使用简介
## 前期准备
* git下载 https://git-scm.com/downloads
* nodejs下载 https://nodejs.org/zh-cn/download/
* 谷歌浏览器下载 https://www.google.cn/chrome/
都下载最新版就行,然后默认安装就可以
## 生成项目
* 登录绘玩云课件开发平台:http://staging-teach.ireadabc.com/
* 点击“登录账号,查看我的课件”
* 输入测试的用户名/密码:developers/12345678
* 在右上角“个人中心”的下拉菜单里,点击“我的模板” 菜单,然后点击“新建模板”, 填写必要的信息,在“技术选型”一项上选择“Angular”
* 点击“确定”后,列表页就会出现一个新生成的模板项目
* 在项目的卡片下找到“开发”按钮,则会弹出相对应的git地址
## 获取并启动项目
```
// xxx 是上面项目对应的Git地址
git clone xxx
cd 项目名称/
npm install -g yarn
yarn install
npm start
//启动成功后打开浏览器,输入:http://localhost:4200 则可以看到这个项目的初始化效果了
```
## 项目结构
|-- bin
|-- dist
|-- e2e
|-- node_modules
|-- publish
|-- src
| |-- app
| | |-- common
| | |-- form
| | |-- pipes
| | |-- play
| | |-- services
| | |-- style
| | |-- app.component.html
| | |-- app.component.scss
| | |-- app.component.ts
| | |-- app.module.ts
| |-- assets
| |-- environments
| |-- services
| |-- index.html
| |-- main.ts
| |--.......
* 其中 play 文件夹是H5模板展示页面,form文件夹是模板的配置页面
* common文件夹是以往做过的模板积累的一些比较常用的 AngularJs 的组件
* assets文件夹存放模板样式的静态资源,例如小图标、背景图片、字体、样式等等
* 其他文件夹开发者可以不做任何更改
## 开始开发
本脚手架的页面类UI框架是基于 [NG-ZORRO](https://ng.ant.design/docs/introduce/zh "With a Title") 框架实现的,在配置页面(form文件夹),一些表单输入,上传图片等组件也可以使用 NG-ZORRO 现成的组件
### 开发配置页面(form/)
配置页面主要作用是为了呈现多样化模板,提高H5模板的高复用性、灵活性提供的一个配置工具,根据H5模板的设计规划或特性,会规定某些元素是可以配置的,比如背景图片、音频、选项、标题等等等等。(课件制作者) 通过配置页面,就可以灵活的更换这些,从而形成多种多样的课件。
配置页面的开发要求很简单,我们不关心布局、样式、交互等所有实现细节与效果,只需调用两个内置的全局接口即可:
* setData 接口,用于将配置的数据存储到云端。
此方法是一个异步的方法,接收三个必要参数
obj: 一个json对象
callback: 回调函数
t_name: 模板名称
一般使用例子如下:
```
// ts语法,不能直接使用js的window对象自定义方法
(<any> window).courseware.setData(obj, callback, t_name);
```
* getData 接口,用于当点击修改的时候将配置的数据从云端获取下来。
此方法是一个异步的方法,接收两个必要参数
> callback: 回调函数, 回调函数里会得到云端保存的数据
> t_name: 模板名称
一般使用例子如下:
```
// ts语法,不能直接使用js的window对象自定义方法
const getData = (<any> window).courseware.getData;
getData((data) => {
//data 就是云端获取的数据,也就是setData方法存到云端的那个obj
//模板开发者需要根据数据,依次填写到表单的相应位置,方便用户二次修改编辑
});
```
### 开发展示页面(play/)
展示页面主要是呈现模板,通过H5技术,实现多样化的交互与展示方式。
展示页面更简单,开发者可以运用各种技术,实现Web端可以实现的任何效果,包括2D、3D、动画、游戏等各种场景,把表单配置的数据获取到,用于渲染相对应的页面即可:
* getData 接口,用于当点击修改的时候将配置的数据从云端获取下来。
此方法是一个异步的方法,接收两个必要参数
> callback: 回调函数, 回调函数里会得到云端保存的数据
> t_name: 模板名称
一般使用例子如下:
```
// ts语法,不能直接使用js的window对象自定义方法
const getData = (<any> window).courseware.getData;
getData((data) => {
//data 就是云端获取的数据,也就是setData方法存到云端的那个obj
//模板开发者需要根据数据来渲染或控制展示页面的呈现,达到模板的互动目的
});
```
### 互动课件
通过H5的交互方式,我们可以很轻松的制作在线的互动课件,使老师端与学生端实现联动,使在线课堂更具有交互性。
* onEvent 定义事件:用于自定义同步事件,配合多端互动使用,与sendEvent方法配合使用,用于监听多端发送的同步事件
参数
> evtName : 自定义事件的名称
> callback : 回调函数,回调函数里会得到传过来的数据
使用例子:
```
const cw = (<any> window).courseware;
//订阅一个事件
cw.onEvent('testEvent', (data,next) => {
console.log(data);
//处理事件的同步逻辑
//在逻辑处理完之后一定要执行next方法,用于解锁事件队列
next();
});
```
* sendEvent 发送事件:用于自定义同步事件,配合多端互动使用,与onEvent方法配合使用,用于对端发送同步事件
参数
> evtName : 自定义事件的名称
> data : 传递的参数
使用例子:
```
const cw = (<any> window).courseware;
//发送事件
//这样,所有端(教师、学生) 都会触发 testEvent 方法
cw.sendEvent('testEvent', 'Hello world');
```
* storeAspect 存储切面数据: 课件的切面状态数据;互动课件需要每一个开发者设计切面状态,用于学生进入已经进行的课件,恢复课件同步。例如老师讲图片轮播到第四页,这个时候学生进入教师,要恢复到第四页,才能跟老师同步上课。
参数
> data : 保存的数据,一个JSON对象
使用例子:
```
const cw = (<any> window).courseware;
//存储切面数据,用于学生进入教室,同步课堂信息等
cw.storeAspect({page: 5});
```
* getAspect 获取切面数据: 课件的切面状态数据;互动课件需要每一个开发者设计切面状态,用于学生进入已经进行的课件,恢复课件同步。例如老师讲图片轮播到第四页,这个时候学生进入教师,要恢复到第四页,才能跟老师同步上课。
参数
> callback : 获取切面数据的回调函数
使用例子:
```
const cw = (<any> window).courseware;
//存储切面数据,用于学生进入教室,同步课堂信息等
cw.getAspect(function(aspect){
//恢复切面状态的逻辑
});
```
* 补充项
1) 有时候我们在实现模板效果的时候,需要一些基本的信息,比如教室信息、当前用户信息等等,例如,老师会显示某个按钮,而学生不显示,我们可以用如下方式获取教室信息;后续大部分静态信息都会完善到这个对象里
```
//获取教室信息,值得注意的是获取这个信息一定要再 getData方法之后,或者确保页面完成之后
getData((data, aspect) => {
let airClassInfo = window["air"].airClassInfo;
console.log(airClassInfo);
});
```
2) 互动课件的 getData 方法的回调函数里多返回了一个切面参数,类似如下:
```
const getData = (<any> window).courseware.getData;
getData((data, aspect) => {
//data 就是云端获取的数据,也就是setData方法存到云端的那个obj
//aspect 切面参数,用于恢复页面的状态
//模板开发者需要根据数据来渲染或控制展示页面的呈现,达到模板的互动目的
});
```
3) 一些必要的内置事件,通过监听这些事件,我们可以实现一些相关的功能
* userchange 事件,用来监听教室内部的人员变动情况,例如某人进入,某人退出都会触发此事件
示例:
```
const cw = (<any> window).courseware;
//订阅一个事件
cw.onEvent('userchange', (data,next) => {
//data的结构如下
/*{
* id: '变动用户的ID',
* connected: true/false, true: 连接的,false:d断开的
* status: 'connect/reconnect', connect:新建连接,reconnect:重新连接;这个字段在断开连接的事件里是缺失的
* all_user: [] 这个是现有的用户列表
*}
*/
console.log(data);
//处理事件的同步逻辑
//在逻辑处理完之后一定要执行next方法,用于解锁事件队列
next();
});
```
4) 测试互动课件
我们在本地开发中,无法模拟线上老师和学生互动的交互场景,所以提供了一套开发者测试的账号,如下:
测试地址:http://staging-ac.ireadabc.com/
老师用户名/密码:devtea / 1
学生用户名/密码: 学生1(13877777711 / 1) 学生2(13877777712 / 1)
测试方法:
1、首先开发者发布完模板之后,在制作课件的菜单下用这个模板制作一个课件
2、在本地打开两个浏览器窗口 一个登陆老师用户,另一个登陆学生用户
3、老师用户进去之后,就会有很多课件,这个时候双击自己制作的课件,学生的窗口就会同步的打开课件了
4、测试自己的交互事件,看看老师端和学生端是否是自己想要的展示效果
### 补充方法
在模板的编辑或展示过程中,还会经常遇到如下两个场景,特提供针对性的解决办法
1) 表单录入往往需要上传图片、音视频等多媒体文件,所以脚手架内置如下方法,用于获取一个上传到云端的接口方法
```
const uploadUrl = (<any> window).courseware.uploadUrl;
const uploadData = (<any> window).courseware.uploadData;
//例如用于NG-ZORRO的上传组件则如下写法:
<nz-upload class="p-image-uploader" [nzDisabled]="disableUpload"
[nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl" <!-- 注意这里 -->
[nzData]="uploadData" <!-- 注意这里 -->
(nzChange)="handleChange($event)">
</nz-upload>
```
2) 在展示页面加载完成的时候,需要调用一下下面的方法,用于释放切换课件的遮罩层
```
//此方法为固定写法,
//其中t_name为模板名称,obj是云端存储的配置数据
window["air"].hideAirClassLoading(t_name,obj);
```
## 打包发布
模板开发完成之后,要推送到云平台上使用则需要进行打包发布操作
```
npm run publish
```
在项目根目录下执行上述命令,则在 ./publish 目录下生产一个 .zip的压缩包,此时打开云平台
http://staging-teach.ireadabc.com/
点击“模板管理” 菜单,找到对应的模板卡片,点击“发布”按钮,在弹出的对话框中选中压缩包,然后点击“确定”,上传完成后,则发布就成功了
\ No newline at end of file
...@@ -3,13 +3,9 @@ ...@@ -3,13 +3,9 @@
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"ng-one": { "ng-template-generator": {
"projectType": "application", "projectType": "application",
"schematics": { "schematics": {},
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
...@@ -17,39 +13,26 @@ ...@@ -17,39 +13,26 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"outputPath": "dist", "outputPath": "dist/ng-template-generator",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": "src/polyfills.ts", "polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"aot": false, "aot": true,
"assets": [ "assets": [
"src/favicon.ico", "src/favicon.ico",
"src/assets", "src/assets",
{ "glob": "**/*", "input": "src/assets/libs/service-worker/", "output": "/" },
{ {
"glob": "**/*", "glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/" "output": "/assets/"
},
{
"glob": "**/*",
"input": "./dist/game/",
"output": "/assets/cocos/"
} }
], ],
"styles": [ "styles": [
"src/styles.scss", "node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css", "src/styles.css"
"./node_modules/font-awesome/css/font-awesome.css",
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"./node_modules/animate.css/animate.min.css"
], ],
"scripts": [ "scripts": []
"src/assets/libs/audio-recorder/lame.min.js",
"src/assets/libs/audio-recorder/worker.js",
"src/assets/libs/audio-recorder/recorder.js"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
...@@ -64,28 +47,39 @@ ...@@ -64,28 +47,39 @@
"sourceMap": false, "sourceMap": false,
"extractCss": true, "extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true,
"extractLicenses": true, "extractLicenses": true,
"vendorChunk": false, "vendorChunk": false,
"buildOptimizer": true "buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
} }
} }
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"options": { "options": {
"browserTarget": "ng-one:build" "browserTarget": "ng-template-generator:build"
}, },
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "ng-one:build:production" "browserTarget": "ng-template-generator:build:production"
} }
} }
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"browserTarget": "ng-one:build" "browserTarget": "ng-template-generator:build"
} }
}, },
"test": { "test": {
...@@ -100,7 +94,8 @@ ...@@ -100,7 +94,8 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
"src/styles.css"
], ],
"scripts": [] "scripts": []
} }
...@@ -122,15 +117,19 @@ ...@@ -122,15 +117,19 @@
"builder": "@angular-devkit/build-angular:protractor", "builder": "@angular-devkit/build-angular:protractor",
"options": { "options": {
"protractorConfig": "e2e/protractor.conf.js", "protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "ng-one:serve" "devServerTarget": "ng-template-generator:serve"
}, },
"configurations": { "configurations": {
"production": { "production": {
"devServerTarget": "ng-one:serve:production" "devServerTarget": "ng-template-generator:serve:production"
}
} }
} }
} }
} }
}}, },
"defaultProject": "ng-one" "defaultProject": "ng-template-generator",
"cli": {
"analytics": "0bdaa560-1d2a-46f5-b14c-1f80decb439e"
}
} }
\ No newline at end of file
...@@ -66,7 +66,7 @@ const runSpawn = async function (){ ...@@ -66,7 +66,7 @@ const runSpawn = async function (){
ls.on('close', (code) => { ls.on('close', (code) => {
console.log(`child process exited with code ${code}`); console.log(`child process exited with code ${code}`);
//要压缩的目录 //要压缩的目录
let zippath = path.resolve(__dirname,"../dist"); let zippath = path.resolve(__dirname,"../dist", pkg.name);
//压缩包的存放目录 //压缩包的存放目录
let date = new Date(); let date = new Date();
let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss"); let zipname = pkg.name+"_"+date.Format("yyyyMMdd hh-mm-ss");
...@@ -112,4 +112,3 @@ exec(); ...@@ -112,4 +112,3 @@ exec();
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2,78 +2,56 @@ ...@@ -2,78 +2,56 @@
"name": "ng-template-generator", "name": "ng-template-generator",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"start": "ng serve --host=0.0.0.0", "start": "ng serve",
"build": "ng build --build--optimizer --aot --base-href /JGT/v3/", "build": "ng build --build--optimizer --aot --base-href /JGT/v3/",
"publish": "node ./bin/publish.js" "publish": "node ./bin/publish.js",
"ng": "ng",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^7.2.10", "@angular/animations": "~9.0.2",
"@angular/cdk": "^7.2.2", "@angular/common": "~9.0.2",
"@angular/common": "^7.2.10", "@angular/compiler": "~9.0.2",
"@angular/compiler": "^7.2.10", "@angular/core": "~9.0.2",
"@angular/core": "^7.2.10", "@angular/forms": "~9.0.2",
"@angular/flex-layout": "^7.0.0-beta.24", "@angular/platform-browser": "~9.0.2",
"@angular/forms": "^7.2.10", "@angular/platform-browser-dynamic": "~9.0.2",
"@angular/http": "^7.2.10", "@angular/router": "~9.0.2",
"@angular/material": "^7.2.2", "@fortawesome/angular-fontawesome": "^0.6.0",
"@angular/platform-browser": "^7.2.10", "@fortawesome/fontawesome-svg-core": "^1.2.27",
"@angular/platform-browser-dynamic": "^7.2.10", "@fortawesome/free-regular-svg-icons": "^5.12.1",
"@angular/platform-server": "^7.2.10", "@fortawesome/free-solid-svg-icons": "^5.12.1",
"@angular/router": "^7.2.10", "@tweenjs/tween.js": "~18.5.0",
"@tweenjs/tween.js": "^17.3.0", "ali-oss": "^6.5.1",
"ali-oss": "^6.0.0", "compressing": "^1.5.0",
"angular-bootstrap-colorpicker": "^3.0.32", "ng-zorro-antd": "^8.5.2",
"angular-cropperjs": "^1.0.1", "rxjs": "~6.5.4",
"angular2-draggable": "^2.1.9",
"angular2-fontawesome": "^5.2.1",
"angular2-uuid": "^1.1.1",
"angularx-qrcode": "^1.5.3",
"animate.css": "^3.7.0",
"bootstrap": "^4.1.1",
"browser-image-compression": "^1.0.5",
"compressing": "^1.4.0",
"core-js": "^2.6.1",
"cropperjs": "1.4.1",
"css-element-queries": "^1.0.2",
"decimal.js": "^10.0.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"install": "^0.12.2",
"karma-cli": "^2.0.0",
"lodash": "^4.17.10",
"nedb": "^1.8.0",
"ng-lottie": "^0.3.1",
"ng-zorro-antd": "^7.2.0",
"ngx-color-picker": "^9.0.0",
"node-sass": "^4.14.0",
"npm": "^6.5.0",
"rxjs": "^6.3.3",
"rxjs-compat": "^6.3.3",
"rxjs-tslint": "^0.1.6",
"spark-md5": "^3.0.0", "spark-md5": "^3.0.0",
"webpack": "^4.28.2", "tslib": "^1.10.0",
"zone.js": "^0.8.26" "zone.js": "~0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.11.4", "@angular-devkit/build-angular": "~0.900.3",
"@angular/cli": "^7.2.10", "@angular/cli": "~9.0.3",
"@angular/compiler-cli": "^7.2.10", "@angular/compiler-cli": "~9.0.2",
"@angular/language-service": "^7.2.10", "@angular/language-service": "~9.0.2",
"@types/jasmine": "^3.3.5", "@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^10.12.18", "@types/node": "^12.11.1",
"codelyzer": "^4.5.0", "codelyzer": "^5.1.2",
"jasmine-core": "^3.3.0", "jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "^4.2.1", "jasmine-spec-reporter": "~4.2.1",
"karma": "^3.1.4", "karma": "~4.3.0",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.0.0", "karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "^2.0.1", "karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0", "karma-jasmine-html-reporter": "^1.4.2",
"protractor": "^5.4.2", "protractor": "~5.4.3",
"ts-node": "~5.0.1", "ts-node": "~8.3.0",
"tslint": "^5.12.0", "tslint": "~5.18.0",
"typescript": "3.1.1" "typescript": "~3.7.5"
} }
} }
import { ErrorHandler } from '@angular/core';
export class MyErrorHandler implements ErrorHandler {
handleError(error) {
console.log(error.stack);
(<any> window).courseware.sendErrorLog(error);
}
}
\ No newline at end of file
...@@ -5,12 +5,12 @@ import { Component , OnInit} from '@angular/core'; ...@@ -5,12 +5,12 @@ import { Component , OnInit} from '@angular/core';
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent implements OnInit{ export class AppComponent implements OnInit {
type = 'play'; type = 'play';
constructor() { constructor() {
let tp = this.getQueryString("type"); const tp = this.getQueryString('type');
if (tp){ if (tp) {
this.type = tp; this.type = tp;
} }
} }
......
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule, ErrorHandler } from '@angular/core';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
import { NzButtonModule } from 'ng-zorro-antd/button';
import {Angular2FontawesomeModule} from 'angular2-fontawesome/angular2-fontawesome';
import { AppComponent } from './app.component'; import {MyErrorHandler} from './MyError';
import { FormComponent } from './form/form.component';
import { PlayComponent } from "./play/play.component";
// import { ColorPickerModule } from 'ngx-color-picker';
import { LessonTitleConfigComponent } from './common/lesson-title-config/lesson-title-config.component'; import { AppComponent } from './app.component';
import { AudioRecorderComponent } from './common/audio-recorder/audio-recorder.component'; import { NgZorroAntdModule, NZ_I18N, zh_CN } from 'ng-zorro-antd';
import { PlayerContentWrapperComponent } from './common/player-content-wrapper/player-content-wrapper.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BackgroundUploadComponent } from './common/background-upload/background-upload.component'; import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
/** 配置 angular i18n **/
import { registerLocaleData } from '@angular/common'; import { registerLocaleData } from '@angular/common';
import zh from '@angular/common/locales/zh'; import zh from '@angular/common/locales/zh';
import {UploadImageWithPreviewComponent} from "./common/upload-image-with-preview/upload-image-with-preview.component"; import {FormComponent} from './form/form.component';
import {BackgroundImagePipe} from "./pipes/background-image.pipe"; import {PlayComponent} from './play/play.component';
import {UploadVideoComponent} from "./common/upload-video/upload-video.component"; import {LessonTitleConfigComponent} from './common/lesson-title-config/lesson-title-config.component';
import {ResourcePipe} from "./pipes/resource.pipe"; import {BackgroundImagePipe} from './pipes/background-image.pipe';
import {TimePipe} from "./pipes/time.pipe"; import {UploadImageWithPreviewComponent} from './common/upload-image-with-preview/upload-image-with-preview.component';
import {CustomHotZoneComponent} from "./common/custom-hot-zone/custom-hot-zone.component"; import {PlayerContentWrapperComponent} from './common/player-content-wrapper/player-content-wrapper.component';
import {CustomHotZoneComponent} from './common/custom-hot-zone/custom-hot-zone.component';
import {BackgroundUploadComponent} from './common/background-upload/background-upload.component';
import {UploadVideoComponent} from './common/upload-video/upload-video.component';
import {TimePipe} from './pipes/time.pipe';
import {ResourcePipe} from './pipes/resource.pipe';
import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.component';
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons';
registerLocaleData(zh); registerLocaleData(zh);
@NgModule({ @NgModule({
...@@ -37,28 +37,32 @@ registerLocaleData(zh); ...@@ -37,28 +37,32 @@ registerLocaleData(zh);
LessonTitleConfigComponent, LessonTitleConfigComponent,
AudioRecorderComponent, AudioRecorderComponent,
UploadImageWithPreviewComponent, UploadImageWithPreviewComponent,
BackgroundUploadComponent,
BackgroundImagePipe, BackgroundImagePipe,
ResourcePipe, ResourcePipe,
TimePipe, TimePipe,
UploadVideoComponent, UploadVideoComponent,
CustomHotZoneComponent, CustomHotZoneComponent,
PlayerContentWrapperComponent, PlayerContentWrapperComponent
BackgroundUploadComponent
], ],
imports: [ imports: [
BrowserModule,
NgZorroAntdModule,
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
BrowserAnimationsModule, BrowserAnimationsModule,
BrowserModule, FontAwesomeModule,
Angular2FontawesomeModule, ReactiveFormsModule
NgZorroAntdModule,
//ColorPickerModule
], ],
/** 配置 ng-zorro-antd 国际化(文案 及 日期) **/ providers: [
providers : [ {provide: ErrorHandler, useClass: MyErrorHandler},
{ provide: NZ_I18N, useValue: zh_CN } { provide: NZ_I18N, useValue: zh_CN }
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule {
constructor(library: FaIconLibrary) {
library.addIconPacks(fas, far);
}
}
<div class="d-flex"> <div class="d-flex">
<div class="p-btn-record d-flex"> <div class="p-btn-record d-flex">
<div <div class="btn-clear" style="cursor: pointer" (click)="onBtnClearAudio()" *ngIf="withRmBtn && (audioUrl || audioBlob)">
class="btn-clear" <fa-icon icon="times"></fa-icon>
(click)="onBtnClearAudio()"
*ngIf="withRmBtn && (audioUrl || audioBlob)"
>
<fa name="close"></fa>
</div> </div>
<div <div class="btn-record" *ngIf="type===Type.RECORD && !isUploading"
class="btn-record"
*ngIf="type === Type.RECORD && !isUploading"
[class.p-recording]="isRecording" [class.p-recording]="isRecording"
(click)="onBtnRecord()" (click)="onBtnRecord()">
> <fa-icon icon="microphone"></fa-icon>
<i nz-icon nzType="audio" nzTheme="outline"></i>
Record Audio Record Audio
</div> </div>
<nz-upload <nz-upload
[nzAccept]="'.mp3'" [nzAccept] = "'.mp3'"
[nzShowUploadList]="false" [nzShowUploadList]="false"
[nzAction]="uploadUrl" [nzAction]="uploadUrl"
[nzData]="uploadData" [nzData]="uploadData"
(nzChange)="handleChange($event)" (nzChange)="handleChange($event)">
>
<div <div class="btn-upload" [ngClass]="{'has-clear': withRmBtn && (audioUrl || audioBlob)}" *ngIf="type===Type.UPLOAD && !isUploading">
class="btn-upload ng-star-inserted" <fa-icon icon="upload"></fa-icon>
[ngClass]="{ 'has-clear': withRmBtn && (audioUrl || audioBlob) }"
*ngIf="type === Type.UPLOAD && !isUploading"
>
<i nz-icon nzType="cloud-upload" nzTheme="outline"></i>
Upload Audio Upload Audio
</div> </div>
</nz-upload> </nz-upload>
<div class="p-upload-progress-bg" *ngIf="isUploading"> <div class="p-upload-progress-bg" *ngIf="isUploading">
<div class="i-bg" [style.width]="progress + '%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<i nz-icon nzType="loading" nzTheme="outline"></i> <fa-icon icon="cloud-upload-alt"></fa-icon>
Uploading... Uploading...
</div> </div>
</div> </div>
<div
*ngIf="audioUrl && needRemove; then truthyTemplate; else falsyTemplate"
></div>
<ng-template #truthyTemplate> <div *ngIf="audioUrl && needRemove; then truthyTemplate else falsyTemplate"></div>
<ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()"> <div class="btn-delete" (click)="onBtnDeleteAudio()">
<i nz-icon nzType="close" nzTheme="outline"></i> <fa-icon icon="close"></fa-icon>
</div> </div>
</ng-template> </ng-template>
<ng-template #falsyTemplate> <ng-template #falsyTemplate>
<div class="btn-switch" (click)="onBtnSwitchType()"> <div class="btn-switch" (click)="onBtnSwitchType()">
<i nz-icon nzType="setting" nzTheme="outline"></i> <fa-icon icon="cog"></fa-icon>
</div> </div>
</ng-template> </ng-template>
</div> </div>
<div <div class="p-progress ml-2" (click)="onBtnPlay()" *ngIf="audioUrl || audioBlob">
class="p-progress ml-2" <nz-progress [nzPercent]="percent" [nzWidth]="30" [nzFormat]="progressText"
(click)="onBtnPlay()" nzType="circle"></nz-progress>
*ngIf="audioUrl || audioBlob" <div class="p-btn-play" [style.left]="isPlaying?'8px':''">
> <fa-icon [icon]="playIcon"></fa-icon>
<nz-progress
[nzPercent]="percent"
[nzWidth]="30"
[nzFormat]="progressText"
nzType="circle"
></nz-progress>
<div class="p-btn-play" [style.left]="isPlaying ? '8px' : ''">
<i nz-icon nzType="caret-right" nzTheme="outline"></i>
</div> </div>
</div> </div>
</div> </div>
.d-flex{
display: flex;
}
.p-btn-record { .p-btn-record {
font-size: 0.9rem; font-size: 0.9rem;
color: #555; color: #555;
...@@ -88,7 +91,6 @@ ...@@ -88,7 +91,6 @@
.p-progress { .p-progress {
margin-top: 2px; margin-top: 2px;
margin-left: 5px;
position: relative; position: relative;
line-height: 26px; line-height: 26px;
.p-btn-play { .p-btn-play {
...@@ -103,6 +105,3 @@ ...@@ -103,6 +105,3 @@
line-height: 33px; line-height: 33px;
} }
.d-flex{
display: flex;
}
\ No newline at end of file
...@@ -19,10 +19,11 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -19,10 +19,11 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
isUploading = false; isUploading = false;
type = Type.UPLOAD; // record | upload type = Type.UPLOAD; // record | upload
Type = Type; Type = Type;
@Input()
withRmBtn = false; withRmBtn = false;
uploadUrl uploadUrl;
uploadData uploadData;
@Input() @Input()
needRemove = false; needRemove = false;
...@@ -32,7 +33,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -32,7 +33,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
@Input() @Input()
set audioUrl(url) { set audioUrl(url) {
this._audioUrl = url this._audioUrl = url;
if (url) { if (url) {
this.audio.src = this._audioUrl; this.audio.src = this._audioUrl;
this.audio.load(); this.audio.load();
...@@ -150,6 +151,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -150,6 +151,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
onBtnSwitchType() { onBtnSwitchType() {
} }
onBtnClearAudio() { onBtnClearAudio() {
this.audioUrl = null;
this.audioRemoved.emit(); this.audioRemoved.emit();
} }
...@@ -192,6 +194,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -192,6 +194,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
return true; return true;
} }
beforeUpload = (file: File) => { beforeUpload = (file: File) => {
this.audioUrl = null; this.audioUrl = null;
if (!this.checkSelectFile(file)) { if (!this.checkSelectFile(file)) {
return false; return false;
...@@ -202,11 +205,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -202,11 +205,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
uploadSuccess = (url) => { uploadSuccess = (url) => {
this.nzMessageService.info('Upload Success'); this.nzMessageService.info('Upload Success');
this.isUploading = false; this.isUploading = false;
if(typeof url == "string"){ this.audioUrl = url;
this.audioUrl = url
}else{
this.audioUrl = url.url
}
} }
uploadFailure = (err, file) => { uploadFailure = (err, file) => {
this.isUploading = false; this.isUploading = false;
......
...@@ -31,8 +31,8 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges { ...@@ -31,8 +31,8 @@ export class CustomHotZoneComponent implements OnInit, OnDestroy, OnChanges {
@Input() hotZoneArr = null; @Input() hotZoneArr = null;
@Output() save = new EventEmitter(); @Output() save = new EventEmitter();
@ViewChild('canvas') canvas: ElementRef; @ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap') wrap: ElementRef; @ViewChild('wrap', {static: true }) wrap: ElementRef;
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize(event) { onResize(event) {
this.g_winResizeEventStream.next(); this.g_winResizeEventStream.next();
......
<div class="title-config"> <div class="title-config">
<div class="title-wrap"> <div class="title-wrap">
...@@ -7,9 +8,10 @@ ...@@ -7,9 +8,10 @@
<nz-select class="ml-1" style="width: 120px;" [(ngModel)]="__fontFamily" <nz-select class="ml-1" style="width: 120px;" [(ngModel)]="__fontFamily"
(ngModelChange)="onChangeFontFamily($event)" (ngModelChange)="onChangeFontFamily($event)"
nzPlaceHolder="Font Family" nzPlaceHolder="Font Family"
[nzDropdownMatchSelectWidth]="false" [nzDropdownMatchSelectWidth]="false">
> <nz-option [nzValue]="font" nzCustomContent [nzLabel]="font" *ngFor="let font of fontFamilyList">
<nz-option [nzValue]="font" [nzLabel]="font" *ngFor="let font of fontFamilyList"></nz-option> <span [ngStyle]="{'font-family': font}" >{{font}}</span>
</nz-option>
</nz-select> </nz-select>
<nz-select class="ml-1" style="width: 110px;" [(ngModel)]="__fontSize" <nz-select class="ml-1" style="width: 110px;" [(ngModel)]="__fontSize"
(ngModelChange)="onChangeFontSize()" (ngModelChange)="onChangeFontSize()"
...@@ -19,28 +21,33 @@ ...@@ -19,28 +21,33 @@
<div class="p-divider"></div> <div class="p-divider"></div>
<div class="i-tool-font-btn d-flex mr-2"> <div class="i-tool-font-btn d-flex mr-2">
<div class="position-relative fa-icon" (click)="onChangeBold()"> <div class="position-relative fa-icon" (click)="onChangeBold()">
<div class="fa fa-bold"></div> <!-- <div class="fa fa-bold"></div>-->
<fa-icon icon="bold"></fa-icon>
</div> </div>
</div> </div>
<div class="i-tool-font-btn d-flex mr-2"> <div class="i-tool-font-btn d-flex mr-2">
<div class="position-relative fa-icon" (click)="onChangeItalic()"> <div class="position-relative fa-icon" (click)="onChangeItalic()">
<div class="fa fa-italic"></div> <!-- <div class="fa fa-italic"></div>-->
<fa-icon icon="italic"></fa-icon>
</div> </div>
</div> </div>
<div class="i-tool-font-btn d-flex mr-2"> <div class="i-tool-font-btn d-flex mr-2">
<div class="position-relative fa-icon" (click)="onChangeUnderline()"> <div class="position-relative fa-icon" (click)="onChangeUnderline()">
<div class="fa fa-underline"></div> <!-- <div class="fa fa-underline"></div>-->
<fa-icon icon="underline"></fa-icon>
</div> </div>
</div> </div>
<div class="i-tool-font-btn d-flex"> <div class="i-tool-font-btn d-flex">
<div class="position-relative fa-icon" (click)="onChangeStrikethrough()"> <div class="position-relative fa-icon" (click)="onChangeStrikethrough()">
<div class="fa fa-strikethrough"></div> <!-- <div class="fa fa-strikethrough"></div>-->
<fa-icon icon="strikethrough"></fa-icon>
</div> </div>
</div> </div>
<div class="p-divider"></div> <div class="p-divider"></div>
<div class="i-tool-font-color d-flex"> <div class="i-tool-font-color d-flex">
<div class="position-relative i-left flex-fill" (click)="onChangeFontColor($event)"> <div class="position-relative i-left flex-fill" (click)="onChangeFontColor($event)">
<div class="fa fa-font"></div> <!-- <div class="fa fa-font"></div>-->
<fa-icon icon="palette"></fa-icon>
<div class="i-color" [style.background-color]="__fontColor"></div> <div class="i-color" [style.background-color]="__fontColor"></div>
</div> </div>
<div class="i-dropdown-menu" nzPlacement="bottom" <div class="i-dropdown-menu" nzPlacement="bottom"
...@@ -51,14 +58,14 @@ ...@@ -51,14 +58,14 @@
</div> </div>
<div class="p-divider"></div> <div class="p-divider"></div>
<div style="background: #fff;display: block;"> <div style="background: #fff;display: block;">
<div class="position-relative" (click)="onChangeStrikethrough()"> <div class="position-relative">
<app-audio-recorder [audioUrl]="titleObj && titleObj.audio_url" (audioUploaded)="titleAudioUploaded($event)"></app-audio-recorder> <app-audio-recorder [audioUrl]="titleObj && titleObj.audio_url" (audioUploaded)="titleAudioUploaded($event)"></app-audio-recorder>
</div> </div>
</div> </div>
</div> </div>
<div class="width-100 d-flex"> <div class="width-100 d-flex">
<iframe #titleEl frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe> <iframe #titleEl id="titleContentEgret" frameborder="0" style="overflow: hidden;width: 100%; height:48px; margin: 0; padding: 0;"></iframe>
</div> </div>
</div> </div>
...@@ -76,37 +83,11 @@ ...@@ -76,37 +83,11 @@
<ng-container *ngIf="withIcon">
<div class="row type-row">
课程类型:
<nz-radio-group [(ngModel)]="titleObj && titleObj.type" (ngModelChange)="typeChange($event)">
<label nz-radio nzValue="a">单数课</label>
<label nz-radio nzValue="b">双数课</label>
<label nz-radio nzValue="c">复习课</label>
</nz-radio-group>
</div>
</ng-container>
</div>
</div>
<ng-container *ngIf="withIcon">
<div class="title-icons">
<div class="icons-list">
<nz-checkbox-wrapper style="width: 100%;clear:both" (nzOnChange)="iconsChanges($event)">
<div [class]="'icon-item icon-'+i" *ngFor="let i of groupIconsCount[titleObj.type];">
<div class="img-box">
<nz-badge class="icon-badge" [nzCount]="titleObj && titleObj.icons && titleObj.icons.indexOf(i) + 1">
<img [src]="'assets/title-icons/'+titleObj.type+'/icon-'+i+'.png'" alt="">
</nz-badge>
</div>
<label nz-checkbox [nzValue]="i" [ngModel]="titleObj && titleObj.icons && titleObj.icons.indexOf(i) > -1"></label>
</div>
</nz-checkbox-wrapper>
</div>
</div>
</ng-container>
</div> </div>
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
.title-config { .title-config {
.letter-wrap{ .letter-wrap{
...@@ -11,37 +11,64 @@ ...@@ -11,37 +11,64 @@
.type-row{ .type-row{
margin: 0;padding-top: 1rem; margin: 0;padding-top: 1rem;
} }
.icon-item{ }
margin-right: 16px;
float: left; // BerlinSansFB
width: 45px; @font-face {
height: 75px; font-family: 'BRLNSDB';
display: flex; src: url("../../../assets/default/font/BerlinSansFB/BRLNSDB_1.TTF") ;
justify-content: center; }
align-items: center;
position: relative; @font-face {
.icon-badge{ font-family: 'BRLNSB';
position: absolute; src: url("../../../assets/default/font/BerlinSansFB/BRLNSB_1.TTF") ;
top: 0; }
right: 0;
} @font-face {
.img-box{ font-family: 'BRLNSR';
top: 0; src: url("../../../assets/default/font/BerlinSansFB/BRLNSR_1.TTF") ;
position: absolute; }
width: 45px;
height: 50px; // CenturyGothic
display: flex; @font-face {
justify-content: center; font-family: 'GOTHIC';
align-items: center; src: url("../../../assets/default/font/CenturyGothic/GOTHIC_1.TTF") ;
img{ }
max-width: 100%;
} @font-face {
} font-family: 'GOTHICB';
label{ src: url("../../../assets/default/font/CenturyGothic/GOTHICB_1.TTF") ;
position: absolute; }
bottom: 0;
} @font-face {
} font-family: 'GOTHICBI';
src: url("../../../assets/default/font/CenturyGothic/GOTHICBI_1.TTF") ;
}
@font-face {
font-family: 'GOTHICI';
src: url("../../../assets/default/font/CenturyGothic/GOTHICI_1.TTF") ;
}
// MMTextBook
@font-face {
font-family: 'MMTextBook';
src: url("../../../assets/default/font/MMTextBook/MMTextBook.otf") ;
}
@font-face {
font-family: 'MMTextBook-Bold';
src: url("../../../assets/default/font/MMTextBook/MMTextBook-Bold.otf") ;
}
@font-face {
font-family: 'MMTextBook-BoldItalic';
src: url("../../../assets/default/font/MMTextBook/MMTextBook-BoldItalic.otf") ;
}
@font-face {
font-family: 'MMTextBook-Italic';
src: url("../../../assets/default/font/MMTextBook/MMTextBook-Italic.otf") ;
} }
@mixin tool-btn { @mixin tool-btn {
...@@ -55,15 +82,38 @@ ...@@ -55,15 +82,38 @@
color: #555; color: #555;
} }
.p-title-box { .d-flex{
.p-title { display: flex;
}
.position-relative {
position: relative;
}
.flex-fill {
-webkit-box-flex: 1;
flex: 1 1 auto;
justify-content: center;
display: flex;
}
.i-dropdown-menu{
width: 15px;
font-size: 10px;
border-left: 1px solid #ddd;
display: -webkit-box;
display: flex;
-webkit-box-align: center;
align-items: center;
flex: 0
}
.p-title-box .p-title {
font-size: 20px; font-size: 20px;
} }
input { .p-title-box input {
width: 300px; width: 300px;
margin-left: 10px; margin-left: 10px;
} }
}
.p-content { .p-content {
border: 1px solid #ddd; border: 1px solid #ddd;
...@@ -85,33 +135,31 @@ ...@@ -85,33 +135,31 @@
align-items: center; align-items: center;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
// save
.i-tool-save {
@include tool-btn(); }
// save
.i-tool-save {
//@include tool-btn();
color: white; color: white;
} }
.i-tool-save:disabled { .i-tool-save:disabled {
color: #555; color: #555;
} }
// font-size // font-size
.i-tool-font-size { .i-tool-font-size {
@include tool-btn(); //@include tool-btn();
width: 37px; width: 37px;
& > span { }
position: absolute; .i-tool-font-size:hover {
top: -5px;
right: 5px;
}
}
.i-tool-font-size:hover {
color: black; color: black;
border-color: #bbb; border-color: #bbb;
} }
// font-color // font-color
.i-tool-font-color, .i-tool-font-btn { .i-tool-font-color, .i-tool-font-btn {
border: 1px solid #ddd; border: 1px solid #ddd;
//padding: 3px 7px; //padding: 3px 7px;
border-radius: 6px; border-radius: 6px;
...@@ -155,20 +203,20 @@ ...@@ -155,20 +203,20 @@
transform: scale(0.6); transform: scale(0.6);
} }
} }
} }
.i-tool-font-btn{ .i-tool-font-btn{
width: 31px; width: 31px;
} }
.fa-icon{ .fa-icon{
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
} }
// bg-color // bg-color
.i-tool-bg-color { .i-tool-bg-color {
@include tool-btn(); @include tool-btn();
padding: 0 9px; padding: 0 9px;
::ng-deep > span { ::ng-deep > span {
...@@ -183,17 +231,14 @@ ...@@ -183,17 +231,14 @@
background-color: white; background-color: white;
margin-left: 10px; margin-left: 10px;
} }
} }
// horizontal-center // horizontal-center
.i-tool-horizontal-center { .i-tool-horizontal-center {
@include tool-btn(); @include tool-btn();
width: 37px; width: 37px;
}
} }
.p-box { .p-box {
width: 1280px; width: 1280px;
height: 720px; height: 720px;
...@@ -203,9 +248,7 @@ ...@@ -203,9 +248,7 @@
overflow: hidden; overflow: hidden;
} }
.p-sentence {
@include k-no-select();
}
.p-animation-index-box { .p-animation-index-box {
.i-animation-index { .i-animation-index {
...@@ -278,7 +321,6 @@ ...@@ -278,7 +321,6 @@
::ng-deep .ant-radio-button-wrapper { ::ng-deep .ant-radio-button-wrapper {
padding: 0 10px; padding: 0 10px;
@include k-no-select();
} }
.i-toolbox { .i-toolbox {
...@@ -309,7 +351,6 @@ ...@@ -309,7 +351,6 @@
cursor: pointer; cursor: pointer;
text-align: left; text-align: left;
display: flex; display: flex;
@include k-no-select();
} }
.i-active { .i-active {
background-color: antiquewhite; background-color: antiquewhite;
......
import { import {
Component, Component,
ElementRef, ElementRef,
...@@ -10,6 +11,82 @@ import { ...@@ -10,6 +11,82 @@ import {
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
const editorTpl = `<html lang="en"><head><meta charset="utf-8">
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
<style>
@font-face{
font-family: 'BRLNSDB';
src: url("../../../assets/font/BRLNSDB.TTF") ;
}
@font-face{
font-family: 'BRLNSB';
src: url("../../../assets/font/BRLNSB.TTF") ;
}
@font-face{
font-family: 'BRLNSR';
src: url("../../../assets/font/BRLNSR.TTF") ;
}
@font-face{
font-family: 'GOTHIC';
src: url("../../../assets/font/GOTHIC.TTF") ;
}
@font-face{
font-family: 'GOTHICB';
src: url("../../../assets/font/GOTHICB.TTF") ;
}
@font-face{
font-family: 'GOTHICBI';
src: url("../../../assets/font/GOTHICBI.TTF") ;
}
@font-face{
font-family: 'GOTHICI';
src: url("../../../assets/font/GOTHICI.TTF") ;
}
@font-face{
font-family: 'MMTextBook';
src: url("../../../assets/font/MMTextBook.otf") ;
}
@font-face{
font-family: 'MMTextBook-Bold';
src: url("../../../assets/font/MMTextBook-Bold.otf") ;
}
@font-face{
font-family: 'MMTextBook-BoldItalic';
src: url("../../../assets/font/MMTextBook-BoldItalic.otf") ;
}
@font-face{
font-family: 'MMTextBook-Italic';
src: url("../../../assets/font/MMTextBook-Italic.otf") ;
}
html, body{
/*font-size: 30px;*/
}
body{
height:48px;
overflow: hidden;
margin: 0;
padding: 0 .5rem;
font-family: 'BRLNSB, BRLNSDB, BRLNSR, GOTHIC, GOTHICB, MMTextBook';
background: #FFF;
line-height: 48px;
}
</style>
</head>
<body>{{content}}</body>
</html>`;
@Component({ @Component({
selector: 'app-lesson-title-config', selector: 'app-lesson-title-config',
templateUrl: './lesson-title-config.component.html', templateUrl: './lesson-title-config.component.html',
...@@ -19,22 +96,45 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -19,22 +96,45 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
fontFamilyList = [ fontFamilyList = [
'Arial', 'Arial',
'ARBLI' 'BRLNSB',
'BRLNSDB',
'BRLNSR',
'GOTHIC',
'GOTHICB',
// "GOTHICBI",
// "GOTHICI",
'MMTextBook',
// "MMTextBook-Bold",
// "MMTextBook-Italic",
// "MMTextBook-BoldItalic",
]; ];
colorList = [ colorList = [
'#111111', '#000000',
'#ffffff', '#ffffff',
'#595959', '#595959',
'#0075c2', '#0075c2',
'#c61c1e', '#c61c1e',
'#9cbc3a' '#9cbc3a',
'#008000',
'#FF0000',
'#D2691E',
]; ];
MIN_FONT_SIZE = 1; MIN_FONT_SIZE = 1;
MAX_FONT_SIZE = 7; MAX_FONT_SIZE = 7;
isShowFontColorPane = false; isShowFontColorPane = false;
isShowBGColorPane = false; isShowBGColorPane = false;
fontSizeRange: number[]; fontSizeRange = [
// {name: '1号', value: 9},
// {name: '2号', value: 13},
// {name: '3号', value: 16},
// {name: '4号', value: 18},
// {name: '5号', value: 24},
// {name: '6号', value: 32},
];
editorContent = ''; editorContent = '';
...@@ -45,25 +145,17 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -45,25 +145,17 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
loopCnt = 0; loopCnt = 0;
maxLoops = 20; maxLoops = 20;
groupIconsCount = {
a: Array.from(Array(11).keys()), @ViewChild('titleEl', {static: true}) titleEl: ElementRef;
b: Array.from(Array(8).keys()),
c: Array.from(Array(8).keys()),
};
prevIcons = [];
prevType = '';
@ViewChild('titleEl') titleEl: ElementRef;
titleEW = null; titleEW = null;
@Input() @Input()
titleObj = { titleObj = {
type: 'a',
content: '', content: '',
icons: [],
audio_url: '' audio_url: ''
}; };
@Input()
withIcon = true;
@Output() @Output()
titleUpdated = new EventEmitter(); titleUpdated = new EventEmitter();
...@@ -84,16 +176,12 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -84,16 +176,12 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
let defObj = this.titleObj; let defObj = this.titleObj;
if (!vars.titleObj.currentValue) { if (!vars.titleObj.currentValue) {
defObj = { defObj = {
type: 'a',
content: '', content: '',
icons: [],
audio_url: '' audio_url: ''
}; };
} else { } else {
defObj = vars.titleObj.currentValue; defObj = vars.titleObj.currentValue;
} }
this.titleObj.icons = defObj.icons || [];
this.titleObj.type = defObj.type || 'a';
this.titleObj.content = defObj.content || ''; this.titleObj.content = defObj.content || '';
this.titleObj.audio_url = defObj.audio_url || ''; this.titleObj.audio_url = defObj.audio_url || '';
this.titleEW.document.body.innerHTML = this.titleObj.content; this.titleEW.document.body.innerHTML = this.titleObj.content;
...@@ -102,33 +190,23 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -102,33 +190,23 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
ngOnInit() { ngOnInit() {
if (!this.titleObj) { if (!this.titleObj) {
this.titleObj = { this.titleObj = {
type: 'a',
content: '', content: '',
icons: [],
audio_url: '' audio_url: ''
}; };
} }
this.titleObj.icons = this.titleObj.icons || [];
this.titleObj.type = this.titleObj.type || 'a';
this.titleObj.content = this.titleObj.content || ''; this.titleObj.content = this.titleObj.content || '';
this.titleObj.audio_url = this.titleObj.audio_url || ''; this.titleObj.audio_url = this.titleObj.audio_url || '';
this.editorContent = `<html lang="en"><head><meta charset="utf-8"> this.editorContent = editorTpl.replace('{{content}}', this.titleObj.content) ;
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
</head>
<body style="height:48px;overflow: hidden;margin: 0;padding: 0 .5rem;background: #FFF;line-height: 48px;">
${this.titleObj.content}
</body>
</html>`;
this.titleEW = this.titleEl.nativeElement.contentWindow; this.titleEW = this.titleEl.nativeElement.contentWindow;
console.log('this.titleEW', this.titleEW);
const tdoc = this.titleEW.document; const tdoc = this.titleEW.document;
tdoc.designMode = "on"; tdoc.designMode = 'on';
tdoc.open('text/html', 'replace'); tdoc.open('text/html', 'replace');
tdoc.write(this.editorContent); tdoc.write(this.editorContent);
tdoc.close(); tdoc.close();
tdoc.addEventListener("keypress", this.keyPress, true); tdoc.addEventListener('keypress', this.keyPress, true);
tdoc.addEventListener("blur", () => { tdoc.addEventListener('blur', () => {
if (this.titleObj.content === this.titleEW.document.body.innerHTML.trim()) { if (this.titleObj.content === this.titleEW.document.body.innerHTML.trim()) {
return; return;
} }
...@@ -159,30 +237,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -159,30 +237,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
ngOnDestroy(): void { ngOnDestroy(): void {
} }
iconsChanges(val) {
let a = this.titleObj.icons;
let b = val;
if (a.length > b.length) {
const diff = a.filter(x => !b.includes(x));
const ti = [...this.titleObj.icons];
for (let i = 0; i < diff.length; i++) {
const d = diff[i];
const idx = ti.indexOf(d);
ti.splice(idx, 1);
}
this.titleObj.icons = ti;
} else {
const diff = b.filter(x => !a.includes(x));
this.titleObj.icons = [...this.titleObj.icons, ...diff];
}
this.shouldSave();
}
typeChange(val) {
this.titleObj.icons = [];
this.shouldSave();
}
keyPress(evt) { keyPress(evt) {
try { try {
...@@ -195,9 +250,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -195,9 +250,9 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
const key = String.fromCharCode(evt.charCode).toLowerCase(); const key = String.fromCharCode(evt.charCode).toLowerCase();
let cmd = ''; let cmd = '';
switch (key) { switch (key) {
case 'b': cmd = "bold"; break; case 'b': cmd = 'bold'; break;
case 'i': cmd = "italic"; break; case 'i': cmd = 'italic'; break;
case 'u': cmd = "underline"; break; case 'u': cmd = 'underline'; break;
} }
...@@ -214,10 +269,13 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -214,10 +269,13 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
alert(e); alert(e);
} }
} }
execEditorCommand(command, option?: any) { execEditorCommand(command, option?: any) {
console.log('sssss');
try { try {
this.titleEW.focus(); this.titleEW.focus();
this.titleEW.document.execCommand(command, false, option); const result = this.titleEW.document.execCommand(command, false, option);
console.log(result);
this.loopCnt = 0; this.loopCnt = 0;
return false; return false;
...@@ -229,7 +287,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -229,7 +287,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
}, 100); }, 100);
this.loopCnt += 1; this.loopCnt += 1;
} else { } else {
alert("Error executing command."); alert('Error executing command.');
} }
} }
} }
...@@ -242,7 +300,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -242,7 +300,7 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
this.execEditorCommand('forecolor', this.__fontColor); this.execEditorCommand('forecolor', this.__fontColor);
} }
onChangeFontFamily(font) { onChangeFontFamily(font) {
this.execEditorCommand('fontname', font); this.execEditorCommand('fontName', font);
} }
onChangeFontSize(size?: any) { onChangeFontSize(size?: any) {
...@@ -272,9 +330,10 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy, ...@@ -272,9 +330,10 @@ export class LessonTitleConfigComponent implements OnInit, OnChanges, OnDestroy,
this.titleUpdated.emit(this.titleObj); this.titleUpdated.emit(this.titleObj);
} }
shouldSave = () => { shouldSave = () => {
console.log('title shouldSave'); console.log('title shouldSave', this.titleObj);
this.titleObj.content = this.titleEW.document.body.innerHTML.trim(); this.titleObj.content = this.titleEW.document.body.innerHTML.trim();
this.titleUpdated.emit(this.titleObj); this.titleUpdated.emit(this.titleObj);
} }
} }
...@@ -18,7 +18,7 @@ import { ...@@ -18,7 +18,7 @@ import {
export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit { export class PlayerContentWrapperComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
@ViewChild('wrapperEl') wrapperEl: ElementRef; @ViewChild('wrapperEl', {static: true }) wrapperEl: ElementRef;
// // aspect ratio? // // aspect ratio?
@Input() ratio; @Input() ratio;
......
...@@ -5,16 +5,21 @@ ...@@ -5,16 +5,21 @@
[nzAction]="uploadUrl" [nzAction]="uploadUrl"
[nzData]="uploadData" [nzData]="uploadData"
(nzChange)="handleChange($event)"> (nzChange)="handleChange($event)">
<!--[nzBeforeUpload]="customUpload">-->
<div class="p-box d-flex align-items-center"> <div class="p-box d-flex align-items-center">
<div class="p-upload-icon" *ngIf="!picUrl && !uploading"> <div class="p-upload-icon" *ngIf="!picUrl && !uploading">
<i nz-icon type="cloud-upload" theme="outline" [style.font-size]="iconSize + 'em'"></i> <i nz-icon nzType="cloud-upload" nzTheme="outline" [style.font-size]="iconSize + 'em'"></i>
<div class="m-3"></div> <div class="m-3"></div>
<span>{{TIP}}</span> <span>{{TIP}}</span>
<!--<div class="mt-5 p-progress-bar" *ngIf="uploading">-->
<!--<div class="p-progress-bg" [style.width]="progress*0.2+'rem'"></div>-->
<!--<div class="p-progress-value">{{progress}}%</div>-->
<!--</div>-->
</div> </div>
<div class="p-upload-progress-bg" *ngIf="uploading"> <div class="p-upload-progress-bg" *ngIf="uploading">
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
Uploading... Uploading...
</div> </div>
</div> </div>
...@@ -23,10 +28,10 @@ ...@@ -23,10 +28,10 @@
</div> </div>
</div> </div>
</nz-upload> </nz-upload>
<div class="p-btn-delete" *ngIf="picUrl && canDelete" <div class="p-btn-delete" *ngIf="canDelete"
nz-popconfirm nzTitle="Are you sure ?" nz-popconfirm nzTitle="Are you sure ?"
(nzOnConfirm)="onDelete()" (nzOnConfirm)="onDelete()"
> >
<i nz-icon type="close" theme="outline"></i> <i nz-icon nzType="close" nzTheme="outline"></i>
</div> </div>
</div> </div>
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
.p-image-uploader { .p-image-uploader {
position: relative; position: relative;
...@@ -52,16 +52,21 @@ ...@@ -52,16 +52,21 @@
.p-preview { .p-preview {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
@include k-img-bg();
} }
} }
.d-flex{
display: flex;
}
} }
.p-btn-delete { .p-btn-delete {
position: absolute; position: absolute;
right: -2rem; right: -0.5rem;
top: 0; top: -0.5rem;
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
border: 0.2rem solid white; border: 0.2rem solid white;
...@@ -70,7 +75,6 @@ ...@@ -70,7 +75,6 @@
background-color: #fb781a; background-color: #fb781a;
color: white; color: white;
text-align: center; text-align: center;
line-height: 2rem !important;
} }
.p-upload-progress-bg { .p-upload-progress-bg {
...@@ -96,6 +100,7 @@ ...@@ -96,6 +100,7 @@
} }
} }
:host ::ng-deep .ant-upload { :host ::ng-deep .ant-upload {
display: block; display: block;
} }
...@@ -33,14 +33,15 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -33,14 +33,15 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
uploadData; uploadData;
constructor(private nzMessageService: NzMessageService) { constructor(private nzMessageService: NzMessageService) {
this.uploadUrl = (<any> window).courseware.uploadUrl(); this.uploadUrl = (<any> window).courseware.uploadUrl();
// console.log("constructor", this.uploadUrl)
this.uploadData = (<any> window).courseware.uploadData(); this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => { window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url; this.uploadUrl = url;
this.uploadData = data; this.uploadData = data;
// console.log("getUploadCallback", this.uploadUrl)
}; };
} }
ngOnChanges() { ngOnChanges() {
if (!this.picItem) { if (!this.picItem) {
...@@ -48,7 +49,14 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -48,7 +49,14 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
} }
} }
handleChange(info: { type: string, file: UploadFile, event: any }): void { handleChange(info: { type: string, file: UploadFile, event: any }): void {
console.log('info:' , info);
switch (info.type) { switch (info.type) {
case 'start': case 'start':
// this.isUploading = true; // this.isUploading = true;
......
<div class="p-video-box">
<div class="up-video" style="display: flex;"> <div class="up-video" style="display: flex;">
<!--<nz-upload class="" [nzDisabled]="!showUploadBtn"--> <!--<nz-upload class="" [nzDisabled]="!showUploadBtn"-->
<!--[nzShowUploadList]="false"--> <!--[nzShowUploadList]="false"-->
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
<button type="button" nz-button nzType="default" *ngIf="showUploadBtn" [disabled]="uploading" <button type="button" nz-button nzType="default" *ngIf="showUploadBtn" [disabled]="uploading"
[nzLoading]="uploading" > [nzLoading]="uploading" >
<i nz-icon type="plus" theme="outline"></i> <i nz-icon nzType="plus" nzTheme="outline"></i>
<span>{{ uploading ? 'Uploading' : 'Select Video' }}</span> <span>{{ uploading ? 'Uploading' : 'Select Video' }}</span>
<!--<span>Select Video</span>--> <!--<span>Select Video</span>-->
</button> </button>
...@@ -56,9 +55,9 @@ ...@@ -56,9 +55,9 @@
</div> </div>
<div class="p-box d-flex align-items-center p-video-uploader" style="top: 20px;"> <div class="p-box d-flex align-items-center p-video-uploader">
<div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading"> <div class="p-upload-icon" *ngIf="!showUploadBtn && !videoUrl && !uploading">
<i nz-icon type="upload" theme="outline"></i> <i nz-icon nzType="upload" nzTheme="outline"></i>
<div class="m-3"></div> <div class="m-3"></div>
<span>Click here to upload video</span> <span>Click here to upload video</span>
<div class="mt-5 p-progress-bar" *ngIf="uploading"> <div class="mt-5 p-progress-bar" *ngIf="uploading">
...@@ -70,26 +69,26 @@ ...@@ -70,26 +69,26 @@
[ngClass]="{'smart-bar': showUploadBtn}" > [ngClass]="{'smart-bar': showUploadBtn}" >
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
Uploading... Uploading...
</div> </div>
</div> </div>
<div class="p-upload-check-bg" *ngIf="checking"> <div class="p-upload-check-bg" *ngIf="checking">
<div class="i-bg" [style.width]="progress+'%'"></div> <div class="i-bg" [style.width]="progress+'%'"></div>
<div class="i-text"> <div class="i-text">
<fa name="cloud-upload"></fa> <fa-icon icon="cloud-upload-alt"></fa-icon>
<i nz-icon type="loading" theme="outline"></i>Checking... <i nz-icon nzType="loading" nzTheme="outline"></i>Checking...
</div> </div>
</div> </div>
<div class="p-preview" *ngIf="!showUploadBtn && !uploading && videoUrl " > <div class="p-preview" *ngIf="!uploading && videoUrl " >
<!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>--> <!--<video crossorigin="anonymous" [src]="videoUrl" controls #videoNode></video>-->
<video [src]="safeVideoUrl(videoUrl)" controls #videoNode (loadedmetadata)="videoLoadedMetaData()"></video> <video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video>
</div> </div>
</div> </div>
<div [style.display]="!checkVideoExists?'none':''"> <div [style.display]="!checkVideoExists?'none':''">
<span><i nz-icon type="loading" theme="outline"></i> checking file to upload</span> <span><i nz-icon nzType="loading" nzTheme="outline"></i> checking file to upload</span>
</div>
</div> </div>
@import '../../style/common_mixin'; @import '../../style/common_mixin.css';
/*.p-video-box{
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
padding-top: 56.25%;
//font-size: 4rem;
position: relative;
.p-upload-icon{
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50% ,-50%);
}
}*/
.p-video-uploader { .p-video-uploader {
position: relative; position: relative;
display: block; display: block;
...@@ -17,25 +33,33 @@ ...@@ -17,25 +33,33 @@
background-color: #fafafa; background-color: #fafafa;
text-align: center; text-align: center;
color: #aaa; color: #aaa;
.p-upload-icon {
}
}
.p-upload-icon {
text-align: center; text-align: center;
margin: auto; margin: auto;
.anticon-upload {
}
.p-upload-icon .anticon-upload {
color: #888; color: #888;
font-size: 5rem; font-size: 5rem;
} }
.p-progress-bar { p-progress-bar {
position: relative; position: relative;
width: 20rem; width: 20rem;
height: 1.5rem; height: 1.5rem;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 1rem; border-radius: 1rem;
.p-progress-bg {
}
.p-progress-bar .p-progress-bg {
background-color: #1890ff; background-color: #1890ff;
border-radius: 1rem; border-radius: 1rem;
height: 100%; height: 100%;
} }
.p-progress-value { .p-progress-bar .p-progress-value {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
...@@ -46,21 +70,19 @@ ...@@ -46,21 +70,19 @@
text-align: center; text-align: center;
font-size: 0.9rem; font-size: 0.9rem;
line-height: 1.5rem; line-height: 1.5rem;
} }
} .p-preview {
}
.p-preview {
width: 100%; width: 100%;
height: 100%; height: 100%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
video{
}
.p-preview video{
max-height: 100%; max-height: 100%;
max-width: 100%; max-width: 100%;
position: absolute;
display: flex;
} }
}
}
}
.p-btn-delete { .p-btn-delete {
position: absolute; position: absolute;
right: -0.5rem; right: -0.5rem;
......
import {Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SecurityContext, ViewChild} from '@angular/core'; import {Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SecurityContext, ViewChild} from '@angular/core';
import {NzMessageService, UploadFile} from 'ng-zorro-antd'; import {NzMessageService, UploadChangeParam, UploadFile, UploadFileStatus} from 'ng-zorro-antd';
import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
...@@ -24,7 +24,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -24,7 +24,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
@Input() @Input()
videoUrl = ''; videoUrl = '';
@ViewChild('videoNode') @ViewChild('videoNode', {static: true })
videoNode: ElementRef; videoNode: ElementRef;
...@@ -47,8 +47,8 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -47,8 +47,8 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
item: any; item: any;
// videoItem = null; // videoItem = null;
uploadUrl uploadUrl;
uploadData uploadData;
constructor(private nzMessageService: NzMessageService, constructor(private nzMessageService: NzMessageService,
private sanitization: DomSanitizer private sanitization: DomSanitizer
...@@ -58,10 +58,12 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -58,10 +58,12 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
this.uploading = false; this.uploading = false;
this.videoFile = null; this.videoFile = null;
this.uploadUrl = (<any> window).courseware.uploadUrl(); this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData(); this.uploadData = (<any> window).courseware.uploadData();
window['air'].getUploadCallback = (url, data) => { window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url; this.uploadUrl = url;
this.uploadData = data; this.uploadData = data;
}; };
...@@ -79,7 +81,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -79,7 +81,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
} }
safeVideoUrl(url) { safeVideoUrl(url) {
console.log(url) console.log(url);
return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`; return this.sanitization.bypassSecurityTrustResourceUrl(url); // `${url}`;
} }
videoLoadedMetaData() { videoLoadedMetaData() {
...@@ -87,7 +89,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -87,7 +89,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
} }
handleChange(info: { type: string, file: UploadFile, event: any }): void { handleChange(info: UploadChangeParam/* { type: string, file: UploadFile, event: any }*/): void {
console.log('info:' , info); console.log('info:' , info);
...@@ -117,7 +119,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -117,7 +119,7 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
break; break;
case 'progress': case 'progress':
this.progress = parseInt(info.event.percent, 10); this.progress = info.event.percent;
this.doProgress(this.progress); this.doProgress(this.progress);
break; break;
} }
...@@ -160,9 +162,9 @@ export class UploadVideoComponent implements OnChanges, OnDestroy { ...@@ -160,9 +162,9 @@ export class UploadVideoComponent implements OnChanges, OnDestroy {
if (duration) { if (duration) {
duration = duration * 1000; duration = duration * 1000;
} }
file['height'] = height; file.height = height;
file['width'] = width; file.width = width;
file['duration'] = duration; file.duration = duration;
vid.preload = 'none'; vid.preload = 'none';
vid.src = ''; vid.src = '';
vid.remove(); vid.remove();
......
...@@ -14,7 +14,6 @@ import { ...@@ -14,7 +14,6 @@ import {
ShapeCircle, ShapeCircle,
MyAnimation MyAnimation
} from "./Unit"; } from "./Unit";
import { matchesElement } from '@angular/animations/browser/src/render/shared';
export class Cartoon { export class Cartoon {
......
...@@ -8,7 +8,6 @@ import { ...@@ -8,7 +8,6 @@ import {
HostListener HostListener
} from "@angular/core"; } from "@angular/core";
import { UUID } from 'angular2-uuid';
import { import {
MySprite, MySprite,
...@@ -912,8 +911,8 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -912,8 +911,8 @@ export class PlayComponent implements OnInit, OnDestroy {
// //
// -------------------------------------------------- // --------------------------------------------------
@ViewChild("canvas") canvas: ElementRef; @ViewChild("canvas", {static: true }) canvas: ElementRef;
@ViewChild("wrap") wrap: ElementRef; @ViewChild("wrap", {static: true }) wrap: ElementRef;
@HostListener("window:resize", ["$event"]) @HostListener("window:resize", ["$event"])
onResize(event) { onResize(event) {
this.g_winResizeEventStream.next(); this.g_winResizeEventStream.next();
......
/*
global css to mixin
*/
@mixin hide-overflow-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
@mixin k-no-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@mixin k-img-bg {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.anticon{
vertical-align: .1em!important;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>NgOne</title>
<base href="/">
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<script type="text/javascript" src="https://staging-teach.cdn.ireadabc.com/h5template/h5-static-lib/js/air.js"></script>
</head>
<body>
Hello World!!
</body>
</html>
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@import "~ng-zorro-antd/src/ng-zorro-antd.css"; @import "~ng-zorro-antd/ng-zorro-antd.min.css";
\ No newline at end of file \ No newline at end of file
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": [
"node"
]
}, },
"files": [ "files": [
"src/main.ts", "src/main.ts",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment