├── src ├── assets │ ├── .gitkeep │ ├── images │ │ ├── logo.ico │ │ ├── logo.png │ │ ├── p1.jpg │ │ ├── u1.png │ │ ├── u2.png │ │ ├── u3.png │ │ ├── u4.png │ │ ├── u5.png │ │ ├── u6.png │ │ ├── v1.png │ │ ├── v2.png │ │ ├── v3.png │ │ ├── v4.png │ │ ├── v5.png │ │ └── git_logo.png │ ├── libs │ │ ├── console.js │ │ └── typescript.compile.js │ └── data │ │ └── pens.json ├── app │ ├── app.component.sass │ ├── full-screen │ │ ├── full-screen.component.sass │ │ ├── full-screen.component.html │ │ ├── full-screen.component.spec.ts │ │ └── full-screen.component.ts │ ├── pen │ │ ├── help-dialog │ │ │ ├── help-dialog.component.spec.ts │ │ │ ├── help-dialog.component.scss │ │ │ ├── help-dialog.component.html │ │ │ └── help-dialog.component.ts │ │ ├── pen.service.spec.ts │ │ ├── pen.service.ts │ │ ├── pen.component.spec.ts │ │ ├── js-dialog │ │ │ ├── js-dialog.component.spec.ts │ │ │ ├── js-dialog.component.scss │ │ │ ├── js-dialog.component.ts │ │ │ └── js-dialog.component.html │ │ ├── css-dialog │ │ │ ├── css-dialog.component.spec.ts │ │ │ ├── css-dialog.component.scss │ │ │ ├── css-dialog.component.html │ │ │ └── css-dialog.component.ts │ │ ├── pen.component.scss │ │ ├── pen.component.html │ │ └── pen.component.ts │ ├── app.component.html │ ├── home │ │ ├── praise-dialog │ │ │ ├── praise-dialog.component.html │ │ │ ├── praise-dialog.component.scss │ │ │ ├── praise-dialog.component.ts │ │ │ └── praise-dialog.component.spec.ts │ │ ├── home.service.ts │ │ ├── home.component.spec.ts │ │ ├── home.component.html │ │ ├── home.component.ts │ │ └── home.component.scss │ ├── app.component.ts │ ├── app-routing.module.ts │ ├── app.component.spec.ts │ ├── console.js │ └── app.module.ts ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── main.ts ├── index.html ├── test.ts ├── styles.sass └── polyfills.ts ├── e2e ├── tsconfig.json ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts └── protractor.conf.js ├── .editorconfig ├── .travis.yml ├── tsconfig.app.json ├── tsconfig.spec.json ├── browserslist ├── tsconfig.json ├── .gitignore ├── karma.conf.js ├── README.md ├── docs └── english.md ├── package.json ├── tslint.json └── angular.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.sass: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/full-screen/full-screen.component.sass: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/pen/help-dialog/help-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/assets/images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/logo.ico -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/assets/images/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/p1.jpg -------------------------------------------------------------------------------- /src/assets/images/u1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/u1.png -------------------------------------------------------------------------------- /src/assets/images/u2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/u2.png -------------------------------------------------------------------------------- /src/assets/images/u3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/u3.png -------------------------------------------------------------------------------- /src/assets/images/u4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/u4.png -------------------------------------------------------------------------------- /src/assets/images/u5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/u5.png -------------------------------------------------------------------------------- /src/assets/images/u6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/u6.png -------------------------------------------------------------------------------- /src/assets/images/v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/v1.png -------------------------------------------------------------------------------- /src/assets/images/v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/v2.png -------------------------------------------------------------------------------- /src/assets/images/v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/v3.png -------------------------------------------------------------------------------- /src/assets/images/v4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/v4.png -------------------------------------------------------------------------------- /src/assets/images/v5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/v5.png -------------------------------------------------------------------------------- /src/assets/images/git_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/renhongl/code-online/HEAD/src/assets/images/git_logo.png -------------------------------------------------------------------------------- /src/app/full-screen/full-screen.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/home/praise-dialog/praise-dialog.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | p 4 |
5 | -------------------------------------------------------------------------------- /src/app/home/praise-dialog/praise-dialog.component.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | .search-con{ 4 | width: 100%; 5 | height: 100%; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | } -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.sass'] 7 | }) 8 | export class AppComponent { 9 | title = 'code-online'; 10 | } 11 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pen/help-dialog/help-dialog.component.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | .help{ 4 | width: 100%; 5 | height: 100%; 6 | 7 | h4{ 8 | margin-bottom: 10px; 9 | } 10 | 11 | p { 12 | line-height: 30px; 13 | color: gray; 14 | font-size: 12px; 15 | } 16 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: node_js 3 | node_js: 4 | - "12" 5 | cache: 6 | directories: 7 | - node_modules 8 | script: 9 | - npm run build 10 | 11 | 12 | deploy: 13 | provider: pages 14 | skip_cleanup: true 15 | github_token: $GITHUB_TOKEN 16 | local_dir: dist/code-online 17 | on: 18 | branch: master -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | 5 | const routes: Routes = []; 6 | 7 | @NgModule({ 8 | imports: [RouterModule.forRoot(routes)], 9 | exports: [RouterModule] 10 | }) 11 | export class AppRoutingModule { } 12 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.ts" 13 | ], 14 | "exclude": [ 15 | "src/test.ts", 16 | "src/**/*.spec.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/app/home/home.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class HomeService { 8 | 9 | constructor(private http: HttpClient) { } 10 | 11 | getPens() { 12 | return this.http.get('/code-online/assets/data/pens.json'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/pen/help-dialog/help-dialog.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Hot Key

3 |

Ctrl-Alt-F: Format

4 |

Ctrl-F: Search

5 |

Ctrl-Shift-F: Replace

6 |

Ctrl-Shift-R: Replace all

7 |

Ctrl-D: Delete one line

8 |

Ctrl-Z: Undo

9 |

Ctrl-Y: Redo

10 |

Ctrl-/: Comment

11 |

Ctrl-Alt-/: Uncomment

