Commit 022d9d3d authored by limingzhe's avatar limingzhe

fix: debug

parent f5a6e2ef
No preview for this file type
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{ {
"ver": "1.0.8", "ver": "1.0.8",
"uuid": "3fb4df94-7fc7-4da8-8f81-ebb70edb865b", "uuid": "88cb9a2d-6891-46a9-8ab6-32b40d3cc977",
"isPlugin": false, "isPlugin": false,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,
......
...@@ -70,75 +70,9 @@ export function setSprNodeMaxLen(sprNode, maxW, maxH) { ...@@ -70,75 +70,9 @@ export function setSprNodeMaxLen(sprNode, maxW, maxH) {
sprNode.scale = Math.round(s * 1000) / 1000; sprNode.scale = Math.round(s * 1000) / 1000;
} }
export function localPosTolocalPos(baseNode, targetNode) {
const worldPos = targetNode.parent.convertToWorldSpaceAR(cc.v2(targetNode.x, targetNode.y));
const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
return localPos;
}
export function worldPosToLocalPos(worldPos, baseNode) {
const localPos = baseNode.parent.convertToNodeSpaceAR(cc.v2(worldPos.x, worldPos.y));
return localPos;
}
export function getScaleRateBy2Node(baseNode, targetNode, maxFlag = true) {
const worldRect1 = targetNode.getBoundingBoxToWorld();
const worldRect2 = baseNode.getBoundingBoxToWorld();
const sx = worldRect1.width / worldRect2.width;
const sy = worldRect1.height / worldRect2.height;
if (maxFlag) {
return Math.max(sx, sy);
} else {
return Math.min(sx, sy);
}
}
export function getDistance (start, end){
var pos = cc.v2(start.x - end.x, start.y - end.y);
var dis = Math.sqrt(pos.x*pos.x + pos.y*pos.y);
return dis;
}
export function playAudioByUrl(audio_url, cb=null) {
if (audio_url) {
cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
const audioId = cc.audioEngine.play(audioClip, false, 0.8);
if (cb) {
cc.audioEngine.setFinishCallback(audioId, () => {
cb();
});
}
});
} else {
cb && cb();
}
}
export function btnClickAnima(btn, time=0.15, rate=1.05) {
btn.tmpScale = btn.scale;
btn.on(cc.Node.EventType.TOUCH_START, () => {
cc.tween(btn)
.to(time / 2, {scale: btn.scale * rate})
.start()
})
btn.on(cc.Node.EventType.TOUCH_CANCEL, () => {
cc.tween(btn)
.to(time / 2, {scale: btn.tmpScale})
.start()
})
btn.on(cc.Node.EventType.TOUCH_END, () => {
cc.tween(btn)
.to(time / 2, {scale: btn.tmpScale})
.start()
})
}
export function getSpriteFrimeByUrl(url, cb) { export function getSpriteFrimeByUrl(url, cb) {
cc.loader.load({ url }, (err, img) => { cc.loader.load({url}, (err, img) => {
const spriteFrame = new cc.SpriteFrame(img) const spriteFrame = new cc.SpriteFrame(img)
if (cb) { if (cb) {
cb(spriteFrame); cb(spriteFrame);
...@@ -166,23 +100,31 @@ export function getSprNodeByUrl(url, cb) { ...@@ -166,23 +100,31 @@ export function getSprNodeByUrl(url, cb) {
export function playAudio(audioClip, cb = null) { export function playAudio(audioClip, cb=null) {
if (audioClip) { if (audioClip) {
const audioId = cc.audioEngine.playEffect(audioClip, false, 0.8);
const audioId = cc.audioEngine.play(audioClip, false, 0.8);
if (cb) { if (cb) {
cc.audioEngine.setFinishCallback(audioId, () => { cc.audioEngine.setFinishCallback(audioId, () => {
cb(); cb();
}); });
} }
} else {
console.log('audioClip is not exist'); return audioId;
}
}
export function playAudioByUrl(audio_url, cb=null) {
if (audio_url) {
cc.assetManager.loadRemote(audio_url, (err, audioClip) => {
playAudio(audioClip, cb);
});
} }
} }
export async function asyncDelay(time) { export async function asyncDelay(time) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
...@@ -331,18 +273,18 @@ export async function asyncTweenBy(node, duration, obj, ease = undefined) { ...@@ -331,18 +273,18 @@ export async function asyncTweenBy(node, duration, obj, ease = undefined) {
export function showTrebleFirework(baseNode, rabbonList) { export function showTrebleFirework(baseNode, rabbonList) {
const middle = new FireworkSettings(baseNode, rabbonList); const middle = new FireworkSettings(baseNode, rabbonList);
middle.pos = cc.v2(0, -400); middle.pos = cc.v2(0, -600);
middle.side = cc.v2(0, 1000); middle.side = cc.v2(0, 1000);
middle.range = 200; middle.range = 200;
middle.number = 100; middle.number = 100;
middle.scalseRange = 0.4; middle.scalseRange = 0.4;
const left = FireworkSettings.copy(middle); const left = FireworkSettings.copy(middle);
left.pos = cc.v2(-600, -400); left.pos = cc.v2(-600, -600);
left.side = cc.v2(200, 1000); left.side = cc.v2(200, 1000);
const right = FireworkSettings.copy(middle); const right = FireworkSettings.copy(middle);
right.pos = cc.v2(600, -400); right.pos = cc.v2(600, -600);
right.side = cc.v2(-200, 1000); right.side = cc.v2(-200, 1000);
showFireworks(middle); showFireworks(middle);
...@@ -350,14 +292,61 @@ export function showTrebleFirework(baseNode, rabbonList) { ...@@ -350,14 +292,61 @@ export function showTrebleFirework(baseNode, rabbonList) {
showFireworks(right); showFireworks(right);
} }
export function onHomeworkFinish() {
export function delayCall(time, cb) {
return cc.tween({})
.delay(time)
.call(() => {
if (cb) {
cb();
}
})
.start();
}
export function removeFromArr(arr, item) {
const index = arr.indexOf(item);
if (index != -1) {
arr.splice(index, 1);
return true;
}
return false;
}
export function showBtnAnima(btn, cb=null) {
const baseS = btn.scale;
cc.tween(btn)
.to(0.05, {scale: 0.9 * baseS})
.to(0.05, {scale: 1 * baseS})
.call(() => {
if (cb) {
cb();
}
})
.start();
}
export function jellyShake(node) {
const baseS = node.scale;
const time = 1;
cc.tween(node)
.to(time / 5 / 2, {scaleX: baseS * 0.8, scaleY: baseS * 1.2}, {easing: "sineInOut"})
.to(time / 5, {scaleX: baseS * 1.1, scaleY: baseS * 0.9}, {easing: "sineInOut"})
.to(time / 5, {scaleX: baseS * 0.95, scaleY: baseS * 1.15}, {easing: "sineInOut"})
.to(time / 5, {scaleX: baseS * 1.02, scaleY: baseS * 0.98}, {easing: "sineInOut"})
.to(time / 5, {scaleX: baseS * 1, scaleY: baseS * 1}, {easing: "sineInOut"})
.start();
}
export function onHomeworkFinish(data) {
const middleLayer = cc.find('middleLayer'); const middleLayer = cc.find('middleLayer');
if (middleLayer) { if (middleLayer) {
const middleLayerComponent = middleLayer.getComponent('middleLayer'); const middleLayerComponent = middleLayer.getComponent('middleLayer');
if (middleLayerComponent.role == 'student') { middleLayerComponent.onHomeworkFinish(() => { }, data);
middleLayerComponent.onHomeworkFinish(() => { });
} return;
} else {
console.log('onHomeworkFinish');
} }
} }
\ No newline at end of file
This diff is collapsed.
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
"compressing": "^1.5.0", "compressing": "^1.5.0",
"ng-zorro-antd": "^8.5.2", "ng-zorro-antd": "^8.5.2",
"rxjs": "~6.5.4", "rxjs": "~6.5.4",
"node-sass": "^4.0.0",
"spark-md5": "^3.0.0", "spark-md5": "^3.0.0",
"tslib": "^1.10.0", "tslib": "^1.10.0",
"node-sass": "^4.0.0",
"zone.js": "~0.10.2" "zone.js": "~0.10.2"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -6,7 +6,7 @@ import { Component , OnInit} from '@angular/core'; ...@@ -6,7 +6,7 @@ import { Component , OnInit} from '@angular/core';
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
type = 'form'; type = 'play';
constructor() { constructor() {
const tp = this.getQueryString('type'); const tp = this.getQueryString('type');
......
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import {DragDropModule} from '@angular/cdk/drag-drop';
import { NgModule, ErrorHandler } from '@angular/core'; import { NgModule, ErrorHandler } from '@angular/core';
import {MyErrorHandler} from './MyError'; import {MyErrorHandler} from './MyError';
...@@ -24,7 +25,10 @@ import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.com ...@@ -24,7 +25,10 @@ import {AudioRecorderComponent} from './common/audio-recorder/audio-recorder.com
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { fas } from '@fortawesome/free-solid-svg-icons'; import { fas } from '@fortawesome/free-solid-svg-icons';
import { far } from '@fortawesome/free-regular-svg-icons'; import { far } from '@fortawesome/free-regular-svg-icons';
import { CustomActionComponent } from './common/custom-action/custom-action.component';
import { UploadDragonBoneComponent } from './common/upload-dragon-bone/upload-dragon-bone.component'; import { UploadDragonBoneComponent } from './common/upload-dragon-bone/upload-dragon-bone.component';
import { SubTemplateComponent } from './common/sub-template/sub-template.component';
import {FormulaInputComponent} from './common/formula-input/formula-input.component';
registerLocaleData(zh); registerLocaleData(zh);
...@@ -41,9 +45,12 @@ registerLocaleData(zh); ...@@ -41,9 +45,12 @@ registerLocaleData(zh);
TimePipe, TimePipe,
UploadVideoComponent, UploadVideoComponent,
CustomHotZoneComponent, CustomHotZoneComponent,
UploadDragonBoneComponent, SubTemplateComponent,
PlayerContentWrapperComponent
PlayerContentWrapperComponent,
CustomActionComponent,
UploadDragonBoneComponent,
FormulaInputComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
...@@ -51,7 +58,8 @@ registerLocaleData(zh); ...@@ -51,7 +58,8 @@ registerLocaleData(zh);
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
BrowserAnimationsModule, BrowserAnimationsModule,
FontAwesomeModule FontAwesomeModule,
DragDropModule
], ],
providers: [ providers: [
{provide: ErrorHandler, useClass: MyErrorHandler}, {provide: ErrorHandler, useClass: MyErrorHandler},
......
...@@ -35,7 +35,8 @@ ...@@ -35,7 +35,8 @@
<ng-template #truthyTemplate > <ng-template #truthyTemplate >
<div class="btn-delete" (click)="onBtnDeleteAudio()"> <div class="btn-delete" (click)="onBtnDeleteAudio()">
<fa-icon icon="close"></fa-icon> <!-- <fa-icon icon="close"></fa-icon> -->
<i nz-icon nzType="close" nzTheme="outline"></i>
</div> </div>
</ng-template> </ng-template>
......
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core'; import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core';
import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd'; import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd';
import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http'; import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http';
import {environment} from '../../../environments/environment';
declare var Recorder; declare var Recorder;
...@@ -26,7 +26,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -26,7 +26,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
uploadData; uploadData;
@Input() @Input()
needRemove = false; needRemove = true;
@Input() @Input()
audioItem: any = null; audioItem: any = null;
...@@ -62,8 +62,25 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -62,8 +62,25 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
this.uploadUrl = url; this.uploadUrl = url;
this.uploadData = data; this.uploadData = data;
}; };
this.setUploadUrl();
}
setUploadUrl() {
if (!this.uploadUrl) {
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
setTimeout(() => {
this.setUploadUrl();
}, 500);
}
} }
init() { init() {
this.playIcon = 'play'; this.playIcon = 'play';
this.isPlaying = false; this.isPlaying = false;
...@@ -157,6 +174,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy { ...@@ -157,6 +174,7 @@ export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
onBtnDeleteAudio() { onBtnDeleteAudio() {
this.audioUrl = null; this.audioUrl = null;
this.audioUploaded.emit({});
this.audioRemoved.emit(); this.audioRemoved.emit();
} }
......
<div class="position-relative">
<button nz-button (click)="setAnimaBtnClick()" style=" border-radius: 0.5rem; border: 1px solid #ddd;" >
<i nz-icon nzType="tool" nzTheme="outline"></i>
{{btnName}}
</button>
<!--配置龙骨面板-->
<nz-modal [(nzVisible)]="panelVisible" (nzAfterClose)="closePanel()" [nzTitle]="btnName" (nzOnCancel)="panelCancel()" (nzOnOk)="panelOk()" nzOkText="保存">
<div>
<h4>基础内容:</h4>
<div style="margin-bottom: 10px; width: 80%; margin: auto;">
<!-- <nz-radio-group [ngModel]="item.type" (ngModelChange)="radioChange($event)">
<label nz-radio nzValue="pic">图片</label>
<label nz-radio nzValue="text">文本</label>
</nz-radio-group> -->
<div *ngIf="item.type == 'pic'">
<app-upload-image-with-preview
[picUrl]="item?.pic_url"
(imageUploaded)="onItemImgUploadSuccess($event, item)">
</app-upload-image-with-preview>
</div>
<div *ngIf="item.type == 'text'">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="saveText(item)">
</div>
<div *ngIf="item.type == 'anima'" style="margin-left: 100px;">
<app-upload-dragon-bone
[skeJsonData]=item.skeJsonData
[texJsonData]=item.texJsonData
[texPngData]=item.texPngData
(save)="saveAnima($event)"
>
</app-upload-dragon-bone>
</div>
</div>
<nz-divider style="margin-top: 10px;"></nz-divider>
<h4>状态设置:</h4>
<div style="display: flex; justify-content: space-around;">
<div style="width: 30%; display: flex; align-items: center; flex-direction: column;">
<h5> 开始状态 </h5>
<div *ngFor="let op of item.changeOption; let i = index" style="margin-bottom: 5px; ">
<div style="display: flex; align-items: center; justify-content: center;">
<span>{{op[0]}}: </span> <input type="text" nz-input [(ngModel)]="op[1]" (blur)="saveText(op)" style="margin-left: 5px;">
</div>
</div>
</div>
<div style="width: 30%; display: flex; align-items: center; flex-direction: column; ">
<h5> 切换时间 </h5>
<div style="display: flex; width: 100%; align-items: center; justify-content: center;">
<span>time: </span> <input type="text" nz-input [(ngModel)]="item.changeTime" (blur)="saveText(item.changeTime)" style="width: 80px; margin-left: 5px;">
</div>
</div>
<div style="width: 30%; display: flex; align-items: center; flex-direction: column;">
<h5> 结束状态 </h5>
<div *ngFor="let op of item.changeOption; let i = index" style="margin-bottom: 5px; ">
<div style="display: flex; align-items: center; justify-content: center;">
<span>{{op[0]}}: </span> <input [disabled]="op[2] == null" type="text" nz-input [(ngModel)]="op[2]" (blur)="saveText(op)" style="margin-left: 5px;">
</div>
</div>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: center; margin-top: 10px;">
<button style="margin-left: 20px; margin-top: -5px" nz-button (click)="copyChangeData()"> 复制数据 </button>
<div style="margin-left: 20px; margin-top: -5px" >
<span>粘贴数据: </span>
<input style="width: 100px;" type="text" nz-input [(ngModel)]="pasteData" >
<button style="margin-left: 5px;" nz-button [disabled]="pasteData==''" nzType="primary" (click)="importData()">导入</button>
</div>
</div>
<nz-divider style="margin-top: 10px;"></nz-divider>
<h4> 音频设置 </h4>
<app-audio-recorder
style="margin: auto"
[audioUrl]="item?.audio_url"
(audioUploaded)="onItemAudioUploadSuccess($event, item)"
></app-audio-recorder>
</div>
<!--
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 ske_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="skeJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isSkeJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="skeJsonData && skeJsonData['name']" style="margin-left: 10px"><u> {{skeJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_json 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept="application/json"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texJsonHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexJsonLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texJsonData && texJsonData['name']" style="margin-left: 10px"><u> {{texJsonData['name']}} </u></span>
</div>
<div class="anima-upload-btn">
<span style="margin-right: 10px">上传 tex_png 文件: </span>
<nz-upload [nzShowUploadList]="false"
nzAccept = "image/*"
[nzAction]="uploadUrl"
[nzData]="uploadData"
(nzChange)="texPngHandleChange($event)">
<button nz-button><i nz-icon nzType="upload"></i><span>Upload</span></button>
</nz-upload>
<i *ngIf="isTexPngLoading" style="margin-left: 10px;" nz-icon [nzType]="'loading'"></i>
<span *ngIf="texPngData && texPngData['name']" style="margin-left: 10px"><u> {{texPngData['name']}} </u></span>
</div>
<div class="anima-upload-btn" *ngIf="animaNames && animaNames.length > 0">
提示:需包含动画: {{animaNames.toString()}}.
</div> -->
</nz-modal>
</div>
@import '../../style/common_mixin.css';
.p-image-uploader {
position: relative;
display: block;
width: 100%;
height: 0;
padding-bottom: 56.25%;
.p-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border: 2px dashed #ddd;
border-radius: 0.5rem;
background-color: #fafafa;
text-align: center;
color: #aaa;
.p-upload-icon {
text-align: center;
margin: auto;
.anticon-upload {
color: #888;
font-size: 5rem;
}
.p-progress-bar {
position: relative;
width: 20rem;
height: 1.5rem;
border: 1px solid #ccc;
border-radius: 1rem;
.p-progress-bg {
background-color: #1890ff;
border-radius: 1rem;
height: 100%;
}
.p-progress-value {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-shadow: 0 0 4px #000;
color: white;
text-align: center;
font-size: 0.9rem;
line-height: 1.5rem;
}
}
}
.p-preview {
width: 100%;
height: 100%;
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
//background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
}
}
.d-flex{
display: flex;
}
}
.p-btn-delete {
position: absolute;
right: -0.5rem;
top: -0.5rem;
width: 2rem;
height: 2rem;
border: 0.2rem solid white;
border-radius: 50%;
font-size: 1.2rem;
background-color: #fb781a;
color: white;
text-align: center;
}
.p-upload-progress-bg {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
& .i-text {
position: absolute;
text-align: center;
color: white;
text-shadow: 0 0 2px rgba(0, 0, 0, .85);
}
& .i-bg {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: #27b43f;
border-radius: 0.5rem;
}
}
.anima-upload-btn {
padding: 10px;
}
:host ::ng-deep .ant-upload {
display: block;
}
import {ApplicationRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output} from '@angular/core';
import { NzMessageService, UploadXHRArgs, UploadFile } from 'ng-zorro-antd';
@Component({
selector: 'app-custom-action',
templateUrl: './custom-action.component.html',
styleUrls: ['./custom-action.component.scss']
})
export class CustomActionComponent implements OnDestroy, OnChanges {
uploading = false;
progress = 0;
@Input()
btnName = '配置变化状态';
@Input()
option = []
@Input()
item;
@Input()
type = 'text'
@Output()
save = new EventEmitter();
@Output()
refreshEmitter = new EventEmitter();
uploadUrl;
uploadData;
panelVisible = false;
pasteData = '';
constructor(private appRef: ApplicationRef, private nzMessageService: NzMessageService) {
window['air'].getUploadCallback = (url, data) => {
this.uploadUrl = url;
this.uploadData = data;
};
const tmpId = setInterval(() => {
console.log(' in setInterval')
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
if (this.uploadUrl) {
clearInterval(tmpId);
}
}, 500)
}
ngOnInit() {
this.initItem();
}
ngOnChanges() {
}
initItem() {
console.log('```this.item: ', this.item);
if (!this.item) {
this.item = {
type: this.type,
skeJsonData: {},
texJsonData: {},
texPngData: {},
changeStart: [
],
changeEnd: [
],
changeTime: 0.3
};
if (this.option) {
this.item.changeOption = JSON.parse(JSON.stringify(this.option));
}
}
console.log('initItem', this.item);
}
setAnimaBtnClick() {
this.panelVisible = true;
this.refresh();
}
panelCancel() {
this.panelVisible = false;
this.refresh();
}
panelOk() {
// this.sendItemDragonBoneData();
this.panelVisible = false;
this.refresh();
this.save.emit(this.item);
}
saveText(t) {
}
radioChange(e) {
this.item.type = e;
console.log('e: ', e);
}
onItemImgUploadSuccess(e, item) {
item.pic_url = e.url;
this.refresh();
}
onItemAudioUploadSuccess(e, item) {
item.audio_url = e.url;
this.refresh();
}
saveAnima(e) {
console.log("~ e: ", e);
}
copyChangeData() {
console.log('this.item: ', this.item);
const jsonData = {
changeOption: this.item.changeOption,
changeTime : this.item.changeTime
// bgItem,
// hotZoneItemArr,
// isHasRect: this.isHasRect,
// isHasPic: this.isHasPic,
// isHasText: this.isHasText,
// isHasAudio: this.isHasAudio,
// isHasAnima: this.isHasAnima,
// hotZoneFontObj: this.hotZoneFontObj,
// defaultItemType: this.defaultItemType,
// hotZoneImgSize: this.hotZoneImgSize,
};
const oInput = document.createElement('input');
oInput.value = JSON.stringify(jsonData);
document.body.appendChild(oInput);
oInput.select(); // 选择对象
document.execCommand('Copy'); // 执行浏览器复制命令
document.body.removeChild(oInput);
this.nzMessageService.success('复制成功');
}
importData() {
if (!this.pasteData) {
return;
}
try {
const data = JSON.parse(this.pasteData);
console.log('data:', data);
const {
changeOption,
changeTime
} = data;
this.item.changeOption = changeOption;
this.item.changeTime = changeTime;
this.pasteData = '';
} catch (e) {
console.log('err: ', e);
this.nzMessageService.error('导入失败');
}
}
/**
* 刷新 渲染页面
*/
refresh() {
// this.refreshEmitter.emit();
setTimeout(() => {
this.appRef.tick();
}, 1);
}
closePanel() {
console.log(' in closePanel ');
this.refresh();
}
ngOnDestroy() {
}
}
This diff is collapsed.
...@@ -81,6 +81,10 @@ ...@@ -81,6 +81,10 @@
} }
} }
.anima-upload-btn {
padding: 10px;
}
h5 { h5 {
margin-top: 1rem; margin-top: 1rem;
} }
...@@ -89,8 +93,8 @@ h5 { ...@@ -89,8 +93,8 @@ h5 {
@font-face @font-face
{ {
font-family: 'BRLNSR_1'; font-family: 'ahronbd-1';
src: url("/assets/font/BRLNSR_1.TTF") ; src: url("/assets/font/ahronbd-1.ttf") ;
} }
...@@ -105,106 +109,3 @@ h5 { ...@@ -105,106 +109,3 @@ h5 {
//@import '../../../style/common_mixin';
//
//.p-image-uploader {
// position: relative;
// display: block;
// width: 100%;
// height: 0;
// padding-bottom: 56.25%;
// .p-box {
// position: absolute;
// left: 0;
// top: 0;
// right: 0;
// bottom: 0;
// border: 2px dashed #ddd;
// border-radius: 0.5rem;
// background-color: #fafafa;
// text-align: center;
// color: #aaa;
// .p-upload-icon {
// text-align: center;
// margin: auto;
// .anticon-upload {
// color: #888;
// font-size: 5rem;
// }
// .p-progress-bar {
// position: relative;
// width: 20rem;
// height: 1.5rem;
// border: 1px solid #ccc;
// border-radius: 1rem;
// .p-progress-bg {
// background-color: #1890ff;
// border-radius: 1rem;
// height: 100%;
// }
// .p-progress-value {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// text-shadow: 0 0 4px #000;
// color: white;
// text-align: center;
// font-size: 0.9rem;
// line-height: 1.5rem;
// }
// }
// }
// .p-preview {
// width: 100%;
// height: 100%;
// //background-image: url("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
// @include k-img-bg();
// }
// }
//}
//
//.p-btn-delete {
// position: absolute;
// right: -0.5rem;
// top: -0.5rem;
// width: 2rem;
// height: 2rem;
// border: 0.2rem solid white;
// border-radius: 50%;
// font-size: 1.2rem;
// background-color: #fb781a;
// color: white;
// text-align: center;
//}
//
//.p-upload-progress-bg {
// position: absolute;
// width: 100%;
// height: 100%;
// display: flex;
// align-items: center;
// justify-content: center;
// & .i-text {
// position: absolute;
// text-align: center;
// color: white;
// text-shadow: 0 0 2px rgba(0, 0, 0, .85);
// }
// & .i-bg {
// position: absolute;
// left: 0;
// top: 0;
// height: 100%;
// background-color: #27b43f;
// border-radius: 0.5rem;
// }
//}
//
//
//:host ::ng-deep .ant-upload {
// display: block;
//}
<nz-input-group [nzSuffix]="suffixTemplate">
<input type="text"
#inputEl
(focus)="showFormulaPad($event)"
nz-input [(ngModel)]="ngfModel"
(ngModelChange)="valueChanged($event)" />
</nz-input-group>
<ng-template #suffixTemplate>
<i nz-icon [nzType]="'percentage'" (click)="showFormulaPad($event)"></i>
</ng-template>
<!-- cdkDrag-->
<!--<div style='position: absolute;visibility: hidden' class="FormulaBoardContainer" #wrapperEl >-->
<!--</div>-->
@import '../../style/common_mixin.css';
:host{
display: inline-block;
}
import {
AfterViewInit,
Component,
ElementRef, EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit, Output,
ViewChild
} from '@angular/core';
import {fromEvent, Observable, Subscription} from 'rxjs';
declare global {
interface Window {
FBOARD: any;
FormulaBoard: any;
__initfp__: any;
__tmp_fp_input_model__: any;
__FormulaBoard_js_installed__: any;
}
}
@Component({
selector: 'app-formula-input',
templateUrl: './formula-input.component.html',
styleUrls: ['./formula-input.component.scss']
})
export class FormulaInputComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
@ViewChild('inputEl', {static: true }) inputEl: ElementRef;
// @ViewChild('wrapperEl', {static: true }) wrapperEl: ElementRef;
private fboard: any;
// [(ngModel)]="item.title" (blur)="save()"
@Input() ngfModel: any;
@Output() ngfModelChange = new EventEmitter();
@Output() ngfBlur = new EventEmitter();
FB_id = 'FormulaBoard';
private esc: Subscription;
constructor() {
if (!window.__FormulaBoard_js_installed__) {
window.__FormulaBoard_js_installed__ = true;
const s = document.createElement('script');
s.src = 'assets/formula-board/formula-board.js';
document.head.append(s);
s.addEventListener('load', () => {
this.FormulaBoardInit();
});
}
}
ngOnInit() {
}
ngOnChanges() {
}
ngOnDestroy(): void {
}
valueChanged(evt) {
console.log('valueChanged', this.ngfModel, evt);
this.ngfModelChange.emit(evt);
}
showFormulaPad(e) {
// console.log('showFormulaPad', e);
window.FBOARD.set(e.target.value);
window.__tmp_fp_input_model__ = this;
const rect = this.inputEl.nativeElement.getBoundingClientRect();
const fb = document.getElementById(this.FB_id);
fb.style.position = 'fixed';
// @ts-ignore
const padWidth = $('#' + this.FB_id).outerWidth() * .8;
// @ts-ignore
const padHeight = $('#' + this.FB_id).outerHeight() * .8;
// @ts-ignore
const ww = $(window).innerWidth();
// @ts-ignore
const hh = $(window).innerHeight();
const left = (ww - padWidth) / 2;
const top = (hh - padHeight) / 2;
console.log('left', left);
fb.style.left = left + 'px';
fb.style.top = top + 'px';
fb.style.visibility = 'visible';
}
updateValue(val) {
this.ngfModel = val;
this.ngfModelChange.emit(val);
}
ngAfterViewInit() {}
FormulaBoardInit() {
// if (window.__initfp__) {
// return;
// }
// window.__initfp__ = true;
window.FBOARD = new window.FormulaBoard({
// container: this.wrapperEl.nativeElement,
id: this.FB_id,
path: 'assets/formula-board/',
options: {
width: 1920,
mode: 'pc',
bottom: false,
}});
document.addEventListener('documentMessage', (e) => {
// @ts-ignore
const {type} = e.detail;
if (type === 'common.setFormula') {
// @ts-ignore
const {formula} = e.detail.data.body;
console.log(formula);
window.FBOARD.clear();
// @ts-ignore
window.__tmp_fp_input_model__.updateValue(formula);
window.FBOARD.editor.style.visibility = 'hidden';
this.ngfBlur.emit();
}
if (type === 'common.closeModal') {
window.FBOARD.editor.style.visibility = 'hidden';
}
});
}
}
<div class="content">
<div style="display: flex; margin-bottom: 5px;">
<button nz-button nzType="dashed" (click)="selectSubTemplate()" style=" border-radius: 0.5rem; border: 1px solid #ddd;">
<i nz-icon nzType="appstore" nzTheme="outline"></i>
选择子模板类型
</button>
<h2 *ngIf="_item.template" style="margin-left: 10px; margin-top: 1px;">
{{_item.template.description}}
</h2>
<button nz-button nzType="danger" (click)="deleteSubTemplate()" style="position: absolute; right: 30px; border-radius: 0.5rem; border: 1px solid #ddd;">
<i nz-icon nzType="delete" nzTheme="outline"></i>
删除
</button>
</div>
<iframe #iframe id="iframe" [src]="safeUrl" style="width: 98%; height: 70vh; border: 1px solid #ccc; padding: 5px;" frameborder="0">
</iframe>
<nz-modal [(nzVisible)]="isShowTemplate" (nzAfterClose)="closePanel()" nzTitle="选择子模板" [nzFooter]="null"
(nzOnCancel)="panelCancelClicked()" nzWidth="80%" nzHeight="80%">
<div class="template-container">
<div *ngFor="let template of templateArr" >
<div (click)="templateClick(template)" style="width: 150px; height: 100px; border: 1px solid #ccc; margin: 5px; cursor:pointer; user-select: none;">
<div style="width: 100%; height: 70%; border-bottom: 1px solid #ccc; overflow: hidden;">
<img [src]="template.cover" style="width: 100%; height: auto;">
</div>
<div style="width: 100%; height: 30%; display: flex; align-items: center; justify-content: center; ">
<label style="width: 90%; text-align: center; text-overflow: ellipsis; white-space:nowrap; overflow: hidden; ">{{template.description}}</label>
</div>
</div>
</div>
</div>
</nz-modal>
</div>
\ No newline at end of file
@import '../../style/common_mixin.css';
.content {
// width: 100%;
height: 100%;
border: 2px solid #ccc;
padding: 10px;
border-radius: 5px;
}
.template-container{
width: 100%;
display: flex;
// align-items: center;
// justify-content: space-around;
flex-wrap: wrap;
}
\ No newline at end of file
This diff is collapsed.
...@@ -42,7 +42,28 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges { ...@@ -42,7 +42,28 @@ export class UploadImageWithPreviewComponent implements OnDestroy, OnChanges {
this.uploadData = data; this.uploadData = data;
}; };
this.setUploadUrl();
} }
setUploadUrl() {
if (!this.uploadUrl) {
console.log('this.uploadUrl -=- 1 : ', this.uploadUrl)
this.uploadUrl = (<any> window).courseware.uploadUrl();
this.uploadData = (<any> window).courseware.uploadData();
console.log('this.uploadUrl -=- 2 : ', this.uploadUrl)
setTimeout(() => {
this.setUploadUrl();
}, 500);
}
console.log('this.uploadUrl -=- 3 : ', this.uploadUrl)
}
ngOnChanges() { ngOnChanges() {
if (!this.picItem) { if (!this.picItem) {
return; return;
......
...@@ -81,8 +81,8 @@ ...@@ -81,8 +81,8 @@
</div> </div>
</div> </div>
<div class="p-preview" *ngIf="!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></video> <!-- <video [src]="safeVideoUrl(videoUrl)" controls #videoNode></video> -->
</div> </div>
</div> </div>
<div [style.display]="!checkVideoExists?'none':''"> <div [style.display]="!checkVideoExists?'none':''">
......
...@@ -126,7 +126,16 @@ ...@@ -126,7 +126,16 @@
</app-upload-image-with-preview> </app-upload-image-with-preview>
</div> </div>
<div style="margin-top: 50px;"></div>
<h2>点位标注:</h2>
<app-custom-hot-zone
[isRotate]="true"
[bgItem]="item.bgItem2"
[hotZoneItemArr]="item.hotZoneItemArr2"
[customTypeGroupArr]="customTypeGroupArr2"
(save)="saveHotZone2(item, $event)"
>
</app-custom-hot-zone>
<!-- <div style="width: 300px;" align='center'> <!-- <div style="width: 300px;" align='center'>
......
...@@ -21,6 +21,52 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -21,6 +21,52 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
{key: 'letter_small_1', title: '小写黑色动画'}, {key: 'letter_small_1', title: '小写黑色动画'},
] ]
customTypeGroupArr2 = [
{
name: '连线Point',
rect: true,
isCopy: true,
isShowPos: true,
centerDot: true,
// checkbox: {
// title: '答案',
// list: [
// {label: '正确', key: 'isRight'},
// ]
// },
},
{
name: '书写Rect',
rect: true,
label: '答案',
isCopy: true,
isShowPos: true,
},
{
name: 'part区域',
rect: true,
},
{
name: '参照物1(标题)',
rect: true,
label: '参照文本',
},
{
name: '参照物2(标题)',
rect: true,
label: '参照文本',
},
{
name: '参照物2(字母)',
rect: true,
label: '参照文本',
},
]
constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) { constructor(private appRef: ApplicationRef, private changeDetectorRef: ChangeDetectorRef) {
} }
...@@ -72,6 +118,16 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -72,6 +118,16 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
} }
} }
saveHotZone2(group, e) {
console.log('e: ', e);
const {bgItem, hotZoneItemArr} = e;
group.bgItem2 = bgItem;
group.hotZoneItemArr2 = hotZoneItemArr;
this.save();
}
saveAnimArr(data, anim) { saveAnimArr(data, anim) {
console.log('data: ', data); console.log('data: ', data);
......
This diff is collapsed.
export async function loadFonts (fontName, fontFile) {
// const font = new FontFace(
// "DroidSansFallback",
// "url(" + "../../assets/play/font/DroidSansFallback.ttf" + ")"
// );
try {
console.log(location.href.split("#")[0] + "assets/play/font/" + fontFile);
const font = new FontFace(
fontName,
"url(" + location.href.split("#")[0] + "../../assets/play/font/" + fontFile + ")"
);
console.log('start: ', new Date().getTime())
await font.load();
console.log('end: ', new Date().getTime())
document.fonts.add(font);
document.body.classList.add("fonts-loaded");
} catch (error) {
console.log(error);
}
}
// --------------- custom class --------------------
This diff is collapsed.
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
height: 100%; height: 100%;
background: #ffffff; background: #ffffff;
background-size: cover; background-size: cover;
} }
#canvas { #canvas {
...@@ -10,10 +12,28 @@ ...@@ -10,10 +12,28 @@
} }
@font-face @font-face
{ {
font-family: 'BRLNSDB'; font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ; src: url("../../assets/play/font/BRLNSDB_1.TTF")
}
@font-face
{
font-family: 'Aileron-Black';
src: url("../../assets/play/font/Aileron-Black.ttf")
}
@font-face
{
font-family: 'Aileron-Bold';
src: url("../../assets/play/font/Aileron-Bold.ttf")
} }
@font-face
{
font-family: 'DroidSansFallback';
src: url("../../assets/play/font/DroidSansFallback.ttf");
}
\ No newline at end of file
<div class="game-container" #wrap> <span style="font-family:'DroidSansFallback'" ></span>
<canvas id="canvas" #canvas></canvas> <span style="font-family:'Aileron-Black'" ></span>
<span style="font-family:'Aileron-Bold'" ></span>
<ng-template #tpl>
<video></video>
</ng-template>
<div style="display: none" #videoContainer></div>
<div class="game-container" #wrap >
<canvas id="canvas" style="width: 100%; height: 100%;" #canvas></canvas>
</div> </div>
<div id='div_input'>
</div>
<!-- <div style="position: absolute; top: 0">
<label style="font-family: Aileron-Black;"></label>
<label style="font-family: DroidSansFallback;"></label>
</div> -->
This diff is collapsed.
const res = [ const res = [
// ['bg', "assets/play/bg.jpg"], ['op_item', "assets/play/op_item.png"],
['btn_left', "assets/play/btn_left.png"], ['op_item_wrong', "assets/play/op_item_wrong.png"],
['btn_right', "assets/play/btn_right.png"], ['op_item_right', "assets/play/op_item_right.png"],
// ['text_bg', "assets/play/text_bg.png"], ['op_item_normal', "assets/play/op_item_normal.png"],
['btn_close', "assets/play/btn_close.png"],
['bg', "assets/play/bg.jpg"],
['video_bg', "assets/play/video_bg.jpg"],
['btn_replay', "assets/play/btn_replay.png"],
['icon_right', "assets/play/icon_right.png"],
['icon_wrong', "assets/play/icon_wrong.png"],
['answer_normal', "assets/play/answer_normal.png"],
['answer_right', "assets/play/answer_right.png"],
['answer_wrong', "assets/play/answer_wrong.png"],
['btn_video', "assets/play/btn_video.png"],
['btn_write', "assets/play/btn_write.png"],
]; ];
...@@ -12,7 +26,14 @@ const res = [ ...@@ -12,7 +26,14 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"], ['click', "assets/play/music/click.mp3"],
['submit', "assets/play/music/submit.mp3"],
['more', "assets/play/music/more.mp3"],
]; ];
export {res, resAudio}; export {res, resAudio};
This diff is collapsed.
File mode changed from 100644 to 100755
<?xml version="1.0" encoding="UTF-8"?>
<svg width="31px" height="23px" viewBox="0 0 31 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 62 (91390) - https://sketch.com -->
<title>up</title>
<desc>Created with Sketch.</desc>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1-学科键盘" transform="translate(-1779.000000, -808.000000)">
<g id="输入框">
<g id="keyboard_light_landscape" transform="translate(0.000000, 585.000000)">
<g id="编组" transform="translate(1698.750000, 26.250000)">
<g id="上翻" transform="translate(50.625000, 163.125000)">
<g>
<rect id="key-boarder" fill="#313C42" opacity="0" x="0" y="0" width="90" height="90" rx="3.76"></rect>
<path d="M48.0085956,35.2507117 L59.3110016,50.5843863 C60.4979164,52.1946422 60.1130426,54.4324199 58.4513618,55.5826026 C57.8242714,56.0166623 57.072896,56.25 56.3022624,56.25 L33.6974504,56.25 C31.6554049,56.25 30,54.6458257 30,52.6669764 C30,51.920192 30.2407896,51.1920698 30.6887113,50.5843863 L41.9911172,35.2507117 C43.1780321,33.6404558 45.4872751,33.2674929 47.1489558,34.4176757 C47.4809703,34.6474896 47.7714424,34.9289723 48.0085956,35.2507117 Z" id="矩形" fill="#7F8B8F"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="31px" height="23px" viewBox="0 0 31 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 62 (91390) - https://sketch.com -->
<title>down</title>
<desc>Created with Sketch.</desc>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1-学科键盘" transform="translate(-1779.000000, -954.000000)">
<g id="输入框">
<g id="keyboard_light_landscape" transform="translate(0.000000, 585.000000)">
<g id="编组" transform="translate(1698.750000, 26.250000)">
<g id="下翻" transform="translate(50.625000, 309.375000)">
<g>
<rect id="key-boarder" fill="#313C42" opacity="0" x="0" y="0" width="90" height="90" rx="3.76"></rect>
<path d="M48.0085956,54.7492883 L59.3110016,39.4156137 C60.4979164,37.8053578 60.1130426,35.5675801 58.4513618,34.4173974 C57.8242714,33.9833377 57.072896,33.75 56.3022624,33.75 L33.6974504,33.75 C31.6554049,33.75 30,35.3541743 30,37.3330236 C30,38.079808 30.2407896,38.8079302 30.6887113,39.4156137 L41.9911172,54.7492883 C43.1780321,56.3595442 45.4872751,56.7325071 47.1489558,55.5823243 C47.4809703,55.3525104 47.7714424,55.0710277 48.0085956,54.7492883 Z" id="矩形" fill="#7F8B8F"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="31px" height="23px" viewBox="0 0 31 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 62 (91390) - https://sketch.com -->
<title>down</title>
<desc>Created with Sketch.</desc>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1-学科键盘" transform="translate(-1779.000000, -954.000000)">
<g id="输入框">
<g id="keyboard_light_landscape" transform="translate(0.000000, 585.000000)">
<g id="编组" transform="translate(1698.750000, 26.250000)">
<g id="下翻" transform="translate(50.625000, 309.375000)">
<g>
<rect id="key-boarder" fill="#313C42" opacity="0" x="0" y="0" width="90" height="90" rx="3.76"></rect>
<path d="M48.0085956,54.7492883 L59.3110016,39.4156137 C60.4979164,37.8053578 60.1130426,35.5675801 58.4513618,34.4173974 C57.8242714,33.9833377 57.072896,33.75 56.3022624,33.75 L33.6974504,33.75 C31.6554049,33.75 30,35.3541743 30,37.3330236 C30,38.079808 30.2407896,38.8079302 30.6887113,39.4156137 L41.9911172,54.7492883 C43.1780321,56.3595442 45.4872751,56.7325071 47.1489558,55.5823243 C47.4809703,55.3525104 47.7714424,55.0710277 48.0085956,54.7492883 Z" id="矩形" fill="#7F8B8F"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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