12 |
13 | -------------------------------------------------------------------------------- /src/app/pen/pen.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PenService } from './pen.service'; 4 | 5 | describe('PenService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: PenService = TestBed.get(PenService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/pen/pen.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class PenService { 8 | 9 | constructor(private http: HttpClient) { } 10 | 11 | searchPath(word: string) { 12 | return this.http.get('https://api.cdnjs.com/libraries?search=' + word + '&fields=description'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import 'hammerjs'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | import { environment } from './environments/environment'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /src/app/pen/help-dialog/help-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; 3 | import { PenComponent } from '../pen.component'; 4 | 5 | @Component({ 6 | selector: 'app-help-dialog', 7 | templateUrl: './help-dialog.component.html', 8 | styleUrls: ['./help-dialog.component.scss'] 9 | }) 10 | export class HelpDialogComponent implements OnInit { 11 | 12 | constructor( 13 | public dialogRef: MatDialogRef, 14 | @Inject(MAT_DIALOG_DATA) public data) { 15 | } 16 | 17 | ngOnInit() { 18 | 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Code Online 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/home/praise-dialog/praise-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; 3 | import { HomeComponent } from '../home.component'; 4 | 5 | @Component({ 6 | selector: 'app-praise-dialog', 7 | templateUrl: './praise-dialog.component.html', 8 | styleUrls: ['./praise-dialog.component.scss'] 9 | }) 10 | export class PraiseDialogComponent implements OnInit { 11 | 12 | constructor( 13 | public dialogRef: MatDialogRef, 14 | @Inject(MAT_DIALOG_DATA) public data) { 15 | } 16 | 17 | ngOnInit() { 18 | 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/app/pen/pen.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PenComponent } from './pen.component'; 4 | 5 | describe('PenComponent', () => { 6 | let component: PenComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PenComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PenComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('code-online app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pen/js-dialog/js-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { JsDialogComponent } from './js-dialog.component'; 4 | 5 | describe('JsDialogComponent', () => { 6 | let component: JsDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ JsDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(JsDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/pen/css-dialog/css-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CssDialogComponent } from './css-dialog.component'; 4 | 5 | describe('CssDialogComponent', () => { 6 | let component: CssDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CssDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CssDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/full-screen/full-screen.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FullScreenComponent } from './full-screen.component'; 4 | 5 | describe('FullScreenComponent', () => { 6 | let component: FullScreenComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ FullScreenComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(FullScreenComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/home/praise-dialog/praise-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PraiseDialogComponent } from './praise-dialog.component'; 4 | 5 | describe('PraiseDialogComponent', () => { 6 | let component: PraiseDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PraiseDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PraiseDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/code-online'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'code-online'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.debugElement.componentInstance; 26 | expect(app.title).toEqual('code-online'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.debugElement.nativeElement; 33 | expect(compiled.querySelector('.content span').textContent).toContain('code-online app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JS在线编辑器: 2 | 3 | 4 | 是一个Javascript在线编辑器。 5 | 6 | 是一个完全由前端语言Angular开发的编辑器, 没有服务器端。 7 | 8 | 在线演示: [Demo](https://renhongl.github.io/code-online#/) 9 | 10 | example2 11 | 12 | example2 13 | 14 | example1 15 | 16 | example2 17 | 18 | # 文档 19 | 20 | - [简体中文](https://github.com/renhongl/code-online) 21 | - [English](https://github.com/renhongl/code-online/blob/master/docs/english.md) 22 | 23 | # 新特性 24 | 25 | - 支持切换编辑器视角区域 26 | - 支持全屏预览,并且实时更新 27 | - 支持导出整个页面源代码 28 | - 编辑器增强 29 | - 控制台可视化 30 | - 作品展示页面 31 | 32 | 你也可以: 33 | 34 | - 添加JS或者CSS库来创作更丰富的应用 35 | - 在Babel环境中使用更新的ES语法 36 | 37 | # 使用技术 38 | 39 | 编辑器使用了如下一些技术: 40 | 41 | - [Angular]() - 网页增强库 42 | - [CodeMirror]() - 多才多艺的文本编辑器 43 | - [GitPages]() - 代码保存与部署 44 | - [Travis]() - 自动测试与部署 45 | 46 | # 安装 47 | 48 | 编辑器需要 [Node.js]() v8+ 去运行. 49 | 50 | - 安装依赖: `npm install` 51 | - 打包应用: `npm run build` 52 | 53 | # 正在实现的列表 54 | 55 | - 多文件的项目开发支持 56 | - 主页例子展示,他人可通过提交代码添加例子 57 | 58 | # 许可证 59 | 60 | MIT 61 | -------------------------------------------------------------------------------- /src/styles.sass: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | 4 | html, body 5 | width: 100% 6 | height: 100% 7 | padding: 0 8 | margin: 0 9 | overflow-x: hidden 10 | overflow-y: auto 11 | position: relative 12 | 13 | * 14 | padding: 0 15 | margin: 0 16 | 17 | div, p, ul, ol, li, h1, h2, h3, h4, h5, h6 18 | padding: 0 19 | margin: 0 20 | 21 | .CodeMirror 22 | height: 100% !important 23 | 24 | .CodeMirror pre.CodeMirror-line, .CodeMirror pre.CodeMirror-line-like 25 | padding-left: 20px !important 26 | 27 | 28 | .CodeMirror-activeline-background 29 | margin-left: 20px !important 30 | 31 | .CodeMirror-dialog-top 32 | position: absolute 33 | right: 0px !important 34 | top: 0px 35 | background: #313131 36 | width: auto 37 | height: 30px 38 | line-height: 30px 39 | padding: 0px 5px 40 | z-index: 10000 41 | 42 | .CodeMirror-search-hint 43 | display: none 44 | 45 | input 46 | outline: none 47 | background: #424242 48 | border: none 49 | padding: 2px 5px 50 | color: #fff 51 | 52 | ::-webkit-scrollbar 53 | width: 5px 54 | height: 5px 55 | 56 | 57 | ::-webkit-scrollbar-track 58 | background: #5c5c5c 59 | 60 | 61 | ::-webkit-scrollbar-thumb 62 | background: #888 63 | 64 | ::-webkit-scrollbar-thumb:hover 65 | background: #555 -------------------------------------------------------------------------------- /src/app/pen/js-dialog/js-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .example-full-width { 2 | width: calc(100% - 40px); 3 | } 4 | 5 | .close-btn{ 6 | float: right; 7 | } 8 | 9 | .search-con{ 10 | position: relative; 11 | } 12 | 13 | .path-view{ 14 | font-size: 12px; 15 | color: gray; 16 | } 17 | 18 | .add-more { 19 | display: flex; 20 | align-items: center; 21 | font-size: 12px; 22 | border: 1px solid gray; 23 | width: 150px; 24 | border-radius: 5px; 25 | height: 30px; 26 | cursor: pointer; 27 | 28 | &:hover{ 29 | border: 1px solid #3f51b5; 30 | color: #3f51b5; 31 | } 32 | } 33 | 34 | .search-result { 35 | position: absolute; 36 | background: #4c4a4a; 37 | width: 100%; 38 | z-index: 100; 39 | color: #fff; 40 | top: 44px; 41 | border-radius: 5px; 42 | 43 | .one-result{ 44 | padding: 5px 10px; 45 | border-bottom: 1px solid gray; 46 | cursor: pointer; 47 | 48 | &:hover{ 49 | background: #353535; 50 | } 51 | 52 | span.name { 53 | display: block; 54 | height: 30px; 55 | line-height: 30px; 56 | font-size: 17px; 57 | } 58 | 59 | span.desc { 60 | height: 20px; 61 | font-size: 12px; 62 | color: gray; 63 | } 64 | } 65 | } 66 | 67 | .mat-dialog-content{ 68 | overflow: hidden !important; 69 | 70 | // .path-action{ 71 | // display: inline-block; 72 | // width: 30px; 73 | // height: 30px; 74 | // line-height: 30px; 75 | // } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/app/pen/css-dialog/css-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .example-full-width { 2 | width: calc(100% - 40px); 3 | } 4 | 5 | .close-btn{ 6 | float: right; 7 | } 8 | 9 | .search-con{ 10 | position: relative; 11 | } 12 | 13 | .path-view{ 14 | font-size: 12px; 15 | color: gray; 16 | } 17 | 18 | .add-more { 19 | display: flex; 20 | align-items: center; 21 | font-size: 12px; 22 | border: 1px solid gray; 23 | width: 150px; 24 | border-radius: 5px; 25 | height: 30px; 26 | cursor: pointer; 27 | 28 | &:hover{ 29 | border: 1px solid #3f51b5; 30 | color: #3f51b5; 31 | } 32 | } 33 | 34 | .search-result { 35 | position: absolute; 36 | background: #4c4a4a; 37 | width: 100%; 38 | z-index: 100; 39 | color: #fff; 40 | top: 44px; 41 | border-radius: 5px; 42 | 43 | .one-result{ 44 | padding: 5px 10px; 45 | border-bottom: 1px solid gray; 46 | cursor: pointer; 47 | 48 | &:hover{ 49 | background: #353535; 50 | } 51 | 52 | span.name { 53 | display: block; 54 | height: 30px; 55 | line-height: 30px; 56 | font-size: 17px; 57 | } 58 | 59 | span.desc { 60 | height: 20px; 61 | font-size: 12px; 62 | color: gray; 63 | } 64 | } 65 | } 66 | 67 | .mat-dialog-content{ 68 | overflow: hidden !important; 69 | 70 | // .path-action{ 71 | // display: inline-block; 72 | // width: 30px; 73 | // height: 30px; 74 | // line-height: 30px; 75 | // } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/app/pen/js-dialog/js-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; 3 | import { PenComponent } from '../pen.component'; 4 | import { PenService } from '../pen.service'; 5 | 6 | @Component({ 7 | selector: 'app-js-dialog', 8 | templateUrl: './js-dialog.component.html', 9 | styleUrls: ['./js-dialog.component.scss'] 10 | }) 11 | export class JsDialogComponent implements OnInit { 12 | 13 | list: Array; 14 | searchResult: any; 15 | searchWord: string; 16 | timer: any; 17 | mode: string; 18 | 19 | constructor( 20 | public dialogRef: MatDialogRef, 21 | @Inject(MAT_DIALOG_DATA) public data, 22 | private penSer: PenService) { 23 | } 24 | 25 | ngOnInit() { 26 | this.list = this.data.jsLibrary; 27 | this.mode = this.data.mode; 28 | } 29 | 30 | onClose(): void { 31 | this.dialogRef.close({ jsLibrary: this.list, mode: this.mode }); 32 | } 33 | 34 | search() { 35 | if (this.timer) { 36 | clearTimeout(this.timer); 37 | } 38 | this.timer = setTimeout(() => { 39 | this.penSer.searchPath(this.searchWord).subscribe(data => { 40 | this.searchResult = data['results']; 41 | }); 42 | }, 1000); 43 | } 44 | 45 | add(value) { 46 | this.list.push(value); 47 | this.searchResult = []; 48 | this.searchWord = ''; 49 | } 50 | 51 | remove(i) { 52 | this.list.splice(i, 1); 53 | } 54 | 55 | addOneItem() { 56 | this.list.push(''); 57 | } 58 | 59 | updateItem(i, e) { 60 | this.list[i] = e.target.value; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /docs/english.md: -------------------------------------------------------------------------------- 1 | # JS Online Editor: 2 | 3 | 4 | A javascript online editor. 5 | 6 | An editor developed by angular, no server support. 7 | 8 | Online Demo: [Demo](https://renhongl.github.io/code-online#/) 9 | 10 | 11 | example2 12 | 13 | example2 14 | 15 | example1 16 | 17 | example2 18 | 19 | # Docs 20 | 21 | - [简体中文](https://github.com/renhongl/code-online) 22 | - [English](https://github.com/renhongl/code-online/blob/master/docs/english.md) 23 | 24 | # New Features 25 | 26 | 27 | 28 | - Support switch view 29 | - Support display on full screen and update automaticly 30 | - Support export source code of this page 31 | - Editor enhence 32 | - Console visualization 33 | - Demo explore 34 | 35 | You Can Also: 36 | 37 | - Add JS and Css library to create prolific application 38 | - Use newest syntax in babel environment 39 | 40 | # Using Tech 41 | 42 | Technology used as below: 43 | 44 | - [Angular]() - Web enhenced library 45 | - [CodeMirror]() - Versatile text edior 46 | - [GitPages]() - Code store and deploy 47 | - [Travis]() - CICD 48 | 49 | # Installation 50 | 51 | Requires [Node.js]() v8+ to run. 52 | 53 | - Install dependence: `npm install` 54 | - Build app: `npm run build` 55 | 56 | # Todos 57 | 58 | - Mutiple file project support 59 | - Home page show demos, people can push demo by commit code 60 | 61 | # License 62 | 63 | MIT 64 | -------------------------------------------------------------------------------- /src/app/pen/js-dialog/js-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Add JS Library

3 | 4 | JavaScript Preprocessor 5 | 6 | 7 | None 8 | 9 | 10 | Babel 11 | 12 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 24 |
25 |
26 | {{item.name}} 27 | {{item.description}} 28 |
29 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | 39 |
40 |
41 | 44 | Add Another Lib 45 |
46 |
47 | -------------------------------------------------------------------------------- /src/app/pen/css-dialog/css-dialog.component.html: -------------------------------------------------------------------------------- 1 |

Add CSS Library

3 | 20 |
21 | 22 | 23 | 24 | 27 |
28 |
29 | {{item.name}} 30 | {{item.description}} 31 |
32 |
33 |
34 |
35 |
36 | 37 | 38 | 39 | 42 |
43 |
44 | 47 | Add Another Lib 48 |
49 |
50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "code-online", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve --deployUrl /code-online/", 7 | "build": "ng build --deployUrl /code-online/", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~8.2.13", 15 | "@angular/cdk": "~8.2.3", 16 | "@angular/common": "~8.2.13", 17 | "@angular/compiler": "~8.2.13", 18 | "@angular/core": "~8.2.13", 19 | "@angular/forms": "~8.2.13", 20 | "@angular/material": "^8.2.3", 21 | "@angular/platform-browser": "~8.2.13", 22 | "@angular/platform-browser-dynamic": "~8.2.13", 23 | "@angular/router": "~8.2.13", 24 | "angular-split": "^3.0.2", 25 | "codemirror": "^5.49.2", 26 | "codemirror-console": "^2.0.1", 27 | "codemirror-console-ui": "^2.0.5", 28 | "codemirror-formatting": "^1.0.0", 29 | "csslint": "^1.0.5", 30 | "emmet-codemirror": "^1.2.5", 31 | "hammerjs": "^2.0.8", 32 | "htmlhint": "^0.11.0", 33 | "jshint": "^2.10.3", 34 | "rxjs": "~6.4.0", 35 | "tslib": "^1.10.0", 36 | "zone.js": "~0.9.1" 37 | }, 38 | "devDependencies": { 39 | "@angular-devkit/build-angular": "~0.803.17", 40 | "@angular/cli": "~8.3.17", 41 | "@angular/compiler-cli": "~8.2.13", 42 | "@angular/language-service": "~8.2.13", 43 | "@types/node": "~8.9.4", 44 | "@types/jasmine": "~3.3.8", 45 | "@types/jasminewd2": "~2.0.3", 46 | "codelyzer": "^5.0.0", 47 | "jasmine-core": "~3.4.0", 48 | "jasmine-spec-reporter": "~4.2.1", 49 | "karma": "~4.1.0", 50 | "karma-chrome-launcher": "~2.2.0", 51 | "karma-coverage-istanbul-reporter": "~2.0.1", 52 | "karma-jasmine": "~2.0.1", 53 | "karma-jasmine-html-reporter": "^1.4.0", 54 | "protractor": "~5.4.0", 55 | "ts-node": "~7.0.0", 56 | "tslint": "~5.15.0", 57 | "typescript": "~3.5.3" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/app/pen/css-dialog/css-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; 3 | import { PenComponent } from '../pen.component'; 4 | import { PenService } from '../pen.service'; 5 | 6 | @Component({ 7 | selector: 'app-css-dialog', 8 | templateUrl: './css-dialog.component.html', 9 | styleUrls: ['./css-dialog.component.scss'] 10 | }) 11 | export class CssDialogComponent implements OnInit { 12 | 13 | list: Array; 14 | searchResult: any; 15 | searchWord: string; 16 | timer: any; 17 | cssMode: string; 18 | 19 | constructor( 20 | public dialogRef: MatDialogRef, 21 | @Inject(MAT_DIALOG_DATA) public data, 22 | private penSer: PenService) { 23 | } 24 | 25 | ngOnInit() { 26 | this.list = this.data.cssLibrary; 27 | this.cssMode = this.data.cssMode; 28 | } 29 | 30 | onClose(): void { 31 | this.dialogRef.close({ cssLibrary: this.list, mode: this.cssMode }); 32 | } 33 | 34 | getCssFile(list) { 35 | return list.filter(item => { 36 | const n = item.latest; 37 | const arr = n.split('.'); 38 | const types = ['css', 'CSS', 'Css', 'scss', 'less']; 39 | const type = arr[arr.length - 1]; 40 | if (types.includes(type)) { 41 | return true; 42 | } 43 | return false; 44 | }); 45 | } 46 | 47 | search() { 48 | if (this.timer) { 49 | clearTimeout(this.timer); 50 | } 51 | this.timer = setTimeout(() => { 52 | this.penSer.searchPath(this.searchWord + '.css').subscribe(data => { 53 | this.searchResult = this.getCssFile(data['results']); 54 | }); 55 | }, 1000); 56 | } 57 | 58 | add(value) { 59 | this.list.push(value); 60 | this.searchResult = []; 61 | this.searchWord = ''; 62 | } 63 | 64 | remove(i) { 65 | this.list.splice(i, 1); 66 | } 67 | 68 | addOneItem() { 69 | this.list.push(''); 70 | } 71 | 72 | updateItem(i, e) { 73 | this.list[i] = e.target.value; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/app/console.js: -------------------------------------------------------------------------------- 1 | window['console'] = { 2 | log: (text) => { 3 | // try { 4 | // if (typeof text !== 'string') { 5 | // text = JSON.stringify(text); 6 | // } 7 | // const output = window.parent.document.getElementById('output'); 8 | // const div = document.createElement('div'); 9 | // div.setAttribute('class', 'output-log'); 10 | // div.setAttribute('style', 'color: #c3c3c3; padding-left: 10px;background: #6d6d6d; height: 30px; line-height: 30px;border-bottom: 1px solid gray;text-overflow:ellipsis;white-space:nowrap;padding-right:10px;width:98%;overflow:hidden;'); 11 | // div.appendChild(document.createTextNode(text)); 12 | // output.appendChild(div); 13 | // } catch (error) { 14 | // console.log(error); 15 | // } 16 | }, 17 | error: (text) => { 18 | // if (typeof text !== 'string') { 19 | // text = JSON.stringify(text); 20 | // } 21 | // const output = window.parent.document.getElementById('output'); 22 | // const div = document.createElement('div'); 23 | // div.setAttribute('class', 'output-error'); 24 | // div.setAttribute('style', 'color: red; padding-left: 10px;background: #734141; height: 30px; line-height: 30px;border-bottom: 1px solid gray;text-overflow:ellipsis;white-space:nowrap;padding-right:10px;width:98%;overflow:hidden;'); 25 | // div.appendChild(document.createTextNode(text)); 26 | // output.appendChild(div); 27 | }, 28 | warn: (text) => { 29 | // if (typeof text !== 'string') { 30 | // text = JSON.stringify(text); 31 | // } 32 | // const output = window.parent.document.getElementById('output'); 33 | // const div = document.createElement('div'); 34 | // div.setAttribute('class', 'output-warn'); 35 | // div.setAttribute('style', 'color: #ffd400; padding-left: 10px;background: #6c6d29; height: 30px; line-height: 30px;border-bottom: 1px solid gray;text-overflow:ellipsis;white-space:nowrap;padding-right:10px;width:98%;overflow:hidden;'); 36 | // div.appendChild(document.createTextNode(text)); 37 | // output.appendChild(div); 38 | } 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /src/assets/libs/console.js: -------------------------------------------------------------------------------- 1 | window['console'] = { 2 | log: (text) => { 3 | try { 4 | if (typeof text !== 'string') { 5 | text = JSON.stringify(text); 6 | } 7 | const output = window.parent.document.getElementById('output'); 8 | const div = document.createElement('div'); 9 | div.setAttribute('class', 'output-log'); 10 | div.setAttribute('style', 'color: #c3c3c3; padding-left: 10px;background: #6d6d6d; height: 30px; line-height: 30px;border-bottom: 1px solid gray;text-overflow:ellipsis;white-space:nowrap;padding-right:10px;width:100%;overflow:hidden;'); 11 | div.appendChild(document.createTextNode(text)); 12 | output.appendChild(div); 13 | div.scrollIntoView(); 14 | } catch (error) { 15 | console.error(error); 16 | } 17 | }, 18 | error: (text) => { 19 | if (typeof text !== 'string') { 20 | text = JSON.stringify(text); 21 | } 22 | const output = window.parent.document.getElementById('output'); 23 | const div = document.createElement('div'); 24 | div.setAttribute('class', 'output-error'); 25 | div.setAttribute('style', 'color: red; padding-left: 10px;background: #734141; height: 30px; line-height: 30px;border-bottom: 1px solid gray;text-overflow:ellipsis;white-space:nowrap;padding-right:10px;width:100%;overflow:hidden;'); 26 | div.appendChild(document.createTextNode(text)); 27 | output.appendChild(div); 28 | div.scrollIntoView(); 29 | }, 30 | warn: (text) => { 31 | if (typeof text !== 'string') { 32 | text = JSON.stringify(text); 33 | } 34 | const output = window.parent.document.getElementById('output'); 35 | const div = document.createElement('div'); 36 | div.setAttribute('class', 'output-warn'); 37 | div.setAttribute('style', 'color: #ffd400; padding-left: 10px;background: #6c6d29; height: 30px; line-height: 30px;border-bottom: 1px solid gray;text-overflow:ellipsis;white-space:nowrap;padding-right:10px;width:100%;overflow:hidden;'); 38 | div.appendChild(document.createTextNode(text)); 39 | output.appendChild(div); 40 | div.scrollIntoView(); 41 | } 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warning" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase" 17 | ], 18 | "component-selector": [ 19 | true, 20 | "element", 21 | "app", 22 | "kebab-case" 23 | ], 24 | "import-blacklist": [ 25 | true, 26 | "rxjs/Rx" 27 | ], 28 | "interface-name": false, 29 | "max-classes-per-file": false, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-consecutive-blank-lines": false, 47 | "no-console": [ 48 | true, 49 | "debug", 50 | "info", 51 | "time", 52 | "timeEnd", 53 | "trace" 54 | ], 55 | "no-empty": false, 56 | "no-inferrable-types": [ 57 | true, 58 | "ignore-params" 59 | ], 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-switch-case-fall-through": true, 63 | "no-var-requires": false, 64 | "object-literal-key-quotes": [ 65 | true, 66 | "as-needed" 67 | ], 68 | "object-literal-sort-keys": false, 69 | "ordered-imports": false, 70 | "quotemark": [ 71 | true, 72 | "single" 73 | ], 74 | "trailing-comma": false, 75 | "no-conflicting-lifecycle": true, 76 | "no-host-metadata-property": true, 77 | "no-input-rename": true, 78 | "no-inputs-metadata-property": true, 79 | "no-output-native": true, 80 | "no-output-on-prefix": true, 81 | "no-output-rename": true, 82 | "no-outputs-metadata-property": true, 83 | "template-banana-in-box": true, 84 | "template-no-negated-async": true, 85 | "use-lifecycle-interface": true, 86 | "use-pipe-transform-interface": true 87 | }, 88 | "rulesDirectory": [ 89 | "codelyzer" 90 | ] 91 | } -------------------------------------------------------------------------------- /src/app/full-screen/full-screen.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-full-screen', 5 | templateUrl: './full-screen.component.html', 6 | styleUrls: ['./full-screen.component.sass'] 7 | }) 8 | export class FullScreenComponent implements OnInit { 9 | 10 | showContent: boolean; 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | this.init(); 16 | window.addEventListener('storage', () => { 17 | location.reload(); 18 | }, false); 19 | } 20 | 21 | init() { 22 | this.showContent = false; 23 | this.showContent = true; 24 | setTimeout(() => { 25 | const doc = document.querySelector('iframe').contentDocument; 26 | const content = this.getContent(); 27 | document.title = localStorage.getItem('code-online-title'); 28 | doc.open(); 29 | doc.write(content); 30 | doc.close(); 31 | }, 1000); 32 | } 33 | 34 | writeLinks(arr) { 35 | return arr.map(item => { 36 | return ``; 37 | }); 38 | } 39 | 40 | writeScript(arr) { 41 | return arr.map(item => { 42 | return ``; 43 | }); 44 | } 45 | 46 | getType(mode) { 47 | const typeMapping = { 48 | None: 'text/javascript', 49 | Babel: 'text/babel', 50 | TypeScript: 'text/typescript', 51 | }; 52 | return typeMapping[mode]; 53 | } 54 | 55 | getContent() { 56 | const mode = localStorage.getItem('code-online-mode'); 57 | const jsLibs = JSON.parse(localStorage.getItem('code-online-jsLib')); 58 | if (mode === 'Babel') { 59 | jsLibs.unshift('https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js'); 60 | } 61 | return ` 62 | 63 | 64 | 65 | 66 | Untitled 67 | 68 | ${this.writeLinks(JSON.parse(localStorage.getItem('code-online-cssLib'))).join(',').replace(/,/ig, '')} 69 | 70 | 71 | 72 | ${localStorage.getItem('code-online-html')} 73 | ${this.writeScript(jsLibs).join(',').replace(/,/ig, '')} 74 | 77 | 78 | 79 | `; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 7 | import { PenComponent } from './pen/pen.component'; 8 | import { AngularSplitModule } from 'angular-split'; 9 | import { MatButtonModule } from '@angular/material/button'; 10 | import { MatIconModule } from '@angular/material/icon'; 11 | import { MatDialogModule } from '@angular/material/dialog'; 12 | import { JsDialogComponent } from './pen/js-dialog/js-dialog.component'; 13 | import { CssDialogComponent } from './pen/css-dialog/css-dialog.component'; 14 | import { MatInputModule } from '@angular/material/input'; 15 | import { FormsModule } from '@angular/forms'; 16 | import { HttpClientModule } from '@angular/common/http'; 17 | import { MatSelectModule } from '@angular/material/select'; 18 | import { MatMenuModule } from '@angular/material/menu'; 19 | import { Routes, RouterModule } from '@angular/router'; 20 | import { FullScreenComponent } from './full-screen/full-screen.component'; 21 | import { MatTooltipModule } from '@angular/material/tooltip'; 22 | import { HomeComponent } from './home/home.component'; 23 | import { PraiseDialogComponent } from './home/praise-dialog/praise-dialog.component'; 24 | import { HelpDialogComponent } from './pen/help-dialog/help-dialog.component'; 25 | 26 | const appRoutes: Routes = [ 27 | { path: '', component: HomeComponent }, 28 | { path: 'pen', component: PenComponent }, 29 | { path: 'fullScreen', component: FullScreenComponent }, 30 | ]; 31 | 32 | @NgModule({ 33 | declarations: [ 34 | AppComponent, 35 | PenComponent, 36 | JsDialogComponent, 37 | FullScreenComponent, 38 | CssDialogComponent, 39 | HomeComponent, 40 | PraiseDialogComponent, 41 | HelpDialogComponent 42 | ], 43 | imports: [ 44 | BrowserModule, 45 | AppRoutingModule, 46 | RouterModule.forRoot(appRoutes, { useHash: true }), 47 | BrowserAnimationsModule, 48 | AngularSplitModule.forRoot(), 49 | MatButtonModule, 50 | MatIconModule, 51 | MatDialogModule, 52 | MatInputModule, 53 | FormsModule, 54 | HttpClientModule, 55 | MatSelectModule, 56 | MatMenuModule, 57 | MatTooltipModule, 58 | ], 59 | entryComponents: [ 60 | JsDialogComponent, 61 | CssDialogComponent, 62 | PraiseDialogComponent, 63 | HelpDialogComponent 64 | ], 65 | providers: [], 66 | bootstrap: [AppComponent] 67 | }) 68 | export class AppModule { } 69 | -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | CODE ONLINE 6 | 7 |
8 | 11 |
12 | search 13 |
14 |
15 | 16 | 19 | 20 | 23 | 24 | 27 |
28 | 29 |
30 | 31 |
32 | Picked Pens 33 |
34 | 35 |
36 |
37 | 38 |
39 | 40 |
41 |
42 | 43 | {{item['code-online-title']}} 44 | {{item.author}} 45 | 48 |
49 |
50 |
51 |
52 | 53 | 61 | 62 |
63 | Powered by © Pomelo 64 | QQ: 1075220132 65 | QQ Mail: 1075220132@qq.com 66 | Gmail Mail: liangrenhong2017@gmail.com 67 |
68 | 69 |
70 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "code-online": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "sass" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/code-online", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": false, 26 | "assets": [ 27 | "src/favicon.ico", 28 | "src/assets" 29 | ], 30 | "styles": [ 31 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 32 | "src/styles.sass", 33 | "node_modules/codemirror/lib/codemirror.css", 34 | "node_modules/codemirror/theme/material-darker.css", 35 | "node_modules/codemirror/theme/monokai.css", 36 | "node_modules/codemirror/addon/lint/lint.css" 37 | ], 38 | "scripts": [ 39 | 40 | ] 41 | }, 42 | "configurations": { 43 | "production": { 44 | "fileReplacements": [ 45 | { 46 | "replace": "src/environments/environment.ts", 47 | "with": "src/environments/environment.prod.ts" 48 | } 49 | ], 50 | "optimization": true, 51 | "outputHashing": "all", 52 | "sourceMap": false, 53 | "extractCss": true, 54 | "namedChunks": false, 55 | "aot": true, 56 | "extractLicenses": true, 57 | "vendorChunk": false, 58 | "buildOptimizer": true, 59 | "budgets": [ 60 | { 61 | "type": "initial", 62 | "maximumWarning": "2mb", 63 | "maximumError": "5mb" 64 | }, 65 | { 66 | "type": "anyComponentStyle", 67 | "maximumWarning": "6kb", 68 | "maximumError": "10kb" 69 | } 70 | ] 71 | } 72 | } 73 | }, 74 | "serve": { 75 | "builder": "@angular-devkit/build-angular:dev-server", 76 | "options": { 77 | "browserTarget": "code-online:build" 78 | }, 79 | "configurations": { 80 | "production": { 81 | "browserTarget": "code-online:build:production" 82 | } 83 | } 84 | }, 85 | "extract-i18n": { 86 | "builder": "@angular-devkit/build-angular:extract-i18n", 87 | "options": { 88 | "browserTarget": "code-online:build" 89 | } 90 | }, 91 | "test": { 92 | "builder": "@angular-devkit/build-angular:karma", 93 | "options": { 94 | "main": "src/test.ts", 95 | "polyfills": "src/polyfills.ts", 96 | "tsConfig": "tsconfig.spec.json", 97 | "karmaConfig": "karma.conf.js", 98 | "assets": [ 99 | "src/favicon.ico", 100 | "src/assets" 101 | ], 102 | "styles": [ 103 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 104 | "src/styles.sass" 105 | ], 106 | "scripts": [] 107 | } 108 | }, 109 | "lint": { 110 | "builder": "@angular-devkit/build-angular:tslint", 111 | "options": { 112 | "tsConfig": [ 113 | "tsconfig.app.json", 114 | "tsconfig.spec.json", 115 | "e2e/tsconfig.json" 116 | ], 117 | "exclude": [ 118 | "**/node_modules/**" 119 | ] 120 | } 121 | }, 122 | "e2e": { 123 | "builder": "@angular-devkit/build-angular:protractor", 124 | "options": { 125 | "protractorConfig": "e2e/protractor.conf.js", 126 | "devServerTarget": "code-online:serve" 127 | }, 128 | "configurations": { 129 | "production": { 130 | "devServerTarget": "code-online:serve:production" 131 | } 132 | } 133 | } 134 | } 135 | } 136 | }, 137 | "defaultProject": "code-online" 138 | } -------------------------------------------------------------------------------- /src/app/pen/pen.component.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | width: 100%; 3 | height: 100%; 4 | 5 | .console-con{ 6 | width: 100%; 7 | height: 100%; 8 | overflow: hidden; 9 | 10 | .console-title { 11 | position: absolute; 12 | top: 0; 13 | /* z-index: 10000; */ 14 | height: 30px !important; 15 | width: 100%; 16 | background: #313131; 17 | line-height: 30px; 18 | color: #b5b5b5; 19 | padding-left: 10px; 20 | font-family: monospace; 21 | font-size: 16px; 22 | } 23 | } 24 | 25 | 26 | 27 | #output { 28 | width: 100%; 29 | height: calc(100% - 30px); 30 | background: #3e3e3e; 31 | overflow-x: hidden; 32 | overflow-y: auto; 33 | margin-top: 30px; 34 | 35 | .output-log{ 36 | height: 25px; 37 | line-height: 25px; 38 | background: #6d6d6d; 39 | color: #c3c3c3; 40 | padding-left: 10px; 41 | } 42 | 43 | .output-warn{ 44 | height: 25px; 45 | line-height: 25px; 46 | background: #6d6d6d; 47 | color: #c3c3c3; 48 | padding-left: 10px; 49 | } 50 | 51 | .output-error{ 52 | height: 25px; 53 | line-height: 25px; 54 | background: #6d6d6d; 55 | color: #c3c3c3; 56 | padding-left: 10px; 57 | } 58 | } 59 | 60 | .format-icon{ 61 | position: absolute; 62 | right: 10px; 63 | } 64 | 65 | .uncomment-icon{ 66 | position: absolute; 67 | right: 40px; 68 | } 69 | 70 | .comment-icon{ 71 | position: absolute; 72 | right: 70px; 73 | } 74 | 75 | .js-title{ 76 | font-size: 12px; 77 | } 78 | 79 | .mat-icon{ 80 | font-size: 20px; 81 | } 82 | 83 | .mat-icon-button { 84 | width: 30px; 85 | height: 30px; 86 | line-height: 30px; 87 | } 88 | 89 | .code-con{ 90 | width: 100%; 91 | height: 100%; 92 | } 93 | 94 | @media only screen and (max-width: 740px) { 95 | .title .format-icon{ 96 | display: none !important; 97 | } 98 | .title .uncomment-icon{ 99 | display: none !important; 100 | } 101 | .title .comment-icon{ 102 | display: none !important; 103 | } 104 | } 105 | 106 | .code{ 107 | height: calc(100% - 30px); 108 | width: calc(100% - 10px); 109 | font-size: 15px; 110 | padding: 0 5px; 111 | background: #272822; 112 | cursor: text; 113 | position: relative; 114 | } 115 | 116 | .title { 117 | height: 30px; 118 | line-height: 30px; 119 | color: #b5b5b5; 120 | padding-left: 10px; 121 | background: #313131; 122 | display: flex; 123 | font-family: monospace; 124 | font-size: 16px; 125 | font-weight: 100; 126 | } 127 | 128 | .as-split-area > div { 129 | position: relative; 130 | height: 100%; 131 | overflow: hidden; 132 | } 133 | 134 | .hack-iframe-hider { 135 | position: absolute; 136 | top: 0; 137 | left: 0; 138 | width: 100%; 139 | height: 100%; 140 | } 141 | 142 | .header{ 143 | width: 100%; 144 | height: 50px; 145 | background: #3e3e3e; 146 | display: flex; 147 | align-items: center; 148 | 149 | .change-view{ 150 | color: #fff; 151 | position: absolute; 152 | right: 150px; 153 | } 154 | 155 | .help{ 156 | color: #fff; 157 | position: absolute; 158 | right: 190px; 159 | } 160 | 161 | .play{ 162 | color: #fff; 163 | position: absolute; 164 | right: 110px; 165 | } 166 | 167 | .download{ 168 | color: #fff; 169 | position: absolute; 170 | right: 70px; 171 | } 172 | 173 | .git{ 174 | color: #fff; 175 | position: absolute; 176 | right: 30px; 177 | width: 30px; 178 | height: 30px; 179 | } 180 | 181 | 182 | mat-form-field{ 183 | height: 55px; 184 | } 185 | 186 | @media only screen and (max-width: 740px) { 187 | .header-title{ 188 | max-width: 60px !important; 189 | } 190 | } 191 | 192 | .header-title{ 193 | color: #fff; 194 | min-width: 80px; 195 | } 196 | 197 | input:disabled{ 198 | color: #fff !important; 199 | font-size: 18px; 200 | } 201 | 202 | input{ 203 | font-size: 18px; 204 | } 205 | 206 | .edit{ 207 | color: #fff; 208 | width: 30px; 209 | height: 30px; 210 | line-height: 30px; 211 | text-align: center; 212 | cursor: pointer; 213 | } 214 | 215 | .logo{ 216 | color: #fff; 217 | width: 30px; 218 | height: 30px; 219 | line-height: 50px; 220 | text-align: center; 221 | margin: 10px; 222 | cursor: pointer; 223 | } 224 | } 225 | 226 | ::ng-deep .as-split-gutter{ 227 | background: #4e4e4e !important; 228 | box-shadow: 0 0 2px #212121; 229 | } 230 | 231 | ::ng-deep .as-split-gutter-icon{ 232 | background-image: none !important; 233 | } 234 | } 235 | 236 | 237 | .top.mat-icon{ 238 | transform: rotate(180deg); 239 | } 240 | 241 | .left.mat-icon{ 242 | transform: rotate(90deg); 243 | } 244 | 245 | .right.mat-icon{ 246 | transform: rotate(-90deg); 247 | } 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { HomeService } from './home.service'; 4 | import { MatDialog } from '@angular/material/dialog'; 5 | import { PraiseDialogComponent } from './praise-dialog/praise-dialog.component'; 6 | 7 | @Component({ 8 | selector: 'app-home', 9 | templateUrl: './home.component.html', 10 | styleUrls: ['./home.component.scss'] 11 | }) 12 | export class HomeComponent implements OnInit { 13 | 14 | list: any; 15 | currPage = 0; 16 | pageLimit = 6; 17 | filter = ''; 18 | currentList: any; 19 | firstPage = true; 20 | lastPage = false; 21 | 22 | constructor(private router: Router, private homeSer: HomeService, private dialog: MatDialog) { } 23 | 24 | ngOnInit() { 25 | document.title = 'Code Online'; 26 | this.initIframes(''); 27 | } 28 | 29 | initIframes(filter) { 30 | this.homeSer.getPens().subscribe(data => { 31 | this.list = data['filter'](item => { 32 | if (item['code-online-title'].toLowerCase().indexOf(filter.toLowerCase()) !== -1) { 33 | return true; 34 | } 35 | return false; 36 | }); 37 | const from = this.currPage * this.pageLimit; 38 | const temp = [...this.list]; 39 | if (Math.ceil(this.list.length / this.pageLimit) - 1 <= 0) { 40 | this.lastPage = true; 41 | } 42 | this.currentList = temp.splice(from, this.pageLimit); 43 | setTimeout(() => { 44 | this.currentList.forEach(item => this.writeDocument(item)); 45 | }, 2000); 46 | }); 47 | } 48 | 49 | nextPage() { 50 | if (this.currPage === Math.floor(this.list.length / this.pageLimit)) { 51 | return; 52 | } 53 | if (this.currPage === Math.floor(this.list.length / this.pageLimit) - 1) { 54 | this.lastPage = true; 55 | } else { 56 | this.lastPage = false; 57 | } 58 | this.firstPage = false; 59 | this.currPage += 1; 60 | this.initIframes(this.filter); 61 | } 62 | 63 | prevPage() { 64 | if (this.currPage === 0) { 65 | return; 66 | } 67 | if (this.currPage === 1) { 68 | this.firstPage = true; 69 | } else { 70 | this.firstPage = false; 71 | } 72 | this.lastPage = false; 73 | this.currPage -= 1; 74 | this.initIframes(this.filter); 75 | } 76 | 77 | searchPens(e) { 78 | this.currPage = 0; 79 | this.firstPage = true; 80 | this.lastPage = false; 81 | this.initIframes(e.target.value); 82 | this.filter = e.target.value; 83 | } 84 | 85 | writeLinks(arr) { 86 | return arr.map(item => { 87 | return ``; 88 | }); 89 | } 90 | 91 | writeScript(arr) { 92 | return arr.map(item => { 93 | return ``; 94 | }); 95 | } 96 | 97 | getType(mode) { 98 | const typeMapping = { 99 | None: 'text/javascript', 100 | Babel: 'text/babel', 101 | TypeScript: 'text/typescript', 102 | }; 103 | return typeMapping[mode]; 104 | } 105 | 106 | getContent(item) { 107 | return ` 108 | 109 | 110 | 111 | 112 | Untitled 113 | 114 | ${this.writeLinks(item['code-online-cssLib']).join(',').replace(/,/ig, '')} 115 | 116 | 117 | 118 | ${item['code-online-html']} 119 | ${this.writeScript(item['code-online-jsLib']).join(',').replace(/,/ig, '')} 120 | 123 | 124 | 125 | `; 126 | } 127 | 128 | goToGit() { 129 | window.open('https://github.com/renhongl/code-online', '_blank'); 130 | } 131 | 132 | writeDocument(item) { 133 | try { 134 | const dom = document.getElementById('preview-iframe' + item.id); 135 | if (dom) { 136 | const doc = dom['contentDocument']; 137 | // dom.setAttribute('style', '-webkit-transform:scale(0.8);-moz-transform-scale(0.8);'); 138 | doc.open(); 139 | doc.write(''); 140 | doc.close(); 141 | const content = this.getContent(item); 142 | doc.open(); 143 | doc.write(content); 144 | doc.close(); 145 | } 146 | } catch (error) { 147 | console.log('Write document error'); 148 | } 149 | } 150 | 151 | newPen() { 152 | // localStorage.setItem('code-online-view', ''); 153 | localStorage.setItem('code-online-js', ''); 154 | localStorage.setItem('code-online-html', ''); 155 | localStorage.setItem('code-online-css', ''); 156 | localStorage.setItem('code-online-cssLib', '[]'); 157 | localStorage.setItem('code-online-jsLib', '[]'); 158 | localStorage.setItem('code-online-mode', ''); 159 | localStorage.setItem('code-online-view-type', 'top'); 160 | localStorage.setItem('code-online-title', 'Untitled'); 161 | this.router.navigate(['/pen']); 162 | } 163 | 164 | openPen(id) { 165 | const item = this.list.filter(ite => ite.id === id)[0]; 166 | // const content = this.getContent(item); 167 | // localStorage.setItem('code-online-view', content); 168 | localStorage.setItem('code-online-js', item['code-online-js']); 169 | localStorage.setItem('code-online-html', item['code-online-html']); 170 | localStorage.setItem('code-online-css', item['code-online-css']); 171 | 172 | localStorage.setItem('code-online-cssLib', JSON.stringify(item['code-online-cssLib'])); 173 | localStorage.setItem('code-online-jsLib', JSON.stringify(item['code-online-jsLib'])); 174 | localStorage.setItem('code-online-mode', item['code-online-mode']); 175 | localStorage.setItem('code-online-view-type', item['code-online-view-type']); 176 | localStorage.setItem('code-online-title', item['code-online-title']); 177 | } 178 | 179 | openNewTab(id) { 180 | this.openPen(id); 181 | window.open('/code-online#/fullScreen', '_blank'); 182 | } 183 | 184 | showPraise() { 185 | const dialogRef = this.dialog.open(PraiseDialogComponent, { 186 | width: '310px', 187 | height: '350px', 188 | }); 189 | 190 | dialogRef.afterClosed().subscribe(result => { 191 | 192 | }); 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /src/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 100%; 3 | min-height: 100%; 4 | background: #272822; 5 | 6 | @media only screen and (max-width: 740px) { 7 | footer>span { 8 | width: 100% !important; 9 | border-right: none !important; 10 | text-align: left; 11 | padding-left: 20px; 12 | } 13 | } 14 | 15 | footer { 16 | height: 100px; 17 | width: 100%; 18 | margin: 0 auto; 19 | background: #3e3e3e; 20 | margin-top: 20px; 21 | display: flex; 22 | justify-content: center; 23 | align-items: center; 24 | flex-wrap: wrap; 25 | 26 | &>span { 27 | border-right: 1px solid rgb(199, 199, 199); 28 | margin-right: 10px; 29 | padding-right: 10px; 30 | } 31 | 32 | &>span:last-child { 33 | border-right: none; 34 | } 35 | 36 | .author { 37 | color: rgb(199, 199, 199); 38 | font-size: 12px; 39 | } 40 | 41 | .qq { 42 | color: rgb(199, 199, 199); 43 | font-size: 12px; 44 | } 45 | 46 | .mail { 47 | color: rgb(199, 199, 199); 48 | font-size: 12px; 49 | } 50 | 51 | .mail2 { 52 | color: rgb(199, 199, 199); 53 | font-size: 12px; 54 | } 55 | } 56 | 57 | .pagination { 58 | height: 260px; 59 | display: flex; 60 | width: 100%; 61 | justify-content: center; 62 | 63 | .pre { 64 | width: 80px; 65 | height: 38px; 66 | border: 3px solid #6e6e6e; 67 | border-radius: 5px; 68 | display: flex; 69 | cursor: pointer; 70 | color: #fff; 71 | align-items: center; 72 | justify-content: center; 73 | 74 | &:hover { 75 | background: #fff; 76 | color: #272822; 77 | border: 3px solid #fff; 78 | } 79 | } 80 | 81 | .next { 82 | width: 80px; 83 | height: 38px; 84 | border: 3px solid #6e6e6e; 85 | border-radius: 5px; 86 | margin-left: 20px; 87 | display: flex; 88 | cursor: pointer; 89 | color: #fff; 90 | align-items: center; 91 | justify-content: center; 92 | 93 | &:hover { 94 | background: #fff; 95 | color: #272822; 96 | border: 3px solid #fff; 97 | } 98 | } 99 | } 100 | 101 | .content { 102 | width: 95%; 103 | padding: 10px 0px; 104 | background: #272822; 105 | padding-bottom: 20px; 106 | max-width: 1194px; 107 | margin: 50px auto; 108 | min-height: 600px; 109 | 110 | 111 | .line { 112 | border-bottom: 4px solid #3f51b5; 113 | width: 100%; 114 | font-size: 35px; 115 | font-family: monospace; 116 | font-weight: bold; 117 | color: #fff; 118 | margin-top: 20px; 119 | } 120 | 121 | @media only screen and (max-width: 740px) { 122 | .pen-con { 123 | justify-content: center !important; 124 | } 125 | } 126 | 127 | .pen-con { 128 | display: flex; 129 | justify-content: space-between; 130 | width: 100%; 131 | flex-wrap: wrap; 132 | margin-top: 20px; 133 | 134 | .pen-panel { 135 | width: 350px; 136 | height: 250px; 137 | margin-top: 20px; 138 | background: #3e3e3e; 139 | border-radius: 5px; 140 | position: relative; 141 | overflow: hidden; 142 | box-shadow: 0px 0px 10px #0000005c; 143 | transition: all .5s; 144 | 145 | &:hover{ 146 | transform: scale(1.05); 147 | box-shadow: 0px 0px 10px #0000005c; 148 | } 149 | 150 | a.link { 151 | position: absolute; 152 | left: 0; 153 | top: 0; 154 | z-index: 111; 155 | display: inline-block; 156 | width: 100%; 157 | height: calc(100% - 50px); 158 | cursor: pointer; 159 | } 160 | 161 | .iframe-con { 162 | height: calc(100% - 50px); 163 | width: 100%; 164 | background: #fff; 165 | border-radius: 5px 5px 0 0; 166 | overflow: hidden; 167 | } 168 | 169 | .desc-con { 170 | height: 50px; 171 | position: relative; 172 | 173 | .fullscreen { 174 | position: absolute; 175 | right: 10px; 176 | top: 4px; 177 | color: #fff; 178 | } 179 | 180 | .logo { 181 | position: absolute; 182 | left: 5px; 183 | top: 5px; 184 | border-radius: 5px; 185 | } 186 | 187 | .title { 188 | position: absolute; 189 | left: 55px; 190 | top: 5px; 191 | color: #fff; 192 | font-size: 16px; 193 | } 194 | 195 | .name { 196 | position: absolute; 197 | left: 55px; 198 | top: 27px; 199 | color: #9e9e9e; 200 | font-size: 13px; 201 | } 202 | } 203 | } 204 | } 205 | } 206 | 207 | .header { 208 | width: 100%; 209 | height: 50px; 210 | background: #3e3e3e; 211 | display: flex; 212 | align-items: center; 213 | position: fixed; 214 | z-index: 1000; 215 | top: 0; 216 | 217 | @media only screen and (max-width: 740px) { 218 | .search-con { 219 | width: 40% !important; 220 | } 221 | } 222 | 223 | .search-con { 224 | width: 250px; 225 | position: absolute; 226 | right: 150px; 227 | justify-content: center; 228 | top: 10px; 229 | 230 | .search { 231 | width: 100%; 232 | overflow: hidden; 233 | } 234 | 235 | input { 236 | font-size: 14px; 237 | color: #fff !important; 238 | height: 30px; 239 | border-radius: 5px; 240 | background: #272822; 241 | padding-left: 50px; 242 | border: none; 243 | outline: none; 244 | width: calc(100% - 50px); 245 | } 246 | 247 | .search-icon { 248 | position: absolute; 249 | left: 0; 250 | top: 4px; 251 | left: 10px; 252 | color: #fff; 253 | } 254 | } 255 | 256 | .praise { 257 | position: absolute; 258 | right: 70px; 259 | color: #fff; 260 | 261 | mat-icon{ 262 | font-size: 18px !important; 263 | color: #ff6161 !important; 264 | } 265 | } 266 | 267 | .new-pen { 268 | position: absolute; 269 | right: 110px; 270 | color: #fff; 271 | } 272 | 273 | .mat-icon-button { 274 | width: 30px; 275 | height: 30px; 276 | line-height: 30px; 277 | } 278 | 279 | @media only screen and (max-width: 740px) { 280 | .title { 281 | display: none !important; 282 | } 283 | } 284 | 285 | .title { 286 | color: #fff; 287 | font-size: 23px; 288 | position: absolute; 289 | left: 10px; 290 | /* top: 0; */ 291 | letter-spacing: 7px; 292 | } 293 | 294 | .change-view { 295 | color: #fff; 296 | position: absolute; 297 | right: 150px; 298 | } 299 | 300 | .play { 301 | color: #fff; 302 | position: absolute; 303 | right: 110px; 304 | } 305 | 306 | .download { 307 | color: #fff; 308 | position: absolute; 309 | right: 70px; 310 | } 311 | 312 | .git { 313 | color: #fff; 314 | position: absolute; 315 | right: 30px; 316 | width: 30px; 317 | height: 30px; 318 | } 319 | 320 | 321 | mat-form-field { 322 | height: 55px; 323 | } 324 | 325 | .header-title { 326 | color: #fff; 327 | min-width: 80px; 328 | } 329 | 330 | input:disabled { 331 | color: #fff !important; 332 | font-size: 18px; 333 | } 334 | 335 | input { 336 | font-size: 18px; 337 | } 338 | 339 | .edit { 340 | color: #fff; 341 | width: 30px; 342 | height: 30px; 343 | line-height: 30px; 344 | text-align: center; 345 | cursor: pointer; 346 | } 347 | 348 | .logo { 349 | color: #fff; 350 | width: 25px; 351 | height: 25px; 352 | line-height: 50px; 353 | text-align: center; 354 | margin: 10px; 355 | position: absolute; 356 | left: 18px; 357 | top: 2px; 358 | z-index: 1000; 359 | word-spacing: 2em; 360 | } 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /src/app/pen/pen.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 6 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | 21 | 24 | 25 | 28 | 29 | 32 | 33 | 37 | 41 | 45 | 46 | 47 | 50 | 51 | 54 | 55 | 58 |
59 | 60 |
61 | 62 | 63 | 64 | 65 |
66 |
67 | 76 | HTML
77 |
78 |
79 |
80 |
81 | 82 |
83 |
84 | 87 | 96 | CSS {{cssMode !== 'None' ? ' ('+cssMode+')' : ''}} 97 |
98 |
99 |
100 |
101 |
102 | 103 |
104 |
105 | 108 | 117 | JS {{mode === 'Babel' ? ' (Babel)' : ''}} 118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | 126 |
127 | 128 |
129 |
130 |
131 | 132 |
133 |
134 | Console 135 | 138 |
139 |
140 |
141 |
142 |
143 |
144 | 145 |
146 | 147 | 148 | 149 | 150 |
151 |
152 | 161 | HTML 162 |
163 |
164 |
165 |
166 |
167 | 168 |
169 |
170 | 173 | 182 | CSS {{cssMode !== 'None' ? ' ('+cssMode+')' : ''}} 183 |
184 |
185 |
186 |
187 |
188 | 189 |
190 |
191 | 194 | 203 | JS {{mode === 'Babel' ? ' (Babel)' : ''}} 204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 | 212 | 213 | 214 |
215 | 216 |
217 |
218 |
219 | 220 |
221 |
222 | Console 223 | 226 |
227 |
228 |
229 |
230 |
231 | 232 |
233 |
234 |
235 | 236 |
237 | 238 | 239 | 240 | 241 |
242 | 243 |
244 |
245 |
246 | 247 |
248 |
249 | Console 250 | 253 |
254 |
255 |
256 |
257 |
258 |
259 | 260 | 261 | 262 |
263 |
264 | 273 | HTML 274 |
275 |
276 |
277 |
278 |
279 | 280 |
281 |
282 | 285 | 294 | CSS {{cssMode !== 'None' ? ' ('+cssMode+')' : ''}} 295 |
296 |
297 |
298 |
299 |
300 | 301 |
302 |
303 | 306 | 315 | JS {{mode === 'Babel' ? ' (Babel)' : ''}} 316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 | -------------------------------------------------------------------------------- /src/app/pen/pen.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ChangeDetectionStrategy, OnInit, ViewChild, ChangeDetectorRef } from '@angular/core'; 2 | import CodeMirror from 'codemirror'; 3 | import { MatDialog } from '@angular/material/dialog'; 4 | 5 | import { JsDialogComponent } from './js-dialog/js-dialog.component'; 6 | import { CssDialogComponent } from './css-dialog/css-dialog.component'; 7 | 8 | import { HelpDialogComponent } from './help-dialog/help-dialog.component'; 9 | 10 | import 'codemirror/addon/lint/lint.css'; 11 | 12 | import 'codemirror/addon/edit/closebrackets.js'; 13 | import 'codemirror/addon/edit/closetag.js'; 14 | import 'codemirror/addon/edit/matchbrackets.js'; 15 | 16 | import 'codemirror/mode/javascript/javascript.js'; 17 | import 'codemirror/mode/htmlmixed/htmlmixed.js'; 18 | import 'codemirror/mode/css/css.js'; 19 | 20 | import 'codemirror/addon/selection/active-line.js'; 21 | 22 | import 'codemirror/addon/dialog/dialog.js'; 23 | import 'codemirror/addon/dialog/dialog.css'; 24 | 25 | import 'codemirror/addon/search/search.js'; 26 | // import 'codemirror/addon/search/matchesonscrollbar.js'; 27 | import 'codemirror/addon/search/searchcursor.js'; 28 | import 'codemirror/addon/search/match-highlighter.js'; 29 | import 'codemirror/addon/search/jump-to-line.js'; 30 | 31 | 32 | import jshint from 'jshint'; 33 | import cssLint from 'csslint'; 34 | import 'codemirror/addon/lint/lint.js'; 35 | import 'codemirror/addon/lint/javascript-lint.js'; 36 | import 'codemirror/addon/lint/html-lint.js'; 37 | import 'codemirror/addon/lint/css-lint.js'; 38 | import 'codemirror-formatting'; 39 | import { Router } from '@angular/router'; 40 | 41 | declare const emmetCodeMirror; 42 | (window).JSHINT = jshint.JSHINT; 43 | (window).CSSLint = cssLint.CSSLint; 44 | 45 | @Component({ 46 | changeDetection: ChangeDetectionStrategy.OnPush, 47 | selector: 'app-pen', 48 | templateUrl: './pen.component.html', 49 | styleUrls: ['./pen.component.scss'] 50 | }) 51 | export class PenComponent implements OnInit { 52 | 53 | jsCode: string; 54 | htmlCode: string; 55 | cssCode: string; 56 | doc: any; 57 | jsEditor: any; 58 | htmlEditor: any; 59 | cssEditor: any; 60 | jsChangeTimer: any; 61 | htmlChangeTimer: any; 62 | cssChangeTimer: any; 63 | jsLibrary: Array; 64 | changeTitle: boolean; 65 | titleWord: string; 66 | cssLibrary: Array; 67 | downloadUrl: string; 68 | content: string; 69 | 70 | showIframeHider = false; 71 | mode = 'None'; 72 | currentView = 'top'; 73 | cssMode = 'None'; 74 | 75 | @ViewChild('js', { static: false }) jsRef; 76 | @ViewChild('html', { static: false }) htmlRef; 77 | @ViewChild('css', { static: false }) cssRef; 78 | 79 | @ViewChild('jsTitle', { static: true }) jsTitleRef; 80 | @ViewChild('title', { static: true }) titleRef; 81 | 82 | constructor(public dialog: MatDialog, private cd: ChangeDetectorRef, private router: Router) { 83 | } 84 | 85 | ngOnInit() { 86 | this.titleWord = localStorage.getItem('code-online-title') || 'Untitled'; 87 | this.jsCode = localStorage.getItem('code-online-js') || ''; 88 | this.htmlCode = localStorage.getItem('code-online-html') || ''; 89 | this.cssCode = localStorage.getItem('code-online-css') || ''; 90 | this.mode = localStorage.getItem('code-online-mode') || 'None'; 91 | this.cssMode = localStorage.getItem('code-online-cssmode') || 'None'; 92 | this.jsLibrary = this.getLibs('code-online-jsLib'); 93 | this.cssLibrary = this.getLibs('code-online-cssLib'); 94 | this.currentView = localStorage.getItem('code-online-view-type') || 'top'; 95 | if (this.mode === 'Babel') { 96 | this.jsLibrary.unshift('https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js'); 97 | } 98 | setTimeout(() => { 99 | this.updateDocumentTitle(); 100 | this.initJs(); 101 | this.initHtml(); 102 | this.initCss(); 103 | this.refresh(); 104 | this.autoUpdate(); 105 | }, 500); 106 | // this.handleSave(); 107 | } 108 | 109 | getLibs(topic) { 110 | let arr = JSON.parse(localStorage.getItem(topic)) || []; 111 | arr = this.getNoneEmpty(arr); 112 | return arr; 113 | } 114 | 115 | getNoneEmpty(arr) { 116 | return arr.filter(item => item.toLowerCase() !== ''); 117 | } 118 | 119 | clearConsole() { 120 | document.getElementById('output').innerHTML = ''; 121 | } 122 | 123 | goToGit() { 124 | window.open('https://github.com/renhongl/code-online', '_blank'); 125 | } 126 | 127 | homePage() { 128 | this.router.navigate(['/']); 129 | } 130 | 131 | openNewTab() { 132 | window.open('/code-online#/fullScreen', '_blank'); 133 | } 134 | 135 | changeView(value) { 136 | this.currentView = value; 137 | localStorage.setItem('code-online-view-type', value); 138 | setTimeout(() => { 139 | this.initJs(); 140 | this.initHtml(); 141 | this.initCss(); 142 | this.refresh(); 143 | this.autoUpdate(); 144 | }, 500); 145 | } 146 | 147 | updateTitle() { 148 | localStorage.setItem('code-online-title', this.titleWord); 149 | this.updateDocumentTitle(); 150 | } 151 | 152 | updateDocumentTitle() { 153 | document.title = this.titleWord; 154 | } 155 | 156 | disableTitle() { 157 | this.changeTitle = false; 158 | } 159 | 160 | toggleTitle() { 161 | this.changeTitle = !this.changeTitle; 162 | if (this.changeTitle) { 163 | this.titleRef.nativeElement.focus(); 164 | } 165 | } 166 | 167 | getDoc() { 168 | return document.querySelector('iframe').contentDocument; 169 | } 170 | 171 | autoUpdate() { 172 | this.cssEditor.on('change', () => { 173 | if (this.cssChangeTimer) { 174 | clearTimeout(this.cssChangeTimer); 175 | } 176 | this.cssChangeTimer = setTimeout(() => { 177 | this.refresh(); 178 | }, 2000); 179 | }); 180 | 181 | this.htmlEditor.on('change', () => { 182 | if (this.htmlChangeTimer) { 183 | clearTimeout(this.htmlChangeTimer); 184 | } 185 | this.htmlChangeTimer = setTimeout(() => { 186 | this.refresh(); 187 | }, 2000); 188 | }); 189 | 190 | this.jsEditor.on('change', () => { 191 | if (this.jsChangeTimer) { 192 | clearTimeout(this.jsChangeTimer); 193 | } 194 | this.jsChangeTimer = setTimeout(() => { 195 | this.refresh(); 196 | }, 2000); 197 | }); 198 | } 199 | 200 | formatJs() { 201 | const range = { from: this.jsEditor.getCursor(true), to: this.jsEditor.getCursor(false) }; 202 | this.jsEditor.autoFormatRange(range.from, range.to); 203 | } 204 | 205 | formatHtml() { 206 | const range = { from: this.htmlEditor.getCursor(true), to: this.htmlEditor.getCursor(false) }; 207 | this.htmlEditor.autoFormatRange(range.from, range.to); 208 | } 209 | 210 | formatCss() { 211 | const range = { from: this.cssEditor.getCursor(true), to: this.cssEditor.getCursor(false) }; 212 | this.cssEditor.autoFormatRange(range.from, range.to); 213 | } 214 | 215 | commentJs() { 216 | const range = { from: this.jsEditor.getCursor(true), to: this.jsEditor.getCursor(false) }; 217 | this.jsEditor.commentRange(true, range.from, range.to); 218 | } 219 | 220 | unCommentJs() { 221 | const range = { from: this.jsEditor.getCursor(true), to: this.jsEditor.getCursor(false) }; 222 | this.jsEditor.commentRange(false, range.from, range.to); 223 | } 224 | 225 | commentHtml() { 226 | const range = { from: this.htmlEditor.getCursor(true), to: this.htmlEditor.getCursor(false) }; 227 | this.htmlEditor.commentRange(true, range.from, range.to); 228 | } 229 | 230 | unCommentHtml() { 231 | const range = { from: this.htmlEditor.getCursor(true), to: this.htmlEditor.getCursor(false) }; 232 | this.htmlEditor.commentRange(false, range.from, range.to); 233 | } 234 | 235 | commentCss() { 236 | const range = { from: this.cssEditor.getCursor(true), to: this.cssEditor.getCursor(false) }; 237 | this.cssEditor.commentRange(true, range.from, range.to); 238 | } 239 | 240 | unCommentCss() { 241 | const range = { from: this.cssEditor.getCursor(true), to: this.cssEditor.getCursor(false) }; 242 | this.cssEditor.commentRange(false, range.from, range.to); 243 | } 244 | 245 | 246 | refresh() { 247 | this.jsCode = this.jsEditor.getValue(); 248 | this.htmlCode = this.htmlEditor.getValue(); 249 | this.cssCode = this.cssEditor.getValue(); 250 | this.initPreview(); 251 | } 252 | 253 | handleSave() { 254 | document.body.addEventListener('keypress', (event) => { 255 | if (!(event.which === 115 && event.ctrlKey) && !(event.which === 19)) { 256 | return true; 257 | }; 258 | this.jsCode = this.jsEditor.getValue(); 259 | this.htmlCode = this.htmlEditor.getValue(); 260 | this.cssCode = this.cssEditor.getValue(); 261 | this.initPreview(); 262 | event.preventDefault(); 263 | event.stopPropagation(); 264 | return false; 265 | }); 266 | } 267 | 268 | initCss() { 269 | this.cssEditor = CodeMirror(this.cssRef.nativeElement, { 270 | value: this.cssCode, 271 | mode: 'css', 272 | theme: 'monokai', 273 | lineNumbers: true, 274 | autoCloseBrackets: true, 275 | styleActiveLine: false, 276 | indentWithTabs: true, 277 | indentUnit: 2, 278 | tabSize: 2, 279 | lint: true, 280 | matchBrackets: true, 281 | }); 282 | this.cssEditor.execCommand('selectAll'); 283 | this.formatCss(); 284 | this.cssEditor.execCommand('goDocStart'); 285 | this.cssEditor.setOption('extraKeys', { 286 | 'Ctrl-Alt-F': () => { 287 | this.formatCss(); 288 | }, 289 | 'Ctrl-/': () => { 290 | this.commentCss(); 291 | }, 292 | 'Ctrl-Alt-/': () => { 293 | this.unCommentCss(); 294 | } 295 | }); 296 | } 297 | 298 | initHtml() { 299 | this.htmlEditor = CodeMirror(this.htmlRef.nativeElement, { 300 | value: this.htmlCode, 301 | mode: 'htmlmixed', 302 | theme: 'monokai', 303 | lineNumbers: true, 304 | autoCloseBrackets: true, 305 | styleActiveLine: false, 306 | autoCloseTags: true, 307 | profile: 'html', 308 | indentWithTabs: true, 309 | indentUnit: 2, 310 | tabSize: 2, 311 | lint: true, 312 | matchBrackets: true, 313 | }); 314 | emmetCodeMirror(this.htmlEditor, { 315 | Tab: 'emmet.expand_abbreviation_with_tab', 316 | }); 317 | this.htmlEditor.execCommand('selectAll'); 318 | this.formatHtml(); 319 | this.htmlEditor.execCommand('goDocStart'); 320 | this.htmlEditor.setOption('extraKeys', { 321 | 'Ctrl-Alt-F': () => { 322 | this.formatHtml(); 323 | }, 324 | 'Ctrl-/': () => { 325 | this.commentHtml(); 326 | }, 327 | 'Ctrl-Alt-/': () => { 328 | this.unCommentHtml(); 329 | } 330 | }); 331 | } 332 | 333 | initJs() { 334 | this.jsEditor = CodeMirror(this.jsRef.nativeElement, { 335 | value: this.jsCode, 336 | mode: 'javascript', 337 | theme: 'monokai', 338 | lineNumbers: true, 339 | autoCloseBrackets: true, 340 | styleActiveLine: false, 341 | indentWithTabs: true, 342 | indentUnit: 2, 343 | tabSize: 2, 344 | gutters: ['CodeMirror-lint-markers'], 345 | lint: { esversion: '8' }, 346 | matchBrackets: true, 347 | }); 348 | this.jsEditor.execCommand('selectAll'); 349 | this.formatJs(); 350 | this.jsEditor.execCommand('goDocStart'); 351 | this.jsEditor.setOption('extraKeys', { 352 | 'Ctrl-Alt-F': () => { 353 | this.formatJs(); 354 | }, 355 | 'Ctrl-/': () => { 356 | this.commentJs(); 357 | }, 358 | 'Ctrl-Alt-/': () => { 359 | this.unCommentJs(); 360 | } 361 | }); 362 | } 363 | 364 | removeTag(tagName) { 365 | const hs = this.doc.getElementsByTagName(tagName); 366 | for (let i = 0, max = hs.length; i < max; i++) { 367 | hs[i].parentNode.removeChild(hs[i]); 368 | } 369 | } 370 | 371 | getType() { 372 | const typeMapping = { 373 | None: 'text/javascript', 374 | Babel: 'text/babel', 375 | TypeScript: 'text/typescript', 376 | }; 377 | return typeMapping[this.mode]; 378 | } 379 | 380 | writeScript() { 381 | return this.jsLibrary.map(item => { 382 | return ``; 383 | }); 384 | } 385 | 386 | getNewIframe() { 387 | const pre = document.getElementById('previewIframe-' + this.currentView); 388 | if (!this.jsCode) { 389 | return pre; 390 | } 391 | if (pre) { 392 | document.querySelector('.preview-parent-' + this.currentView).removeChild(pre); 393 | } 394 | const curr = document.createElement('iframe'); 395 | curr.setAttribute('id', 'previewIframe-' + this.currentView); 396 | curr.setAttribute('width', '100%'); 397 | curr.setAttribute('height', '100%'); 398 | curr.setAttribute('frameborder', '0'); 399 | document.querySelector('.preview-parent-' + this.currentView).prepend(curr); 400 | } 401 | 402 | writeLinks() { 403 | return this.cssLibrary.map(item => { 404 | return ``; 405 | }); 406 | } 407 | 408 | openHelp() { 409 | this.dialog.open(HelpDialogComponent, { 410 | width: '350px', 411 | height: '350px', 412 | }); 413 | } 414 | 415 | initPreview() { 416 | this.doc = this.getNewIframe(); 417 | setTimeout(() => { 418 | this.doc = this.getDoc(); 419 | this.doc.location.reload(); 420 | this.doc.open(); 421 | this.doc.write(''); 422 | this.doc.close(); 423 | this.content = ` 424 | 425 | 426 | 427 | 428 | Untitled 429 | 430 | ${this.writeLinks().join(',').replace(/,/ig, '')} 431 | 432 | 433 | 434 | ${this.htmlCode} 435 | ${this.writeScript().join(',').replace(/,/ig, '')} 436 | 439 | 440 | 441 | `; 442 | this.doc.open(); 443 | this.doc.write(this.content); 444 | this.doc.close(); 445 | // localStorage.setItem('code-online-view', this.content); 446 | localStorage.setItem('code-online-js', this.jsCode); 447 | localStorage.setItem('code-online-html', this.htmlCode); 448 | localStorage.setItem('code-online-css', this.cssCode); 449 | 450 | document.getElementById('output').innerHTML = ''; 451 | }, 1000); 452 | } 453 | 454 | openJSDialog() { 455 | const dialogRef = this.dialog.open(JsDialogComponent, { 456 | width: '600px', 457 | height: '70%', 458 | data: { jsLibrary: this.jsLibrary, mode: this.mode }, 459 | disableClose: true 460 | }); 461 | 462 | dialogRef.afterClosed().subscribe(result => { 463 | let arr = result.jsLibrary || []; 464 | arr = this.getNoneEmpty(arr); 465 | this.jsLibrary = arr; 466 | this.mode = result.mode; 467 | const babelPath = 'https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js'; 468 | const path = 'https://cdnjs.cloudflare.com/ajax/libs/typescript/3.6.3/typescript.min.js'; 469 | if (this.mode === 'Babel') { 470 | this.jsLibrary = this.jsLibrary.filter(item => item !== babelPath); 471 | this.jsLibrary = this.jsLibrary.filter(item => item !== path); 472 | this.jsLibrary.push(babelPath); 473 | } else if (this.mode === 'TypeScript') { 474 | this.jsLibrary = this.jsLibrary.filter(item => item !== babelPath); 475 | this.jsLibrary = this.jsLibrary.filter(item => item !== path); 476 | this.jsLibrary.push(path); 477 | this.jsLibrary.push('/code-online/assets/libs/typescript.compile.js'); 478 | } 479 | this.refresh(); 480 | this.cd.detectChanges(); 481 | localStorage.setItem('code-online-jsLib', JSON.stringify(this.jsLibrary)); 482 | localStorage.setItem('code-online-mode', this.mode); 483 | }); 484 | } 485 | 486 | openCssDialog() { 487 | const dialogRef = this.dialog.open(CssDialogComponent, { 488 | width: '600px', 489 | height: '70%', 490 | data: { cssLibrary: this.cssLibrary, cssMode: this.cssMode }, 491 | disableClose: true 492 | }); 493 | 494 | dialogRef.afterClosed().subscribe(result => { 495 | let arr = result.cssLibrary || []; 496 | arr = this.getNoneEmpty(arr); 497 | this.cssLibrary = arr; 498 | this.cssMode = result.mode; 499 | this.refresh(); 500 | this.cd.detectChanges(); 501 | localStorage.setItem('code-online-cssLib', JSON.stringify(this.cssLibrary)); 502 | // localStorage.setItem('code-online-cssmode', this.cssMode); 503 | }); 504 | } 505 | 506 | downloadSource() { 507 | const element = document.createElement('a'); 508 | element.setAttribute( 509 | 'href', 510 | 'data:text/plain;charset=utf-8,' + encodeURIComponent(this.content) 511 | ); 512 | element.setAttribute('download', this.titleWord + '.html'); 513 | element.style.display = 'none'; 514 | document.body.appendChild(element); 515 | element.click(); 516 | document.body.removeChild(element); 517 | } 518 | 519 | } 520 | -------------------------------------------------------------------------------- /src/assets/libs/typescript.compile.js: -------------------------------------------------------------------------------- 1 | /* ***************************************************************************** 2 | Copyright (c) niu tech. All rights reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 10 | MERCHANTABLITY OR NON-INFRINGEMENT. 11 | 12 | See the Apache Version 2.0 License for specific language governing permissions 13 | and limitations under the License. 14 | ***************************************************************************** */ 15 | 16 | (function() { 17 | if (!window.console) { 18 | window.console = { 19 | log: function() {} 20 | } 21 | } 22 | hashCode = function(c) { 23 | var d = 0, b, a; 24 | if (c.length == 0) { 25 | return d 26 | } 27 | for (a = 0; a < c.length; a++) { 28 | b = c.charCodeAt(a); 29 | d = (d << 5) - d + b; 30 | d = d & d 31 | } 32 | return d 33 | } 34 | ; 35 | load = function(a) { 36 | var b; 37 | if (window.XMLHttpRequest) { 38 | b = new XMLHttpRequest() 39 | } else { 40 | if (window.ActiveXObject) { 41 | b = new ActiveXObject("Microsoft.XMLHTTP") 42 | } else { 43 | return "" 44 | } 45 | } 46 | b.open("GET", a, false); 47 | if (b.overrideMimeType) { 48 | b.overrideMimeType("text/plain") 49 | } 50 | b.send(null); 51 | if (b.status == 200) { 52 | return b.responseText 53 | } 54 | return "" 55 | } 56 | ; 57 | compile = function() { 58 | var j = '/// \ndeclare var NaN:number;\ndeclare var Infinity:number;\ndeclare function eval(x:string):any;\ndeclare function parseInt(s:string,radix?:number):number;\ndeclare function parseFloat(string:string):number;\ndeclare function isNaN(number:number):bool;\ndeclare function isFinite(number:number):bool;\ndeclare function decodeURI(encodedURI:string):string;\ndeclare function decodeURIComponent(encodedURIComponent:string):string;\ndeclare function encodeURI(uri:string):string;\ndeclare function encodeURIComponent(uriComponent:string):string;\ninterface PropertyDescriptor{\nconfigurable?:bool;\nenumerable?:bool;\nvalue?:any;\nwritable?:bool;\nget?():any;\nset?(v:any):void;\n}\ninterface PropertyDescriptorMap{\n[s:string]:PropertyDescriptor;\n}\ninterface Object{\ntoString():string;\ntoLocaleString():string;\nvalueOf():Object;\nhasOwnProperty(v:string):bool;\nisPrototypeOf(v:Object):bool;\npropertyIsEnumerable(v:string):bool;\n[s:string]:any;\n}\ndeclare var Object:{\nnew(value?:any):Object;\n():any;\n(value:any):any;\nprototype:Object;\ngetPrototypeOf(o:any):any;\ngetOwnPropertyDescriptor(o:any,p:string):PropertyDescriptor;\ngetOwnPropertyNames(o:any):string[];\ncreate(o:any,properties?:PropertyDescriptorMap):any;\ndefineProperty(o:any,p:string,attributes:PropertyDescriptor):any;\ndefineProperties(o:any,properties:PropertyDescriptorMap):any;\nseal(o:any):any;\nfreeze(o:any):any;\npreventExtensions(o:any):any;\nisSealed(o:any):bool;\nisFrozen(o:any):bool;\nisExtensible(o:any):bool;\nkeys(o:any):string[];\n}\ninterface Function{\napply(thisArg:any,...argArray:any[]):any;\ncall(thisArg:any,...argArray:any[]):any;\nbind(thisArg:any,...argArray:any[]):Function;\nprototype:any;\nlength:number;\n}\ndeclare var Function:{\nnew(...args:string[]):Function;\n(...args:string[]):Function;\nprototype:Function;\n}\ninterface IArguments{\n[index:number]:any;\nlength:number;\ncallee:Function;\n}\ninterface String{\ntoString():string;\ncharAt(pos:number):string;\ncharCodeAt(index:number):number;\nconcat(...strings:string[]):string;\nindexOf(searchString:string,position?:number):number;\nlastIndexOf(searchString:string,position?:number):number;\nlocaleCompare(that:string):number;\nmatch(regexp:string):string[];\nmatch(regexp:RegExp):string[];\nreplace(searchValue:string,replaceValue:string):string;\nreplace(searchValue:string,replaceValue:(substring:string,...args:any[])=>string):string;\nreplace(searchValue:RegExp,replaceValue:string):string;\nreplace(searchValue:RegExp,replaceValue:(substring:string,...args:any[])=>string):string;\nsearch(regexp:string):number;\nsearch(regexp:RegExp):number;\nslice(start:number,end?:number):string;\nsplit(seperator:string,limit?:number):string[];\nsplit(seperator:RegExp,limit?:number):string[];\nsubstring(start:number,end?:number):string;\ntoLowerCase():string;\ntoLocaleLowerCase():string;\ntoUpperCase():string;\ntoLocaleUpperCase():string;\ntrim():string;\nlength:number;\nsubstr(from:number,length?:number):string;\n}\ndeclare var String:{\nnew(value?:any):String;\n(value?:any):string;\nprototype:String;\nfromCharCode(...codes:number[]):string;\n}\ninterface Boolean{\n}\ndeclare var Boolean:{\nnew(value?:any):Boolean;\n(value?:any):bool;\nprototype:Boolean;\n}\ninterface Number{\ntoString(radix?:number):string;\ntoFixed(fractionDigits?:number):string;\ntoExponential(fractionDigits?:number):string;\ntoPrecision(precision:number):string;\n}\ndeclare var Number:{\nnew(value?:any):Number;\n(value?:any):number;\nprototype:Number;\nMAX_VALUE:number;\nMIN_VALUE:number;\nNaN:number;\nNEGATIVE_INFINITY:number;\nPOSITIVE_INFINITY:number;\n}\ninterface Math{\nE:number;\nLN10:number;\nLN2:number;\nLOG2E:number;\nLOG10E:number;\nPI:number;\nSQRT1_2:number;\nSQRT2:number;\nabs(x:number):number;\nacos(x:number):number;\nasin(x:number):number;\natan(x:number):number;\natan2(y:number,x:number):number;\nceil(x:number):number;\ncos(x:number):number;\nexp(x:number):number;\nfloor(x:number):number;\nlog(x:number):number;\nmax(...values:number[]):number;\nmin(...values:number[]):number;\npow(x:number,y:number):number;\nrandom():number;\nround(x:number):number;\nsin(x:number):number;\nsqrt(x:number):number;\ntan(x:number):number;\n}\ndeclare var Math:Math;\ninterface Date{\ntoString():string;\ntoDateString():string;\ntoTimeString():string;\ntoLocaleString():string;\ntoLocaleDateString():string;\ntoLocaleTimeString():string;\nvalueOf():number;\ngetTime():number;\ngetFullYear():number;\ngetUTCFullYear():number;\ngetMonth():number;\ngetUTCMonth():number;\ngetDate():number;\ngetUTCDate():number;\ngetDay():number;\ngetUTCDay():number;\ngetHours():number;\ngetUTCHours():number;\ngetMinutes():number;\ngetUTCMinutes():number;\ngetSeconds():number;\ngetUTCSeconds():number;\ngetMilliseconds():number;\ngetUTCMilliseconds():number;\ngetTimezoneOffset():number;\nsetTime(time:number):void;\nsetMilliseconds(ms:number):void;\nsetUTCMilliseconds(ms:number):void;\nsetSeconds(sec:number,ms?:number):void;\nsetUTCSeconds(sec:number,ms?:number):void;\nsetMinutes(min:number,sec?:number,ms?:number):void;\nsetUTCMinutes(min:number,sec?:number,ms?:number):void;\nsetHours(hours:number,min?:number,sec?:number,ms?:number):void;\nsetUTCHours(hours:number,min?:number,sec?:number,ms?:number):void;\nsetDate(date:number):void;\nsetUTCDate(date:number):void;\nsetMonth(month:number,date?:number):void;\nsetUTCMonth(month:number,date?:number):void;\nsetFullYear(year:number,month?:number,date?:number):void;\nsetUTCFullYear(year:number,month?:number,date?:number):void;\ntoUTCString():string;\ntoISOString():string;\ntoJSON(key?:any):string;\n}\ndeclare var Date:{\nnew():Date;\nnew(value:number):Date;\nnew(value:string):Date;\nnew(year:number,month:number,date?:number,hours?:number,minutes?:number,seconds?:number,ms?:number):Date;\n():string;\nprototype:Date;\nparse(s:string):number;\nUTC(year:number,month:number,date?:number,hours?:number,minutes?:number,seconds?:number,ms?:number):number;\nnow():number;\n}\ninterface RegExpExecArray{\n[index:number]:string;\nlength:number;\nindex:number;\ninput:string;\ntoString():string;\ntoLocaleString():string;\nconcat(...items:string[][]):string[];\njoin(seperator?:string):string;\npop():string;\npush(...items:string[]):void;\nreverse():string[];\nshift():string;\nslice(start:number,end?:number):string[];\nsort(compareFn?:(a:string,b:string)=>number):string[];\nsplice(start:number):string[];\nsplice(start:number,deleteCount:number,...items:string[]):string[];\nunshift(...items:string[]):number;\nindexOf(searchElement:string,fromIndex?:number):number;\nlastIndexOf(searchElement:string,fromIndex?:number):number;\nevery(callbackfn:(value:string,index:number,array:string[])=>bool,thisArg?:any):bool;\nsome(callbackfn:(value:string,index:number,array:string[])=>bool,thisArg?:any):bool;\nforEach(callbackfn:(value:string,index:number,array:string[])=>void,thisArg?:any):void;\nmap(callbackfn:(value:string,index:number,array:string[])=>any,thisArg?:any):any[];\nfilter(callbackfn:(value:string,index:number,array:string[])=>bool,thisArg?:any):string[];\nreduce(callbackfn:(previousValue:any,currentValue:any,currentIndex:number,array:string[])=>any,initialValue?:any):any;\nreduceRight(callbackfn:(previousValue:any,currentValue:any,currentIndex:number,array:string[])=>any,initialValue?:any):any;\n}\ninterface RegExp{\nexec(string:string):RegExpExecArray;\ntest(string:string):bool;\nsource:string;\nglobal:bool;\nignoreCase:bool;\nmultiline:bool;\nlastIndex:bool;\n}\ndeclare var RegExp:{\nnew(pattern:string,flags?:string):RegExp;\n(pattern:string,flags?:string):RegExp;\n}\ninterface Error{\nname:string;\nmessage:string;\n}\ndeclare var Error:{\nnew(message?:string):Error;\n(message?:string):Error;\nprototype:Error;\n}\ninterface JSON{\nparse(text:string,reviver?:(key:any,value:any)=>any):any;\nstringify(value:any):string;\nstringify(value:any,replacer:(key:string,value:any)=>any):string;\nstringify(value:any,replacer:any[]):string;\nstringify(value:any,replacer:(key:string,value:any)=>any,space:any):string;\nstringify(value:any,replacer:any[],space:any):string;\n}\ndeclare var JSON:JSON;\ninterface Array{\ntoString():string;\ntoLocaleString():string;\nconcat(...items:_element[][]):_element[];\njoin(seperator?:string):string;\npop():_element;\npush(...items:_element[]):void;\nreverse():_element[];\nshift():_element;\nslice(start:number,end?:number):_element[];\nsort(compareFn?:(a:_element,b:_element)=>number):_element[];\nsplice(start:number):_element[];\nsplice(start:number,deleteCount:number,...items:_element[]):_element[];\nunshift(...items:_element[]):number;\nindexOf(searchElement:_element,fromIndex?:number):number;\nlastIndexOf(searchElement:_element,fromIndex?:number):number;\nevery(callbackfn:(value:_element,index:number,array:_element[])=>bool,thisArg?:any):bool;\nsome(callbackfn:(value:_element,index:number,array:_element[])=>bool,thisArg?:any):bool;\nforEach(callbackfn:(value:_element,index:number,array:_element[])=>void,thisArg?:any):void;\nmap(callbackfn:(value:_element,index:number,array:_element[])=>any,thisArg?:any):any[];\nfilter(callbackfn:(value:_element,index:number,array:_element[])=>bool,thisArg?:any):_element[];\nreduce(callbackfn:(previousValue:any,currentValue:any,currentIndex:number,array:_element[])=>any,initialValue?:any):any;\nreduceRight(callbackfn:(previousValue:any,currentValue:any,currentIndex:number,array:_element[])=>any,initialValue?:any):any;\nlength:number;\n}\ndeclare var Array:{\nnew(...items:any[]):any[];\n(...items:any[]):any[];\nisArray(arg:any):bool;\nprototype:Array;\n}\ninterface Window{\nondragend:(ev:any)=>any;\nonkeydown:(ev:any)=>any;\nondragover:(ev:any)=>any;\nonkeyup:(ev:any)=>any;\nonreset:(ev:any)=>any;\nonmouseup:(ev:any)=>any;\nondragstart:(ev:any)=>any;\nondrag:(ev:any)=>any;\nonmouseover:(ev:any)=>any;\nondragleave:(ev:any)=>any;\nhistory:any;\nname:string;\nonafterprint:(ev:any)=>any;\nonpause:(ev:any)=>any;\nonbeforeprint:(ev:any)=>any;\ntop:Window;\nonmousedown:(ev:any)=>any;\nonseeked:(ev:any)=>any;\nopener:Window;\nonclick:(ev:any)=>any;\nonwaiting:(ev:any)=>any;\nononline:(ev:any)=>any;\nondurationchange:(ev:any)=>any;\nframes:Window;\nonblur:(ev:any)=>any;\nonemptied:(ev:any)=>any;\nonseeking:(ev:any)=>any;\noncanplay:(ev:any)=>any;\nonstalled:(ev:any)=>any;\nonmousemove:(ev:any)=>any;\nonoffline:(ev:any)=>any;\nlength:number;\nonbeforeunload:(ev:any)=>any;\nonratechange:(ev:any)=>any;\nonstorage:(ev:any)=>any;\nonloadstart:(ev:any)=>any;\nondragenter:(ev:any)=>any;\nonsubmit:(ev:any)=>any;\nself:Window;\nonprogress:(ev:any)=>any;\nondblclick:(ev:any)=>any;\noncontextmenu:(ev:any)=>any;\nonchange:(ev:any)=>any;\nonloadedmetadata:(ev:any)=>any;\nonplay:(ev:any)=>any;\nonerror:any;\nonplaying:(ev:any)=>any;\nparent:Window;\nlocation:any;\noncanplaythrough:(ev:any)=>any;\nonabort:(ev:any)=>any;\nonreadystatechange:(ev:any)=>any;\nonkeypress:(ev:any)=>any;\nframeElement:any;\nonloadeddata:(ev:any)=>any;\nonsuspend:(ev:any)=>any;\nwindow:Window;\nonfocus:(ev:any)=>any;\nonmessage:(ev:any)=>any;\nontimeupdate:(ev:any)=>any;\nonresize:(ev:any)=>any;\nnavigator:any;\nonselect:(ev:any)=>any;\nondrop:(ev:any)=>any;\nonmouseout:(ev:any)=>any;\nonended:(ev:any)=>any;\nonhashchange:(ev:any)=>any;\nonunload:(ev:any)=>any;\nonscroll:(ev:any)=>any;\nonmousewheel:(ev:any)=>any;\nonload:(ev:any)=>any;\nonvolumechange:(ev:any)=>any;\noninput:(ev:any)=>any;\nalert(message?:string):void;\nfocus():void;\nprint():void;\nprompt(message?:string,defaul?:string):string;\ntoString():string;\nopen(url?:string,target?:string,features?:string,replace?:bool):Window;\nclose():void;\nconfirm(message?:string):bool;\npostMessage(message:any,targetOrigin:string,ports?:any):void;\nshowModalDialog(url?:string,argument?:any,options?:any):any;\nblur():void;\ngetSelection():any;\n}\ndeclare var Window:{\nprototype:Window;\nnew():Window;\n}\ninterface Document{\ndoctype:any;\nxmlVersion:string;\nimplementation:any;\nxmlEncoding:string;\nxmlStandalone:bool;\ndocumentElement:any;\ninputEncoding:string;\nbody:any;\ncreateElement(tagName:string):any;\nadoptNode(source:any):any;\ncreateComment(data:string):any;\ncreateDocumentFragment():any;\ngetElementsByTagName(tagname:string):any;\ngetElementsByTagNameNS(namespaceURI:string,localName:string):any;\ncreateProcessingInstruction(target:string,data:string):any;\ncreateElementNS(namespaceURI:string,qualifiedName:string):any;\ncreateAttribute(name:string):any;\ncreateTextNode(data:string):any;\nimportNode(importedNode:any,deep:bool):any;\ncreateCDATASection(data:string):any;\ncreateAttributeNS(namespaceURI:string,qualifiedName:string):any;\ngetElementById(elementId:string):any;\n}\ndeclare var Document:{\nprototype:Document;\nnew():Document;\n}\ndeclare var ondragend:(ev:any)=>any;\ndeclare var onkeydown:(ev:any)=>any;\ndeclare var ondragover:(ev:any)=>any;\ndeclare var onkeyup:(ev:any)=>any;\ndeclare var onreset:(ev:any)=>any;\ndeclare var onmouseup:(ev:any)=>any;\ndeclare var ondragstart:(ev:any)=>any;\ndeclare var ondrag:(ev:any)=>any;\ndeclare var onmouseover:(ev:any)=>any;\ndeclare var ondragleave:(ev:any)=>any;\ndeclare var history:any;\ndeclare var name:string;\ndeclare var onafterprint:(ev:any)=>any;\ndeclare var onpause:(ev:any)=>any;\ndeclare var onbeforeprint:(ev:any)=>any;\ndeclare var top:Window;\ndeclare var onmousedown:(ev:any)=>any;\ndeclare var onseeked:(ev:any)=>any;\ndeclare var opener:Window;\ndeclare var onclick:(ev:any)=>any;\ndeclare var onwaiting:(ev:any)=>any;\ndeclare var ononline:(ev:any)=>any;\ndeclare var ondurationchange:(ev:any)=>any;\ndeclare var frames:Window;\ndeclare var onblur:(ev:any)=>any;\ndeclare var onemptied:(ev:any)=>any;\ndeclare var onseeking:(ev:any)=>any;\ndeclare var oncanplay:(ev:any)=>any;\ndeclare var onstalled:(ev:any)=>any;\ndeclare var onmousemove:(ev:any)=>any;\ndeclare var onoffline:(ev:any)=>any;\ndeclare var length:number;\ndeclare var onbeforeunload:(ev:any)=>any;\ndeclare var onratechange:(ev:any)=>any;\ndeclare var onstorage:(ev:any)=>any;\ndeclare var onloadstart:(ev:any)=>any;\ndeclare var ondragenter:(ev:any)=>any;\ndeclare var onsubmit:(ev:any)=>any;\ndeclare var self:Window;\ndeclare var onprogress:(ev:any)=>any;\ndeclare var ondblclick:(ev:any)=>any;\ndeclare var oncontextmenu:(ev:any)=>any;\ndeclare var onchange:(ev:any)=>any;\ndeclare var onloadedmetadata:(ev:any)=>any;\ndeclare var onplay:(ev:any)=>any;\ndeclare var onerror:any;\ndeclare var onplaying:(ev:any)=>any;\ndeclare var parent:Window;\ndeclare var location:any;\ndeclare var oncanplaythrough:(ev:any)=>any;\ndeclare var onabort:(ev:any)=>any;\ndeclare var onreadystatechange:(ev:any)=>any;\ndeclare var onkeypress:(ev:any)=>any;\ndeclare var frameElement:any;\ndeclare var onloadeddata:(ev:any)=>any;\ndeclare var onsuspend:(ev:any)=>any;\ndeclare var window:Window;\ndeclare var onfocus:(ev:any)=>any;\ndeclare var onmessage:(ev:any)=>any;\ndeclare var ontimeupdate:(ev:any)=>any;\ndeclare var onresize:(ev:any)=>any;\ndeclare var navigator:any;\ndeclare var onselect:(ev:any)=>any;\ndeclare var ondrop:(ev:any)=>any;\ndeclare var onmouseout:(ev:any)=>any;\ndeclare var onended:(ev:any)=>any;\ndeclare var onhashchange:(ev:any)=>any;\ndeclare var onunload:(ev:any)=>any;\ndeclare var onscroll:(ev:any)=>any;\ndeclare var onmousewheel:(ev:any)=>any;\ndeclare var onload:(ev:any)=>any;\ndeclare var onvolumechange:(ev:any)=>any;\ndeclare var oninput:(ev:any)=>any;\ndeclare function alert(message?:string):void;\ndeclare function focus():void;\ndeclare function print():void;\ndeclare function prompt(message?:string,defaul?:string):string;\ndeclare function toString():string;\ndeclare function open(url?:string,target?:string,features?:string,replace?:bool):Window;\ndeclare function close():void;\ndeclare function confirm(message?:string):bool;\ndeclare function postMessage(message:any,targetOrigin:string,ports?:any):void;\ndeclare function showModalDialog(url?:string,argument?:any,options?:any):any;\ndeclare function blur():void;\ndeclare function getSelection():any;\ndeclare function getComputedStyle(elt:any,pseudoElt?:string):any;\ndeclare function attachEvent(any:string,listener:any):bool;\ndeclare function detachEvent(any:string,listener:any):void;\ndeclare var status:string;\ndeclare var onmouseleave:(ev:any)=>any;\ndeclare var screenLeft:number;\ndeclare var offscreenBuffering:any;\ndeclare var maxConnectionsPerServer:number;\ndeclare var onmouseenter:(ev:any)=>any;\ndeclare var clipboardData:any;\ndeclare var defaultStatus:string;\ndeclare var clientInformation:any;\ndeclare var closed:bool;\ndeclare var onhelp:(ev:any)=>any;\ndeclare var external:any;\ndeclare var any:any;\ndeclare var onfocusout:(ev:any)=>any;\ndeclare var screenTop:number;\ndeclare var onfocusin:(ev:any)=>any;\ndeclare function showModelessDialog(url?:string,argument?:any,options?:any):Window;\ndeclare function navigate(url:string):void;\ndeclare function resizeBy(x?:number,y?:number):void;\ndeclare function item(index:any):any;\ndeclare function resizeTo(x?:number,y?:number):void;\ndeclare function createPopup(arguments?:any):any;\ndeclare function toStaticHTML(html:string):string;\ndeclare function execScript(code:string,language?:string):any;\ndeclare function msWriteProfilerMark(profilerMarkName:string):void;\ndeclare function moveTo(x?:number,y?:number):void;\ndeclare function moveBy(x?:number,y?:number):void;\ndeclare function showHelp(url:string,helpArg?:any,features?:string):void;\ndeclare var performance:any;\ndeclare var outerWidth:number;\ndeclare var pageXOffset:number;\ndeclare var innerWidth:number;\ndeclare var pageYOffset:number;\ndeclare var screenY:number;\ndeclare var outerHeight:number;\ndeclare var screen:any;\ndeclare var innerHeight:number;\ndeclare var screenX:number;\ndeclare function scroll(x?:number,y?:number):void;\ndeclare function scrollBy(x?:number,y?:number):void;\ndeclare function scrollTo(x?:number,y?:number):void;\ndeclare var styleMedia:any;\ndeclare var document:Document;\ndeclare function removeEventListener(type:string,listener:any,useCapture?:bool):void;\ndeclare function addEventListener(type:string,listener:any,useCapture?:bool):void;\ndeclare function dispatchEvent(evt:any):bool;\ndeclare var localStorage:any;\ndeclare var sessionStorage:any;\ndeclare function clearTimeout(handle:number):void;\ndeclare function setTimeout(expression:any,msec?:number,language?:any):number;\ndeclare function clearInterval(handle:number):void;\ndeclare function setInterval(expression:any,msec?:number,language?:any):number;\ndeclare var onpopstate:(ev:any)=>any;\ndeclare var applicationCache:any;\ndeclare function matchMedia(mediaQuery:string):any;\ndeclare var animationStartTime:number;\ndeclare function cancelAnimationFrame(handle:number):void;\ndeclare function requestAnimationFrame(callback:any):number;\ndeclare function btoa(rawString:string):string;\ndeclare function atob(encodedString:string):string;\ndeclare var indexedDB:any;\ndeclare var console:any;\ndeclare function importScripts(...urls:string[]):void;'; 59 | var d = { 60 | source: "", 61 | Write: function(e) { 62 | this.source += e 63 | }, 64 | WriteLine: function(e) { 65 | this.source += e + "\n" 66 | }, 67 | Close: function() {} 68 | }; 69 | var b = new TypeScript.TypeScriptCompiler(d); 70 | var k = document.getElementsByTagName("script"); 71 | var g = document.getElementsByTagName("body")[0]; 72 | var f, a = [], c; 73 | for (f = 0; f < k.length; f++) { 74 | if (k[f].type == "text/typescript") { 75 | if (k[f].src) { 76 | a.push(load(k[f].src)) 77 | } else { 78 | a.push(k[f].innerHTML) 79 | } 80 | } 81 | } 82 | if (a.length == 0) { 83 | return 84 | } 85 | if (window.sessionStorage && sessionStorage.getItem("typescript" + hashCode(a.join("")))) { 86 | d.source = sessionStorage.getItem("typescript" + hashCode(a.join(""))) 87 | } else { 88 | b.parser.errorRecovery = true; 89 | b.setErrorCallback(function(n, e, i, m) { 90 | console.log("Compilation error: ", i, "\n Code block: ", m, " Start position: ", n, " Length: ", e) 91 | }); 92 | b.addUnit(j, "lib.d.ts"); 93 | for (f = 0; f < a.length; f++) { 94 | b.addUnit(a[f], "") 95 | } 96 | b.typeCheck(); 97 | b.emit(false, function l(e) { 98 | return d 99 | }); 100 | if (window.sessionStorage) { 101 | sessionStorage.setItem("typescript" + hashCode(a.join("")), d.source) 102 | } 103 | } 104 | c = document.createElement("script"); 105 | c.type = "text/javascript"; 106 | c.innerHTML = "//Compiled TypeScript\n\n" + d.source; 107 | g.appendChild(c) 108 | } 109 | ; 110 | compile() 111 | } 112 | )(); 113 | -------------------------------------------------------------------------------- /src/assets/data/pens.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "0001", 4 | "code-online-title": "五子棋", 5 | "code-online-css": ".container{ width: 100%; height: 500px; display: flex; justify-content: center; align-items: center;}#chess{ height: 450px; width: 450px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5), 0 0 30px rgba(0, 0, 0, 0.2) inset; display: block; margin: 20px; float: left;}.wrap { height: 450px; width: 200px; margin: 20px; float: left; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5), 0 0 30px rgba(0, 0, 0, 0.2) inset;}.message{ width: 100%; height: 50px; text-align: center; color: #e721a6; margin-top: 20px; font-size: 16px; text-shadow: 0 0 10px rgba(0, 0, 0, 0.7); font-weight: 700;}.title{ width: 100%; height: 50px; text-align: center; font-size: 14px; text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);}.timer{ clear: both; width: 100%; height: 50px; text-align: left; font-size: 14px; margin-left: 20px; text-shadow: 0 0 10px rgba(0, 0, 0, 0.7);}.point { width: 50px; height: 50px; border-radius: 50%; position: relative; cursor: pointer; display: flex; justify-content: center; align-items: center; margin: 25px; float: left;}.point::before { content: attr(out); width: 50px; height: 50px; background: grey; border-radius: 50%; position: absolute; z-index: 1; font-size: 14px; color: #fff; display: flex; justify-content: center; align-items: center; text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);}.point::after { content: \"\"; width: 18px; height: 18px; background: rgba(0, 0, 0, 0.5); position: absolute; border-radius: 50%; animation: bigger 3s linear 2s infinite;}.point:hover::before { content: attr(over); background: rgba(0, 0, 0, 0.3); color: #E721A6;}.point:hover::after { width: 55px; height: 55px; background: none; border: 6px solid grey; animation: changeBorder 2s linear 0s infinite alternate;}@keyframes changeBorder{ 0%{ border: 6px solid grey; } 100%{ border: 6px solid rgba(0, 0, 0, 0); }}@keyframes bigger { 0% { width: 38px; height: 38px; background: rgba(0, 0, 0, 0.5); } 60% { width: 80px; height: 80px; background: rgba(0, 0, 0, 0); } 61% { width: 38px; height: 38px; background: rgba(0, 0, 0, 0); } 62% { width: 38px; height: 38px; background: rgba(0, 0, 0, 0.5); }}", 6 | "code-online-view-type": "top", 7 | "code-online-jsLib": [], 8 | "code-online-mode": "Babel", 9 | "code-online-cssLib": [], 10 | "author": "Pomelo", 11 | "logo": "u1.png", 12 | "code-online-js": "(function () { var timerThread = null; var time = 0; var chessDOM = document.getElementById('chess'); var title = document.querySelector('.title'); var msg = document.querySelector('.message'); var timer = document.querySelector('.timer'); var chess = null; function Chess(chessDOM, isComputer) { this.chessDOM = chessDOM; this.context = chessDOM.getContext('2d'); this.black = true; this.board = []; this.gameOver = false; this.wins = []; this.count = 0; this.blackWin = []; this.whiteWin = []; this.isComputer = isComputer || false; } Chess.prototype.init = function () { this.chessDOM.height = this.chessDOM.height; this.initBoard(); this.countWinsArray(); this.initWinArr(); this.handleClick(); return this; } Chess.prototype.initWinArr = function () { for (var i = 0; i < this.count; i++) { this.blackWin[i] = 0; this.whiteWin[i] = 0; } } Chess.prototype.handleClick = function () { this.chessDOM.onclick = function (e) { var x = Math.floor(e.offsetX / 30); var y = Math.floor(e.offsetY / 30); this.oneStep(x, y); }.bind(this); } Chess.prototype.oneStep = function (x, y) { if (this.gameOver || this.board[x][y] !== 0) { return; } if (this.black) { this.stepByBlack(x, y); this.board[x][y] = 1; this.black = false; this.verifyBlack(x, y); return; } this.stepByWhite(x, y); this.verifyWhite(x, y); this.board[x][y] = 2; this.black = true; } Chess.prototype.computerAI = function () { var blackCore = []; var computerCore = []; var max = 0; var maxX = 0; var maxY = 0; for (var i = 0; i < 15; i++) { blackCore[i] = []; computerCore[i] = []; for (var j = 0; j < 15; j++) { blackCore[i][j] = 0; computerCore[i][j] = 0; } } for (var x = 0; x < 15; x++) { for (var y = 0;y < 15; y++) { if (this.board[x][y] === 0) { for (var k = 0; k < this.count; k++) { if (this.wins[x][y][k]) { if (this.blackWin[k] === 1) { blackCore[x][y] += 200; } else if (this.blackWin[k] === 2) { blackCore[x][y] += 400; } else if (this.blackWin[k] === 3) { blackCore[x][y] += 1000; } else if (this.blackWin[k] === 4) { blackCore[x][y] += 10000; } if (this.whiteWin[k] === 1) { computerCore[x][y] += 250; } else if (this.whiteWin[k] === 2) { computerCore[x][y] += 500; } else if (this.whiteWin[k] === 3) { computerCore[x][y] += 1500; } else if (this.whiteWin[k] === 4) { computerCore[x][y] += 20000; } } } var bigger = computerCore[x][y] > blackCore[x][y] ? computerCore[x][y]:blackCore[x][y]; if (bigger > max) { max = bigger; maxX = x; maxY = y; } } } } setTimeout(function() { this.oneStep(maxX, maxY); }.bind(this), 500); } Chess.prototype.verifyBlack = function (x, y) { for (var i = 0; i < this.count; i++) { if (this.wins[x][y][i]) { this.blackWin[i]++; this.whiteWin[i] = 6; if (this.blackWin[i] === 5) { this.showSuccessDialog('黑棋赢了!'); this.gameOver = true; } } } if (this.isComputer) { this.computerAI(); } } Chess.prototype.verifyWhite = function (x, y) { for (var j = 0; j < this.count; j++) { if(this.wins[x][y][j]){ this.whiteWin[j]++; this.blackWin[j] = 6; if (this.whiteWin[j] === 5) { this.showSuccessDialog('白棋赢了!'); this.gameOver = true; } } } } Chess.prototype.showSuccessDialog = function (message) { var msg = document.querySelector('.message'); msg.innerText = message; clearInterval(timerThread); } Chess.prototype.stepByWhite = function (x, y) { var a = x * 30 + 15; var b = y * 30 + 15; this.context.beginPath(); var gradient = this.context.createRadialGradient(a, b, 1, a, b, 10); gradient.addColorStop('0', '#fff'); gradient.addColorStop('1', 'grey'); this.context.fillStyle = gradient; this.context.arc(a, b, 10, 0, 2 * Math.PI); this.context.fill(); this.context.closePath(); } Chess.prototype.stepByBlack = function (x, y) { var a = x * 30 + 15; var b = y * 30 + 15; this.context.beginPath(); var gradient = this.context.createRadialGradient(a, b, 1, a, b, 10); gradient.addColorStop('0', 'grey'); gradient.addColorStop('1', '#000'); this.context.fillStyle = gradient; this.context.arc(a, b, 10, 0, 2 * Math.PI); this.context.fill(); this.context.closePath(); } Chess.prototype.initBoard = function() { this.context.strokeStyle = 'grey'; for (var i = 0; i < 15; i++) { this.context.moveTo(15 + i * 30, 15); this.context.lineTo(15 + i * 30, 435); this.context.moveTo(15, 15 + i * 30); this.context.lineTo(435, 15 + i * 30); this.context.stroke(); this.board[i] = []; for (var j = 0; j < 15; j++) { this.board[i][j] = 0; } } } Chess.prototype.countWinsArray = function () { for (var d = 0; d < 15; d++) { this.wins[d] = []; for (var e = 0; e < 15; e++) { this.wins[d][e] = []; } } for (var i = 0; i < 15; i++) { for (var j = 0; j < 11; j++) { for (var k = 0; k < 5; k++) { this.wins[i][j + k][this.count] = true; } this.count++; } } for (var m = 0; m < 11; m++) { for (var n = 0; n < 15; n++) { for (var o = 0; o < 5; o++) { this.wins[m + o][n][this.count] = true; } this.count++; } } for (var x = 0; x < 11; x++) { for (var y = 14; y > 3; y--) { for (var z = 0; z < 5; z++) { this.wins[x + z][y - z][this.count] = true; } this.count++; } } for (var a = 0; a < 11; a++) { for (var b = 0; b < 11; b++) { for (var c = 0; c < 5; c++) { this.wins[a + c][b + c][this.count] = true; } this.count++; } } } function parseTime(time) { var min = Math.floor(time / 60); var sec = time % 60; return min + '分' + sec + '秒'; } function resetChess(titleText, stop) { time = 0; msg.innerText = ''; timer.innerText = '时长: ' + parseTime(time); title.innerText = titleText; clearInterval(timerThread); chessDOM.height = chessDOM.height; } function startPeopleComputer() { resetChess('玩家与电脑对战进行中', false); chess = new Chess(chessDOM, true).init(); runTimer(); } function startPeoplePeople() { resetChess('玩家对战进行中', false); chess = new Chess(chessDOM).init(); runTimer(); } function runTimer() { timerThread = setInterval(function () { time++; var timeStr = parseTime(time); timer.innerText = '时长: ' + timeStr; }, 1000); } function main() { var peoplePeople = document.querySelector('.people-people'); var peopleComputer = document.querySelector('.people-computer'); var reset = document.querySelector('.reset'); reset.onclick = function () { resetChess('请选择对战模式', true); } peopleComputer.onclick = function () { startPeopleComputer(); } peoplePeople.onclick = function () { startPeoplePeople(); } } main();})()", 13 | "code-online-html": "
请选择对战模式
" 14 | }, 15 | { 16 | "id": "0002", 17 | "code-online-title": "拖动验证", 18 | "code-online-css": ".wrap{ width: 300px; height: 200px; margin: 0 auto; position: relative;}.back-img{ display: block; position: absolute;}.small-img{ position: absolute; top: 109px; left: 0;}.bar{ position: absolute; width: 100%; height: 10px; border: 1px solid #0e6fd4; top: 200px; box-sizing: border-box; background: #0e6fd4; margin-top: 15px; border-radius: 5px;}.drag-btn{ background: #0e6fd4; width: 30px; height: 30px; top: 205px; position: absolute; cursor: pointer; left: 0px; border-radius: 50%; color: #fff; text-align: center; line-height: 25px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.9);}.drag-btn::before{ content: \"\"; width: 10px; height: 10px; background: #fff; left: 10px; top: 10px; position: absolute; box-shadow: 0, 0, 5px rgba(0, 0, 0, 1); border-radius: 50%;}.small-back{ width: 55px; height: 55px; top: 97px; left: 183px; position: absolute;}", 19 | "code-online-view-type": "top", 20 | "code-online-jsLib": [], 21 | "code-online-mode": "Babel", 22 | "code-online-cssLib": [], 23 | "author": "Grape", 24 | "logo": "u2.png", 25 | "code-online-js": "var moving = false;var x;var dragBtn = document.querySelector('.drag-btn');var small = document.querySelector('.small-img');dragBtn.onmousedown = (e) => { moving = true; x = e.clientX;};document.onmousemove = (e) => { if (!moving) { return; } var offsetX = e.clientX; var beforeLeft = Number(dragBtn.style.left.replace('px', '')); dragBtn.style.left = beforeLeft + offsetX - x + 'px'; small.style.left = beforeLeft + offsetX - x + 'px'; if (beforeLeft + offsetX - x < 0) { dragBtn.style.left = '0px'; small.style.left = '0px'; } if (beforeLeft + offsetX - x > 250) { dragBtn.style.left = '250px'; small.style.left = '250px'; } x = offsetX;}document.onmouseup = () => { moving = false; let stopLeft = Number(dragBtn.style.left.replace('px', '')); console.log(stopLeft); if (stopLeft < 190 && stopLeft > 185) { alert('验证通过。'); }};", 26 | "code-online-html": "
\"\" \"\"
" 27 | }, 28 | { 29 | "id": "0003", 30 | "code-online-title": "Cool Navigation", 31 | "code-online-css": ".nav{ width: 600px; height: 50px; margin: 0 auto; position: relative;}ul{ width: 100%; height: 50px; margin: 0; padding: 0;}li{ list-style-type: none; float: left; width: 20%; height: 50px; text-align: center; line-height: 50px; cursor: pointer; border-right: 1px solid rgba(0, 0, 0, 0.1); box-sizing: border-box; color: rgba(0, 0, 0, 0.5);}.focus{ width: 20%; height: 100%; position: absolute; left: 0; top: 0; background: grey; border-bottom: 3px solid red; opacity: 0.3; z-index: -1; transition: all .5s; box-sizing: border-box;}.red{ color: rgba(255, 0, 0, 0.5);}li:last-child{ border-right: none;}", 32 | "code-online-view-type": "top", 33 | "code-online-jsLib": [], 34 | "code-online-mode": "None", 35 | "code-online-cssLib": [], 36 | "author": "Jujube", 37 | "logo": "u3.png", 38 | "code-online-js": "var liArr = document.querySelectorAll('li');liArr = Array.from(liArr);focus = document.querySelector('.focus');liArr.forEach((li, index) => { ((index) => { li.onmouseover = () => { liArr.forEach((li, index) => { li.setAttribute('class', ''); }); focus.style.left = index * 0.2 * 600 + 'px'; li.setAttribute('class', 'red'); } })(index);}); ", 39 | "code-online-html": "
  • 视觉设计
  • 前端开发
  • 数据库管理
  • 后端开发
  • 移动端测试
" 40 | }, 41 | { 42 | "id": "0004", 43 | "code-online-title": "贪吃蛇", 44 | "code-online-css": ".canvas{ width: 600px; height: 600px; border: 1px solid grey; display: block; margin: 0 auto; background: #1d1f20;}", 45 | "code-online-view-type": "top", 46 | "code-online-jsLib": [], 47 | "code-online-mode": "Babel", 48 | "code-online-cssLib": [], 49 | "author": "Mushroom", 50 | "logo": "u4.png", 51 | "code-online-js": "(function () { var SnakeGame = function () { this.canvas = document.querySelector('.canvas'); this.context = this.canvas.getContext('2d'); this.snake = new Snake(this.context); this.bean = new Bean(this.context); this.timer = null; this.stop = false; }; SnakeGame.prototype.addEvent = function () { var self = this; document.onkeyup = function (e) { switch(e.keyCode) { case 37: self.snake.setDirection('left'); break; case 38: self.snake.setDirection('top'); break; case 39: self.snake.setDirection('right'); break; case 40: self.snake.setDirection('down'); break; default: break; } } } SnakeGame.prototype.run = function () { var fps = 30; var now; var then = Date.now(); var interval = 2500/fps; var del; this.addEvent(); this.snake.render(); this.bean.generate(); this.bean.render(); this.timer = function () { if (this.stop) { return; } now = Date.now(); del = now - then; console.log(del, interval); if (del > interval) { then = now - (del % interval); this.snake.clear(); this.snake.run(); this.bean.render(); this.snake.eat(this.bean); this.snake.out(this); } requestAnimationFrame(this.timer); }.bind(this); this.timer(); } var Bean = function (context) { this.context = context; this.location = []; } Bean.prototype.generate = function () { this.location[0] = Math.floor(Math.random() * 59); this.location[1] = Math.floor(Math.random() * 59); } Bean.prototype.render = function () { this.context.beginPath(); var gradient = this.context.createRadialGradient(this.location[0] * 10, this.location[1] * 10, 1, this.location[0] * 10, this.location[1] * 10, 10); gradient.addColorStop('0', '#fff'); gradient.addColorStop('1', 'red'); this.context.fillStyle = gradient; this.context.arc(this.location[0] * 10 + 5, this.location[1] * 10 + 5, 7, 7, 0, 2 * Math.PI); this.context.fill(); this.context.closePath(); } var Snake = function (context) { this.context = context; this.length = 1; this.location = [[4, 0],[3, 0],[2, 0], [1, 0], [0, 0]]; this.direction = 'down'; this.speed = 1; this.turn = []; } Snake.prototype.out = function (game) { var x = this.location[0][0]; var y = this.location[0][1]; console.log(x, y); if (x < 0 || x > 79 || y < 0 || y > 79) { game.stop = true; } } Snake.prototype.eat = function (bean) { if (this.location[0][0] === bean.location[0] && this.location[0][1] === bean.location[1]) { bean.generate(); this.location.push(bean.location); } } Snake.prototype.setDirection = function (dir) { this.direction = dir; this.turn.push(this.location[0]); } Snake.prototype.run = function () { switch(this.direction) { case 'right': this.runRight(); break; case 'left': this.runLeft(); break; case 'top': this.runTop(); break; case 'down': this.runDown(); break; default: break; } this.render(); } Snake.prototype.runRight = function () { this.location.pop(); var header = []; header[0] = this.location[0][0] + this.speed; header[1] = this.location[0][1]; this.location.unshift(header); } Snake.prototype.runLeft = function () { this.location.pop(); var header = []; header[0] = this.location[0][0] - this.speed; header[1] = this.location[0][1]; this.location.unshift(header); } Snake.prototype.runTop = function () { this.location.pop(); var header = []; header[0] = this.location[0][0]; header[1] = this.location[0][1] - this.speed; this.location.unshift(header); } Snake.prototype.runDown = function () { this.location.pop(); var header = []; header[0] = this.location[0][0]; header[1] = this.location[0][1] + this.speed; this.location.unshift(header); } Snake.prototype.clear = function () { this.context.clearRect(0, 0, 600, 600); } Snake.prototype.render = function () { for (var i = 0; i < this.location.length; i++) { if (i === 0) { this.renderHeader(i); } else { this.renderBody(i); } } } Snake.prototype.renderHeader = function (i) { this.context.beginPath(); var gradient = this.context.createRadialGradient(this.location[i][0] * 10 + 5, this.location[i][1] * 10 + 5, 1, this.location[i][0] * 10 + 5, this.location[i][1] * 10 + 5, 10); gradient.addColorStop('0', '#fff'); gradient.addColorStop('1', 'red'); this.context.fillStyle = gradient; this.context.arc(this.location[i][0] * 10 + 5, this.location[i][1] * 10 + 5, 7, 7, 0, 2 * Math.PI); this.context.fill(); this.context.closePath(); } Snake.prototype.renderBody = function (i) { this.context.beginPath(); var gradient = this.context.createRadialGradient(this.location[i][0] * 10 + 5, this.location[i][1] * 10 + 5, 1, this.location[i][0] * 10 + 5, this.location[i][1] * 10 + 5, 10); gradient.addColorStop('0', '#fff'); gradient.addColorStop('1', '#0eaf56'); this.context.fillStyle = gradient; this.context.arc(this.location[i][0] * 10 + 5, this.location[i][1] * 10 + 5, 7, 7, 0, 2 * Math.PI); this.context.fill(); this.context.closePath(); } var snakeGame = new SnakeGame(); snakeGame.run(); })();", 52 | "code-online-html": "" 53 | }, 54 | { 55 | "id": "0005", 56 | "code-online-title": "放大镜", 57 | "code-online-css": ".wrap{ width: 600px; height: 300px; margin: 0 auto; position: relative;}.small-container{ width: 300px; height: 300px; background: grey; position: relative; opacity: 1;}.bigger-container{ width: 300px; height: 300px; position: absolute; right: -10px; top: 0; overflow: hidden; background-image: url(http://pic1.win4000.com/wallpaper/0/54801a825e46e.jpg); background-repeat: no-repeat; box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.9);}.overlay{ position: absolute; width: 40px; height: 40px; z-index: 1; background: #fff; opacity: 0.7; pointer-events: none;}", 58 | "code-online-view-type": "top", 59 | "code-online-jsLib": [], 60 | "code-online-mode": "Babel", 61 | "code-online-cssLib": [], 62 | "author": "Xiao Jie Jie", 63 | "logo": "u5.png", 64 | "code-online-js": "let small = document.querySelector('.small-container');let radius = 20;let moving = false;let layer = document.querySelector('.overlay');let bigger = document.querySelector('.bigger-container');small.onmousemove = (e) => { let offsetX = e.offsetX; let offsetY = e.offsetY; let beginX = (offsetX - radius) < -20 ? -20 : offsetX - radius; let endX = (offsetX + radius) > 300 ? 300 : offsetX + radius; let beginY = (offsetY - radius) < -20 ? -20 : offsetY - radius; let endY = (offsetY + radius) > 300 ? 300 : offsetY + radius; console.log('p1: (' + beginX + ',' + beginY + ') p2: (' + endX + ',' + endY + ')'); moveOverlay([beginX, beginY]); changePosition([offsetX, offsetY]);}function moveOverlay(point) { layer.style.left = point[0] + 'px'; layer.style.top = point[1] + 'px';}function changePosition(point) { let perX = point[0]/3 + '%'; let perY = point[1]/3 + '%'; bigger.style.backgroundPosition = perX + ' ' + perY;}layer.onmousemove = (e) => { }", 65 | "code-online-html": "
\"\"
" 66 | }, 67 | { 68 | "id": "0006", 69 | "code-online-title": "Echarts Download As PDF", 70 | "code-online-css": "#wrap{ width: 600px; height: 500px; margin: 0 auto;}", 71 | "code-online-view-type": "top", 72 | "code-online-jsLib": ["https://cdnjs.cloudflare.com/ajax/libs/echarts/3.8.5/echarts.min.js", "https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.min.js"], 73 | "code-online-mode": "Babel", 74 | "code-online-cssLib": [], 75 | "author": "Xiao Jie Jie", 76 | "logo": "u5.png", 77 | "code-online-js": "let firstChart=echarts.init(document.getElementById(\"wrap\")),option={title:{text:\"ECharts Example\"},tooltip:{},legend:{data:[\"销量\",\"价格\"]},xAxis:{data:[\"衬衫\",\"羊毛衫\",\"裤子\",\"高跟鞋\",\"袜子\",\"衣服\"]},yAxis:{},series:[{name:\"销量\",type:\"bar\",data:[5,20,36,12,10,20]},{name:\"价格\",type:\"line\",data:[35,160,79,230,15,65]}]};firstChart.setOption(option),document.querySelector(\"button\").onclick=function(){html2pdf().set({margin:[.5,.5,.5,.5],filename:\"test.pdf\",image:{type:\"jpeg\",quality:.98},pagebreak:{mode:[\"avoid-all\"]},html2canvas:{dpi:192,letterRendering:!0,useCORS:!0,imageTimeout:0},useCORS:!0,jsPDF:{unit:\"in\",format:\"letter\",orientation:\"portrait\"}}).from(document.getElementById(\"wrap\")).toPdf().save()};", 78 | "code-online-html": "
" 79 | }, 80 | { 81 | "id": "0007", 82 | "code-online-title": "日历", 83 | "code-online-css": "html,body{width:100%;height:100%}.mr-date-picker-background{width:100%;height:100%;background:black;opacity:1;background-color:rgba(0,0,0,0.54);position:fixed;left:0;top:0;z-index:100}.mr-date-picker{width:400px;height:300px;background:#fff;position:absolute;overflow:hidden;left:50%;top:50%;transform:translate(-50%,-50%)}.mr-date-picker-day{display:inline-block;width:30px;height:30px;border-radius:50%;transition:all .5s;margin:2px;font-size:12px}.mr-date-picker-day:hover{background:#e85b74ad;cursor:pointer;color:#fff}.mr-date-picker-week{display:inline-block;width:30px;height:30px;font-size:12px;line-height:30px;text-align:center;margin:2px;color:grey}.mr-date-picker-value{width:30%;float:left;height:100%;background:#e85b74;transition:all .5s}.mr-date-picker-right{width:100%;float:right;margin:0;padding:0;height:30px;line-height:30px;text-align:center;transition:all 1s}.mr-date-picker-right-day{transition:all .5s}.mr-date-picker-day-container{overflow:hidden;width:70%;float:right;height:calc(100% - 110px)}.mr-date-picker-footer{width:70%;float:left;height:40px;position:relative}.mr-date-picker-right-week{width:70% !important}.mr-date-picker-ok-btn{position:absolute;right:26px;top:7px;color:#e85b74;font-weight:bold;font-size:14px;cursor:pointer;padding:5px 10px;text-align:center;border-radius:3px}.mr-date-picker-ok-btn:hover{background:#c5c0c0a3}.mr-date-picker-header{width:70%;float:right;margin:0;padding:0;height:40px;line-height:40px;text-align:center;position:relative}.mr-date-picker-day-empty{display:inline-block;width:30px;height:30px;color:transparent;margin:2px}.mr-date-picker-year-p{color:#ffffff9c;font-size:20px;margin:0;padding-left:20px;padding-top:20px;transition:all .5s}.mr-date-picker-month-p{color:#fff;font-size:30px;padding-left:18px;padding-top:10px;margin:0;transition:all .5s}.mr-date-picker-day-p{color:#fff;font-size:50px;padding-left:14px;margin:0;transition:all .5s}.mr-date-picker-day-active{background:#e85b74 !important;color:#fff}.mr-date-picker-month-before{border:0;position:absolute;left:30px;top:6px;background:0;font-size:18px;font-weight:bold;outline:0;cursor:pointer;color:grey}.mr-date-picker-month-after{border:0;position:absolute;right:27px;top:6px;background:0;font-size:18px;font-weight:bold;outline:0;cursor:pointer;color:grey}.mr-date-picker-month-after:hover{color:#e85b74}.mr-date-picker-month-before:hover{color:#e85b74}.mr-date-picker-month-after::before{content:\"\\276f\"}.mr-date-picker-month-before::before{content:\"\\276e\"}.mr-date-picker .click{content:'';left:50%;top:50%;display:inline-block;width:10px;height:10px;background:#dddada;position:absolute;transform:translate(-50%,-50%);animation:mr-tab-click .5s;animation-fill-mode:forwards;border-radius:50%;opacity:.9;pointer-events:none;z-index:10}@keyframes mr-tab-click{to{width:100px;height:100px;opacity:0}}", 84 | "code-online-view-type": "top", 85 | "code-online-jsLib": [], 86 | "code-online-mode": "None", 87 | "code-online-cssLib": [], 88 | "author": "Mushroom", 89 | "logo": "u1.png", 90 | "code-online-js": "class DatePicker{constructor(t){this.background=document.createElement(\"div\"),this.container=document.createElement(\"div\"),this.monthArr=[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],this.valueContainer=document.createElement(\"div\"),this.monthContainer=document.createElement(\"div\"),this.dayContainer=document.createElement(\"div\"),this.dayContainer.setAttribute(\"class\",\"mr-date-picker-day-container\"),this.monthSpan=document.createElement(\"span\"),this.background.setAttribute(\"class\",\"mr-date-picker-background\"),document.body.appendChild(this.background),this.background.appendChild(this.container),this.className=\"mr-date-picker\",this.options=t,this.options.container=this.container,this._init()}_init(){let t=this.options.defaultDate||(new Date).toLocaleDateString();this.date=new Date(t),this._parseDate(),this._render(),this.background.onclick=function(){this.background.parentNode.removeChild(this.background)}.bind(this),this.container.onclick=function(t){t.stopPropagation()}}_render(){this.options.container.setAttribute(\"class\",this.className),this.monthContainer.innerHTML=\"\";let t=document.createElement(\"button\"),e=document.createElement(\"button\");t.setAttribute(\"class\",\"mr-date-picker-month-before\"),e.setAttribute(\"class\",\"mr-date-picker-month-after\"),this.monthContainer.appendChild(t),this.monthContainer.appendChild(e),this.monthContainer.insertBefore(this.monthSpan,this.monthContainer.childNodes[1]),this.monthContainer.setAttribute(\"class\",\"mr-date-picker-header\"),this.options.container.insertBefore(this.monthContainer,this.options.container.childNodes[1]),t.onclick=function(t){this._rain(t),this._changeMonth(!1)}.bind(this),e.onclick=function(t){this._rain(t),this._changeMonth(!0)}.bind(this),this._renderValue(),this._renderMonth(),this._renderWeek(),this.options.container.appendChild(this.dayContainer),this._renderDay(!0),this._renderFooter()}_renderFooter(){let t=document.createElement(\"div\");t.setAttribute(\"class\",\"mr-date-picker-footer\");let e=document.createElement(\"span\");e.setAttribute(\"class\",\"mr-date-picker-ok-btn\"),e.innerText=\"OK\",t.appendChild(e),this.options.container.appendChild(t),e.onclick=function(t){this._rain(t),this.background.parentNode.removeChild(this.background),console.log(this.date.toLocaleDateString())}.bind(this)}_renderValue(){this.valueContainer.innerHTML=\"\";let t=document.createElement(\"p\"),e=document.createElement(\"p\"),n=document.createElement(\"p\");n.style.transform=\"translateY(100%)\",n.style.opacity=0,e.style.transform=\"translateX(100%)\",e.style.opacity=0,t.style.transform=\"translateX(-100%)\",t.style.opacity=0,this.valueContainer.setAttribute(\"class\",\"mr-date-picker-value\"),t.setAttribute(\"class\",\"mr-date-picker-year-p\"),e.setAttribute(\"class\",\"mr-date-picker-month-p\"),n.setAttribute(\"class\",\"mr-date-picker-day-p\"),t.innerText=this.year,e.innerText=this.monthArr[this.month].substring(0,3),n.innerText=this.day,this.valueContainer.appendChild(t),this.valueContainer.appendChild(e),this.valueContainer.appendChild(n),this.options.container.insertBefore(this.valueContainer,this.options.container.childNodes[0]),setTimeout(function(){n.style.transform=\"translateY(0%)\",n.style.opacity=1,e.style.transform=\"translateY(0%)\",e.style.opacity=1,t.style.transform=\"translateY(0%)\",t.style.opacity=1}.bind(this),500)}_fromWeek(t,e){let n=e-(t%7-1);return n<0?7+n:n}_renderDay(t){let e=document.querySelectorAll(\".mr-date-picker-right-day\");Array.prototype.slice.call(e).forEach(function(e,n){e.style.transform=t?\"translateX(-100%)\":\"translateX(100%)\"}),setTimeout(function(){this.dayContainer.innerHTML=\"\";let e=this._getDays(this.month),n=this._fromWeek(this.day,this.date.getDay()),i=Math.ceil((e+n)/7),r=1;for(let a=0;a=n+1&&r{t.setAttribute(\"class\",\"mr-date-picker-day\")}),t.setAttribute(\"class\",\"mr-date-picker-day mr-date-picker-day-active\"),this.day=t.innerText,this.date.setDate(Number(this.day)),this._parseDate(),this._renderValue(),this._renderMonth()}_renderWeek(){let t=[\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\" Fri\",\"Sat\"],e=document.createElement(\"div\");e.setAttribute(\"class\",\"mr-date-picker-right mr-date-picker-right-week\");for(let n=0;n<7;n++){let i=document.createElement(\"span\");i.innerText=t[n],i.setAttribute(\"class\",\"mr-date-picker-week\"),e.appendChild(i)}this.options.container.appendChild(e)}_getDays(t){\"number\"!=typeof t&&(t=Number(t));return-1!==[1,3,5,7,8,10,12].indexOf(++t)?31:-1!==[4,6,9,11].indexOf(t)?30:this.isLeapYear?29:28}_renderMonth(){this.monthContainer.removeChild(this.monthSpan),this.monthSpan=document.createElement(\"span\"),this.monthSpan.innerText=this.monthArr[this.month]+\" \"+this.year,this.monthContainer.insertBefore(this.monthSpan,this.monthContainer.childNodes[1])}_changeMonth(t){t?this.date.setMonth(this.date.getMonth()+1):this.date.setMonth(this.date.getMonth()-1),this._parseDate(),this._renderValue(),this._renderMonth(),this._renderDay(t)}_renderYear(){let t=document.createElement(\"div\");t.innerText=this.year,this.options.container.appendChild(t)}_rain(t){let e=document.createElement(\"span\"),n=t.offsetX,i=t.offsetY;e.setAttribute(\"class\",\"click\"),e.style.left=n+\"px\",e.style.top=i+\"px\",t.target.appendChild(e),setTimeout(()=>{t.target.removeChild(e)},500)}_parseDate(){this.year=this.date.getFullYear(),this.month=this.date.getMonth(),this.day=this.date.getDate(),this.week=this.date.getDay(),this.isLeapYear=this._isLeapYear(this.year)}_isLeapYear(t){return\"number\"!=typeof t&&(t=Number(t)),t%100==0?t%400==0:t%4==0}}let datePicker=document.querySelector(\".date\");new DatePicker({defaultDate:\"4/16/2018\"});", 91 | "code-online-html": "" 92 | }, 93 | { 94 | "id": "0008", 95 | "code-online-title": "立体的轮播", 96 | "code-online-css": ".wrap{width:600px;height:200px;margin:0 auto;padding:20px;border:1px solid #d4d4d4}.mr-carousel{width:100%;height:100%;position:relative;overflow:hidden}.mr-carousel:hover .mr-carousel-btn-before{opacity:.4}.mr-carousel:hover .mr-carousel-btn-after{opacity:.4}.mr-carousel-btn-before{width:30px;height:30px;display:inline-block;position:absolute;left:10px;top:50%;background:grey;color:#fff;z-index:30;transform:translateY(-50%);border-radius:50%;line-height:30px;text-align:center;opacity:0;transition:all 1s;cursor:pointer;font-size:x-small}.mr-carousel-btn-before:hover{opacity:.7 !important}.mr-carousel-btn-after:hover{opacity:.7 !important}.mr-carousel-btn-after{width:30px;height:30px;display:inline-block;position:absolute;right:10px;color:#fff;top:50%;background:grey;z-index:30;transform:translateY(-50%);border-radius:50%;line-height:30px;text-align:center;opacity:0;transition:all 1s;cursor:pointer;font-size:x-small}.mr-carousel-item{width:50%;height:50%;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:none;transition:all .5s;z-index:-1}.mr-carousel-item-before{left:20%;width:40%;height:60%;display:block;z-index:0}.mr-carousel-item-after{left:80%;width:40%;height:60%;display:block;z-index:0}.mr-carousel-item-center{display:block;z-index:20;width:60%;height:80%;left:50%;box-shadow:0 0 20px rgba(0,0,0,0.5)}", 97 | "code-online-view-type": "top", 98 | "code-online-jsLib": [], 99 | "code-online-mode": "None", 100 | "code-online-cssLib": [], 101 | "author": "Mushroom", 102 | "logo": "u2.png", 103 | "code-online-js": "class Carousel{constructor(t){this.className=\"mr-carousel\",this.options=t,this._init()}_init(){this._render()}_render(){this.options.container.setAttribute(\"class\",this.className),this.items=this.options.container.querySelectorAll(\"div\"),this.center=0,this._setLayer(this.center),this._loop(),this._createButton()}_loop(){this.timer=setInterval(function(){this.center\",this.options.container.appendChild(t),this.options.container.appendChild(e),this.reloopTimer,this._clickBefore(t),this._clickAfter(e)}_clickBefore(t){t.onclick=function(){clearInterval(this.timer),clearTimeout(this.reloopTimer),this.reloopTimer=setTimeout(function(){this._loop()}.bind(this),500),this.center<=0?this.center=this.items.length-1:this.center--,this._setLayer(this.center)}.bind(this)}_clickAfter(t){t.onclick=function(){clearInterval(this.timer),clearTimeout(this.reloopTimer),this.reloopTimer=setTimeout(function(){this._loop()}.bind(this),500),this.centerthis.items.length-1?0:t+1;Array.prototype.slice.call(this.items).forEach((i,r)=>{r===e?(i.style.zIndex=0,i.setAttribute(\"class\",\"mr-carousel-item mr-carousel-item-before\")):r===t?(i.style.zIndex=20,i.setAttribute(\"class\",\"mr-carousel-item mr-carousel-item-center\")):r===s?(i.style.zIndex=0,i.setAttribute(\"class\",\"mr-carousel-item mr-carousel-item-after\")):(i.style.zIndex=-1,setTimeout(function(){i.setAttribute(\"class\",\"mr-carousel-item\")},500))})}}let carousel=document.querySelector(\".test\");new Carousel({container:carousel});", 104 | "code-online-html": "
div1
div2
div3
div4
div5
" 105 | }, 106 | { 107 | "id": "0009", 108 | "code-online-title": "3D例子", 109 | "code-online-css": ".wrap{width:100%;height:400px;-webkit-perspective:2000px;-webkit-perspective-origin:center -100%;padding:100px;background:black}img{width:100%;height:100%}.view{width:300px;height:300px;margin:0 auto;position:relative;transform-style:preserve-3d;transform-origin:150px 150px}.view:hover{animation:rotate 5s linear 0s infinite}.view>.img{opacity:.9;width:200px;height:200px;position:absolute}.view>.out{opacity:.5;width:300px;height:300px;position:absolute}.left{background:blue;transform:rotateY(90deg) translateY(50px) translateZ(-50px)}.right{background:green;transform:rotateY(90deg) translateZ(150px) translateY(50px)}.top{background:red;transform:rotateX(90deg) translateZ(50px) translateX(50px)}.bottom{background:black;transform:rotateX(90deg) translateZ(-150px) translateX(50px)}.front{background:yellow;transform:rotateX(0) translateZ(100px) translateX(50px) translateY(50px)}.back{background:yellow;transform:rotateX(0) translateZ(-100px) translateX(50px) translateY(50px)}@keyframes rotate{0%{transform:rotate3d(0,1,0,0)}100%{transform:rotate3d(0,1,0,360deg)}}.out-left{background:white;transform:rotateY(90deg) translateZ(-150px)}.out-right{background:white;transform:rotateY(90deg) translateZ(150px)}.out-top{background:white;transform:rotateX(90deg) translateZ(150px)}.out-bottom{background:white;transform:rotateX(90deg) translateZ(-150px)}.out-front{background:white;transform:rotateX(0) translateZ(150px)}.out-back{background:white;transform:rotateX(0) translateZ(-150px)}", 110 | "code-online-view-type": "top", 111 | "code-online-jsLib": [], 112 | "code-online-mode": "None", 113 | "code-online-cssLib": [], 114 | "author": "Mushroom", 115 | "logo": "u5.png", 116 | "code-online-js": "", 117 | "code-online-html": "
\"\"/
\"\"/
\"\"/
\"\"/
\"\"/
\"\"/
" 118 | } 119 | ] --------------------------------------------------------------------------------