├── .editorconfig ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── .yo-rc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── config ├── helpers.js ├── jestGlobalMocks.ts └── setupJest.ts ├── demo ├── .editorconfig ├── .firebase │ └── hosting.ZGlzdC9icm93c2Vy.cache ├── .firebaserc ├── .gitignore ├── README.md ├── angular.json ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── firebase.json ├── package-lock.json ├── package.json ├── prerender.ts ├── proxy.conf.json ├── server.ts ├── src │ ├── _variables.scss │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── app.server.module.ts │ │ ├── getting-started │ │ │ ├── getting-started-routing.module.ts │ │ │ ├── getting-started.component.html │ │ │ ├── getting-started.component.scss │ │ │ ├── getting-started.component.spec.ts │ │ │ ├── getting-started.component.ts │ │ │ └── getting-started.module.ts │ │ ├── home │ │ │ ├── home-routing.module.ts │ │ │ ├── home.component.html │ │ │ ├── home.component.scss │ │ │ ├── home.component.spec.ts │ │ │ ├── home.component.ts │ │ │ └── home.module.ts │ │ ├── material.module.ts │ │ └── shared │ │ │ ├── content-wrapper │ │ │ ├── content-wrapper.component.html │ │ │ ├── content-wrapper.component.scss │ │ │ ├── content-wrapper.component.spec.ts │ │ │ └── content-wrapper.component.ts │ │ │ ├── footer │ │ │ ├── footer.component.html │ │ │ ├── footer.component.scss │ │ │ ├── footer.component.spec.ts │ │ │ └── footer.component.ts │ │ │ ├── header │ │ │ ├── header.component.html │ │ │ ├── header.component.scss │ │ │ ├── header.component.spec.ts │ │ │ └── header.component.ts │ │ │ ├── index.ts │ │ │ └── shared.module.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── .npmignore │ │ ├── forms.png │ │ ├── forms.svg │ │ └── logo.svg │ ├── browserslist │ ├── environments │ │ ├── environment.hmr.ts │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── highlight.js.scss │ ├── hmr.ts │ ├── index.html │ ├── jestGlobalMocks.ts │ ├── karma.conf.js │ ├── main.server.ts │ ├── main.ts │ ├── polyfills.ts │ ├── setupJest.ts │ ├── styles.scss │ ├── test.ts │ ├── testing │ │ ├── index.ts │ │ └── router-stubs.ts │ ├── tsconfig.app.json │ ├── tsconfig.server.json │ ├── tsconfig.spec.json │ └── typings.d.ts ├── static.paths.ts ├── tsconfig.json ├── tslint.json └── webpack.server.config.js ├── greenkeeper.json ├── gulpfile.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── index.ts ├── module │ ├── editor │ │ ├── editor.component.html │ │ ├── editor.component.scss │ │ ├── editor.component.ts │ │ └── toolbar │ │ │ ├── toolbar.component.html │ │ │ ├── toolbar.component.scss │ │ │ └── toolbar.component.ts │ ├── lib.interface.ts │ ├── lib.module.ts │ ├── material.module.ts │ ├── service │ │ ├── lib.service.spec.ts │ │ └── lib.service.ts │ └── utils │ │ └── index.ts ├── tsconfig.lib.es5.json ├── tsconfig.lib.json └── tsconfig.spec.json ├── tsconfig.json ├── tslint.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://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 = 0 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | ### Bug Report or Feature Request (mark with an `x`) 5 | ``` 6 | - [ ] bug report -> please search issues before submitting 7 | - [ ] feature request 8 | ``` 9 | 10 | ### OS and Version? 11 | 14 | 15 | ### Versions 16 | 20 | 21 | 22 | ### Repro steps 23 | 28 | 29 | 30 | ### The log given by the failure 31 | 32 | 33 | 34 | ### Desired functionality 35 | 39 | 40 | 41 | ### Mention any other details that might be useful 42 | 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | 10 | # IDEs and editors 11 | /.idea 12 | .project 13 | .classpath 14 | .c9/ 15 | *.launch 16 | .settings/ 17 | *.sublime-workspace 18 | 19 | # IDE - VSCode 20 | .vscode/* 21 | !.vscode/settings.json 22 | !.vscode/tasks.json 23 | !.vscode/launch.json 24 | !.vscode/extensions.json 25 | 26 | # misc 27 | /.sass-cache 28 | /connect.lock 29 | /coverage 30 | /libpeerconnection.log 31 | npm-debug.log 32 | yarn-error.log 33 | testem.log 34 | /typings 35 | /config/gulp-tasks/README.md 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | 4 | #install google chrome, using addons 5 | addons: 6 | apt: 7 | sources: 8 | - google-chrome 9 | packages: 10 | - google-chrome-stable 11 | 12 | language: node_js 13 | node_js: 14 | - "8" 15 | 16 | before_script: 17 | - export DISPLAY=:99.0 18 | - sh -e /etc/init.d/xvfb start 19 | - npm install --quiet -g gulp-cli 20 | 21 | script: gulp test:ci 22 | 23 | after_success: gulp coveralls 24 | 25 | cache: 26 | yarn: true 27 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-ngx-library": { 3 | "version": "6.2.1", 4 | "authorName": "Michael Doye", 5 | "authorEmail": "michaeldoye@gmail.com", 6 | "githubUsername": "michaeldoye", 7 | "githubRepoName": "mat-markdown-editor", 8 | "projectName": "mat-markdown-editor", 9 | "projectVersion": "0.0.1", 10 | "projectDescription": "Material design markdown editor", 11 | "projectKeywords": [ 12 | "markdown", 13 | "text editor", 14 | "angular", 15 | "material design" 16 | ], 17 | "ngVersion": "6.0.0",\ 18 | "ngModules": [ 19 | "core", 20 | "common" 21 | ], 22 | "otherDependencies": [], 23 | "additionalPackageFiles": [], 24 | "dependenciesRange": "^", 25 | "ngPrefix": "ngx-mde", 26 | "testingFramework": "jest", 27 | "useGreenkeeper": true, 28 | "useCompodoc": true, 29 | "enforceNgGitCommitMsg": true, 30 | "exclusions": [ 31 | "config/karma.conf.js", 32 | "config/webpack.test.js", 33 | "config/karma-test-shim.js" 34 | ], 35 | "deleteExclusions": [] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [0.0.8](https://github.com/michaeldoye/mat-markdown-editor/compare/v0.0.7...v0.0.8) (2019-03-27) 3 | 4 | 5 | ### Bug Fixes 6 | 7 | * **demo:** readme update ([b3a1c77](https://github.com/michaeldoye/mat-markdown-editor/commit/b3a1c77)) 8 | * **demo:** readme update ([39b399e](https://github.com/michaeldoye/mat-markdown-editor/commit/39b399e)) 9 | * **lib:** update travis ([8dfda7d](https://github.com/michaeldoye/mat-markdown-editor/commit/8dfda7d)) 10 | 11 | 12 | 13 | 14 | ## [0.0.7](https://github.com/michaeldoye/mat-markdown-editor/compare/v0.0.6...v0.0.7) (2019-03-20) 15 | 16 | 17 | 18 | 19 | ## [0.0.6](https://github.com/michaeldoye/mat-markdown-editor/compare/v0.0.5...v0.0.6) (2019-03-20) 20 | 21 | 22 | 23 | 24 | ## [0.0.5](https://github.com/michaeldoye/mat-markdown-editor/compare/v0.0.4...v0.0.5) (2019-03-20) 25 | 26 | 27 | 28 | 29 | ## [0.0.4](https://github.com/michaeldoye/mat-markdown-editor/compare/v0.0.3...v0.0.4) (2019-03-20) 30 | 31 | 32 | 33 | 34 | ## [0.0.3](https://github.com/michaeldoye/mat-markdown-editor/compare/v0.0.2...v0.0.3) (2019-03-19) 35 | 36 | 37 | 38 | 39 | ## [0.0.2](https://github.com/michaeldoye/mat-markdown-editor/compare/aa4765c...v0.0.2) (2019-03-19) 40 | 41 | 42 | ### Bug Fixes 43 | 44 | * **demo:** add usage to readme ([f717d4e](https://github.com/michaeldoye/mat-markdown-editor/commit/f717d4e)) 45 | * **demo:** fixed logo in readme ([5035304](https://github.com/michaeldoye/mat-markdown-editor/commit/5035304)) 46 | * **demo:** readme update ([3ab2067](https://github.com/michaeldoye/mat-markdown-editor/commit/3ab2067)) 47 | * **lib:** added svg logo ([7c7bb07](https://github.com/michaeldoye/mat-markdown-editor/commit/7c7bb07)) 48 | * **lib:** greenkeeper ignore ([2eae841](https://github.com/michaeldoye/mat-markdown-editor/commit/2eae841)) 49 | * **lib:** ts version ([09ae721](https://github.com/michaeldoye/mat-markdown-editor/commit/09ae721)) 50 | * **lib:** updated logo ([cfbe38d](https://github.com/michaeldoye/mat-markdown-editor/commit/cfbe38d)) 51 | 52 | 53 | ### Features 54 | 55 | * **lib:** initial commit ([aa4765c](https://github.com/michaeldoye/mat-markdown-editor/commit/aa4765c)) 56 | * **lib:** pass all options via one object ([122d493](https://github.com/michaeldoye/mat-markdown-editor/commit/122d493)) 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Michael Doye 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Material Design Markdown Editor 6 | 7 | [![npm version](https://badge.fury.io/js/mat-markdown-editor.svg)](https://badge.fury.io/js/mat-markdown-editor) 8 | [![Build Status](https://travis-ci.org/michaeldoye/mat-markdown-editor.svg?branch=master)](https://travis-ci.org/michaeldoye/mat-markdown-editor) 9 | [![Coverage Status](https://coveralls.io/repos/github/michaeldoye/mat-markdown-editor/badge.svg?branch=master)](https://coveralls.io/github/michaeldoye/mat-markdown-editor?branch=master) 10 | [![dependency Status](https://david-dm.org/michaeldoye/mat-markdown-editor/status.svg)](https://david-dm.org/michaeldoye/mat-markdown-editor) 11 | [![devDependency Status](https://david-dm.org/michaeldoye/mat-markdown-editor/dev-status.svg?branch=master)](https://david-dm.org/michaeldoye/mat-markdown-editor#info=devDependencies) 12 | [![Greenkeeper Badge](https://badges.greenkeeper.io/michaeldoye/mat-markdown-editor.svg)](https://greenkeeper.io/) 13 | 14 | ## Demo 15 | 16 | View it in action at https://mat-markdown-editor.firebaseapp.com 17 | 18 | Edit on StackBlitz: https://stackblitz.com/edit/angular-w4tejv 19 | 20 | ## Dependencies 21 | * [Angular](https://angular.io) (*requires* Angular 2 or higher, tested with 2.0.0) 22 | * [Angular Material](https://material.angular.io/) 23 | 24 | ## Installation 25 | Install above dependencies via *npm*. 26 | 27 | Now install `mat-markdown-editor` via: 28 | ```shell 29 | npm install --save mat-markdown-editor 30 | ``` 31 | 32 | Add the following to your `index.html` (or [configure](https://nitayneeman.com/posts/how-to-add-third-party-library-in-angular-cli/) via `angular-cli.json`) 33 | * [Marked JS](https://marked.js.org/#/README.md#README.md) 34 | * [Hightlight JS](https://highlightjs.org/) 35 | * [Ace Editor](https://ace.c9.io/) 36 | 37 | ```html 38 | 39 | 40 | 41 | ``` 42 | 43 | --- 44 | ##### SystemJS 45 | >**Note**:If you are using `SystemJS`, you should adjust your configuration to point to the UMD bundle. 46 | In your systemjs config file, `map` needs to tell the System loader where to look for `mat-markdown-editor`: 47 | ```js 48 | map: { 49 | 'mat-markdown-editor': 'node_modules/mat-markdown-editor/bundles/mat-markdown-editor.umd.js', 50 | } 51 | ``` 52 | --- 53 | 54 | Once installed you need to import the main module: 55 | ```js 56 | import { MatMarkdownEditorModule } from 'mat-markdown-editor'; 57 | ``` 58 | The only remaining part is to list the imported module in your application module. The exact method will be slightly 59 | different for the root (top-level) module for which you should end up with the code similar to (notice ` MatMarkdownEditorModule.forRoot()`): 60 | ```js 61 | import { MatMarkdownEditorModule } from 'mat-markdown-editor'; 62 | 63 | @NgModule({ 64 | declarations: [AppComponent, ...], 65 | imports: [MatMarkdownEditorModule.forRoot(), ...], 66 | bootstrap: [AppComponent] 67 | }) 68 | export class AppModule { 69 | } 70 | ``` 71 | 72 | Other modules in your application can simply import ` MatMarkdownEditorModule `: 73 | 74 | ```js 75 | import { MatMarkdownEditorModule } from 'mat-markdown-editor'; 76 | 77 | @NgModule({ 78 | declarations: [OtherComponent, ...], 79 | imports: [MatMarkdownEditorModule, ...], 80 | }) 81 | export class OtherModule { 82 | } 83 | ``` 84 | 85 | ## Usage 86 | 87 | ```js 88 | import { Component } from '@angular/core'; 89 | import { MatMarkdownEditorOptions } from 'mat-markdown-editor'; 90 | 91 | @Component({ 92 | selector: 'app-home', 93 | template: ` 94 |
95 | 101 | 102 |
103 | `, 104 | }) 105 | export class HomeComponent { 106 | public options: MatMarkdownEditorOptions = { 107 | enablePreviewContentClick: false, 108 | resizable: true, 109 | showBorder: true, 110 | hideIcons: {}, 111 | hideToolbar: false, 112 | height: '500px', 113 | mode: 'editor', 114 | toolbarColor: 'primary', 115 | preRender: this.preRender, 116 | }; 117 | 118 | preRender(markDown: any) { 119 | // Here you have access to the markdown binding 120 | // before it is rendered 121 | return markDown; 122 | } 123 | } 124 | ``` 125 | All options can be found [here](https://github.com/michaeldoye/mat-markdown-editor/blob/master/src/module/lib.interface.ts) 126 | 127 | 128 | 129 | ## Run Demo App Locally 130 | 131 | - [clone this repo](https://github.com/michaeldoye/mat-markdown-editor.git) by running 132 | ```bash 133 | $ git clone https://github.com/michaeldoye/mat-markdown-editor.git 134 | ``` 135 | 136 | - link the **mat-markdown-editor** package 137 | 138 | ```bash 139 | $ gulp link 140 | ``` 141 | 142 | - navigate to the demo app directory 143 | ```bash 144 | $ cd demo 145 | ``` 146 | 147 | - install the dependencies 148 | ```bash 149 | $ npm i 150 | ``` 151 | 152 | - run/start/serve the app 153 | ```bash 154 | $ npm run start 155 | ``` 156 | or 157 | ```bash 158 | $ ng serve --open 159 | ``` 160 | - the app is now hosted by `http://localhost:4200/` 161 | 162 | 163 | 164 | 165 | ## Development 166 | 167 | 1. clone this [repo](https://github.com/michaeldoye/mat-markdown-editor.git) 168 | 2. Install the dependencies by running `npm i` 169 | 3. build the library `npm run build` or `gulp build` 170 | 4. Link the library `gulp link` 171 | 5. Navigate to the demo app's directory 172 | - `cd demo` 173 | _ `npm i` 174 | _ `npm start` 175 | 176 | ## License 177 | 178 | Copyright (c) 2019 Michael Doye. Licensed under the MIT License (MIT) 179 | 180 | -------------------------------------------------------------------------------- /config/helpers.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const path = require('path'); 3 | const exec = require('child_process').exec; 4 | 5 | const _root = path.resolve(__dirname, '..'); 6 | 7 | 8 | /** 9 | * Plaform independant path to an executable cmd 10 | * @param {string} path 11 | */ 12 | platformPath = (path) => { 13 | return /^win/.test(os.platform()) ? `${path}.cmd` : path; 14 | }; 15 | 16 | /** 17 | * 18 | * @param {string[]} args 19 | */ 20 | rootDir = (...args) => { 21 | return path.join.apply(path, [_root].concat(...args)); 22 | }; 23 | 24 | /** 25 | * 26 | * @param {string} cmd 27 | */ 28 | binPath = (cmd) => { 29 | return platformPath(`/node_modules/.bin/${cmd}`); 30 | }; 31 | 32 | /** 33 | * Promisified child_process.exec 34 | * 35 | * @param cmd 36 | * @param opts See child_process.exec node docs 37 | * @returns {Promise} 38 | */ 39 | execp = (cmd, opts) => { 40 | opts = Object.assign(opts || {}, { 41 | stdout: process.stdout, 42 | stderr: process.stderr 43 | }); 44 | return new Promise((resolve, reject) => { 45 | const child = exec(cmd, opts, 46 | (err, stdout, stderr) => err ? reject(err.code) : resolve(0)); 47 | 48 | if (opts.stdout) { 49 | child.stdout.pipe(opts.stdout); 50 | } 51 | if (opts.stderr) { 52 | child.stderr.pipe(opts.stderr); 53 | } 54 | }); 55 | }; 56 | 57 | /** 58 | * Install dependencies using yarn, if present, or npm otherwise. 59 | * @param opts See child_process.exec node docs 60 | * @returns {Promise} 61 | */ 62 | installDependencies = (opts) => { 63 | return execp('yarn -v') // first try to install deps using yarn 64 | .then(exitCode => exitCode === 0 ? execp('yarn install', opts) : execp('npm install', opts)); 65 | }; 66 | 67 | var exports = module.exports = { 68 | root: rootDir, 69 | execp: execp, 70 | binPath: binPath, 71 | platformPath: platformPath, 72 | installDependencies: installDependencies 73 | }; 74 | -------------------------------------------------------------------------------- /config/jestGlobalMocks.ts: -------------------------------------------------------------------------------- 1 | global['CSS'] = null; 2 | 3 | const mock = () => { 4 | let storage = {}; 5 | return { 6 | getItem: (key: string) => key in storage ? storage[key] : null, 7 | setItem: (key: string | number, value: string) => storage[key] = value || '', 8 | removeItem: (key: string | number) => delete storage[key], 9 | clear: () => storage = {}, 10 | }; 11 | }; 12 | 13 | Object.defineProperty(window, 'localStorage', {value: mock()}); 14 | Object.defineProperty(window, 'sessionStorage', {value: mock()}); 15 | Object.defineProperty(document, 'doctype', { 16 | value: '' 17 | }); 18 | Object.defineProperty(window, 'getComputedStyle', { 19 | value: () => { 20 | return { 21 | display: 'none', 22 | appearance: ['-webkit-appearance'] 23 | }; 24 | } 25 | }); 26 | /** 27 | * ISSUE: https://github.com/angular/material2/issues/7101 28 | * Workaround for JSDOM missing transform property 29 | */ 30 | Object.defineProperty(document.body.style, 'transform', { 31 | value: () => { 32 | return { 33 | enumerable: true, 34 | configurable: true, 35 | }; 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /config/setupJest.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular'; 2 | import './jestGlobalMocks'; 3 | -------------------------------------------------------------------------------- /demo/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://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 | -------------------------------------------------------------------------------- /demo/.firebase/hosting.ZGlzdC9icm93c2Vy.cache: -------------------------------------------------------------------------------- 1 | 4.8c8d0bb3ab912bd7f8bf.js,1553072127206,315863f1ac769487b9b217511c532a3cec7188b436fff2bbec8309a62edd6d82 2 | favicon.ico,1553072127206,3c8f1dca744007357393e9228949f1d36e0865c21c06cb504be0fa21e397df5f 3 | index.html,1553072127207,6961b7a9d946e868f63ec6d2ea65f563f0ae864a4d34f80f2b50c144c95dfb0a 4 | 3rdpartylicenses.txt,1553072127205,031ee3198184597544d063de32568ea37ac7ea04cb9ece0b062cc31c3f3a0a60 5 | runtime.ff57a64bedad5d60e350.js,1553072127206,786cbf52c8342046f1f9a399730ddaa838fdc594c5046c5ac55f5c7d747d6d22 6 | assets/forms.png,1553072127207,361a875eecaab41bb23b427add7fa92300392acfafc20fe8e5db460c259f2632 7 | assets/forms.svg,1553072127207,80c218a9ad36f618eb0c2b10c385c79f3833d8dcd17096195da40937e9ff7066 8 | assets/logo.svg,1553072127207,04e531ef510c0566b0b3a7895158bad2bba2da4fff93a1d25899073f88cdd82f 9 | polyfills.a9824751764fbcd6131c.js,1553072127206,827452fcaf4948f7e6df0a8551e61fb7ab5d60a0a4633893ee9733d1b288882b 10 | fontawesome-webfont.af7ae505a9eed503f8b8.woff2,1553072127206,156e171dae6239bcd8304d42163d8b1e6bfd029759d46be88a4e446a51249ba2 11 | fontawesome-webfont.fee66e712a8a08eef580.woff,1553072127205,9cb84ef5f51a04cf0dd3a9aec98c43ad4d44df442b7454c6b448913e36fb0c43 12 | fontawesome-webfont.674f50d287a8c48dc19b.eot,1553072127206,9acdf34fe486fad3cfa8ef4aa925ebbe9e955c8a8d127bff4d427620b0eeb643 13 | fontawesome-webfont.b06871f281fee6b241d6.ttf,1553072127206,225dc03087123b26cb71296d418705ec2e89e826acd04bfe6fc6353a0f5220c8 14 | styles.bdaf6eb4c09997661380.css,1553072127206,79cde03b7ffea9a69654880b2774aef8724c85c42255c0dcbdd63da82e393493 15 | main.415e51ee6651ef6c11ce.js,1553072127206,b4c54f182fe9e17709b7bcbf0e751bcc081ffb4e59521bd13863d9d2937be849 16 | fontawesome-webfont.912ec66d7572ff821749.svg,1553072127206,303fc405939cc4d296906102b8047b71a4ec14a7b51aa7a2abfaad416ec8fb3c 17 | -------------------------------------------------------------------------------- /demo/.firebaserc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /demo/.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 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # mat-markdown-editor-demo 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /demo/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "mat-markdown-editor-demo": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/browser", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.scss" 27 | ], 28 | "scripts": [] 29 | }, 30 | "configurations": { 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "src/environments/environment.ts", 35 | "with": "src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "extractCss": true, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true 47 | }, 48 | "hmr": { 49 | "fileReplacements": [ 50 | { 51 | "replace": "src/environments/environment.ts", 52 | "with": "src/environments/environment.hmr.ts" 53 | } 54 | ] 55 | } 56 | } 57 | }, 58 | "serve": { 59 | "builder": "@angular-devkit/build-angular:dev-server", 60 | "options": { 61 | "browserTarget": "mat-markdown-editor-demo:build", 62 | "hmrWarning": false 63 | }, 64 | "configurations": { 65 | "production": { 66 | "browserTarget": "mat-markdown-editor-demo:build:production" 67 | }, 68 | "hmr": { 69 | "hmr": true, 70 | "browserTarget": "mat-markdown-editor-demo:build:hmr" 71 | } 72 | } 73 | }, 74 | "extract-i18n": { 75 | "builder": "@angular-devkit/build-angular:extract-i18n", 76 | "options": { 77 | "browserTarget": "mat-markdown-editor-demo:build" 78 | } 79 | }, 80 | "test": { 81 | "builder": "@angular-devkit/build-angular:karma", 82 | "options": { 83 | "main": "src/test.ts", 84 | "polyfills": "src/polyfills.ts", 85 | "tsConfig": "src/tsconfig.spec.json", 86 | "karmaConfig": "src/karma.conf.js", 87 | "styles": [ 88 | "styles.scss" 89 | ], 90 | "scripts": [], 91 | "assets": [ 92 | "src/favicon.ico", 93 | "src/assets" 94 | ] 95 | } 96 | }, 97 | "lint": { 98 | "builder": "@angular-devkit/build-angular:tslint", 99 | "options": { 100 | "tsConfig": [ 101 | "src/tsconfig.app.json", 102 | "src/tsconfig.spec.json" 103 | ], 104 | "exclude": [ 105 | "**/node_modules/**" 106 | ] 107 | } 108 | }, 109 | "server": { 110 | "builder": "@angular-devkit/build-angular:server", 111 | "options": { 112 | "outputPath": "dist/server", 113 | "main": "src/main.server.ts", 114 | "tsConfig": "src/tsconfig.server.json" 115 | } 116 | } 117 | } 118 | }, 119 | "mat-markdown-editor-demo-e2e": { 120 | "root": "e2e/", 121 | "projectType": "application", 122 | "architect": { 123 | "e2e": { 124 | "builder": "@angular-devkit/build-angular:protractor", 125 | "options": { 126 | "protractorConfig": "e2e/protractor.conf.js", 127 | "devServerTarget": "mat-markdown-editor-demo:serve" 128 | } 129 | }, 130 | "lint": { 131 | "builder": "@angular-devkit/build-angular:tslint", 132 | "options": { 133 | "tsConfig": "e2e/tsconfig.e2e.json", 134 | "exclude": [ 135 | "**/node_modules/**" 136 | ] 137 | } 138 | } 139 | } 140 | } 141 | }, 142 | "defaultProject": "mat-markdown-editor-demo" 143 | } -------------------------------------------------------------------------------- /demo/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /demo/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { NgxMarkdownEditorDemoPage } from './app.po'; 2 | 3 | describe('mat-markdown-editor-demo App', () => { 4 | let page: NgxMarkdownEditorDemoPage; 5 | 6 | beforeEach(() => { 7 | page = new NgxMarkdownEditorDemoPage (); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /demo/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class NgxMarkdownEditorDemoPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /demo/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist/browser", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mat-markdown-editor-demo", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "description": "Demo app for mat-markdown-editor", 6 | "scripts": { 7 | "ng": "ng", 8 | "start": "ng serve", 9 | "build": "ng build", 10 | "test": "jest", 11 | "lint": "ng lint", 12 | "e2e": "ng e2e", 13 | "postinstall": "npm link mat-markdown-editor", 14 | "builddemo": "gulp build && sudo gulp link && npm i && npm start" 15 | }, 16 | "private": true, 17 | "dependencies": { 18 | "@angular/animations": "^7.2.8", 19 | "@angular/cdk": "^7.3.3", 20 | "@angular/common": "^7.2.8", 21 | "@angular/compiler": "^7.2.8", 22 | "@angular/core": "^7.2.8", 23 | "@angular/flex-layout": "^7.0.0-beta.23", 24 | "@angular/forms": "^7.2.8", 25 | "@angular/http": "^7.2.8", 26 | "@angular/material": "^7.3.3", 27 | "@angular/platform-browser": "^7.2.8", 28 | "@angular/platform-browser-dynamic": "^7.2.8", 29 | "@angular/platform-server": "^7.2.8", 30 | "@angular/router": "^7.2.8", 31 | "@ng-bootstrap/ng-bootstrap": "4.1.0", 32 | "@stackblitz/sdk": "^1.2.0", 33 | "bootstrap": "4.3.1", 34 | "core-js": "^2.5.4", 35 | "font-awesome": "^4.7.0", 36 | "hammerjs": "^2.0.8", 37 | "rxjs": "^6.4.0", 38 | "zone.js": "^0.8.26" 39 | }, 40 | "devDependencies": { 41 | "@angular-devkit/build-angular": "~0.13.5", 42 | "@angular/cli": "~7.3.5", 43 | "@angular/compiler-cli": "^7.2.8", 44 | "@angular/language-service": "^7.2.8", 45 | "@angularclass/hmr": "~2.1.3", 46 | "@compodoc/gulp-compodoc": "0.0.10", 47 | "@nguniversal/common": "^7.1.1", 48 | "@nguniversal/express-engine": "^7.1.1", 49 | "@nguniversal/module-map-ngfactory-loader": "^7.1.1", 50 | "@types/jest": "24.0.11", 51 | "@types/node": "~11.11.0", 52 | "angular-cli-ghpages": "0.5.3", 53 | "ansi-colors": "3.2.4", 54 | "codelyzer": "^4.0.1", 55 | "commitplease": "3.2.0", 56 | "conventional-github-releaser": "3.1.2", 57 | "del": "4.0.0", 58 | "express": "^4.16.2", 59 | "fancy-log": "1.3.3", 60 | "gulp": "^3.9.1", 61 | "gulp-bump": "3.1.3", 62 | "gulp-conventional-changelog": "2.0.10", 63 | "gulp-coveralls": "0.1.4", 64 | "gulp-file": "0.4.0", 65 | "gulp-git": "2.9.0", 66 | "gulp-hub": "4.2.0", 67 | "jest": "24.3.1", 68 | "jest-preset-angular": "7.0.1", 69 | "lodash": "4.17.11", 70 | "prettier": "1.16.4", 71 | "protractor": "~5.4.2", 72 | "reflect-metadata": "~0.1.10", 73 | "run-sequence": "2.2.1", 74 | "travis-status": "3.0.1", 75 | "ts-loader": "~5.3.3", 76 | "ts-node": "~8.0.3", 77 | "tslint": "~5.13.1", 78 | "typescript": "3.1.1", 79 | "webpack-cli": "^3.2.3", 80 | "yargs": "13.2.2" 81 | }, 82 | "jest": { 83 | "preset": "jest-preset-angular", 84 | "coverageReporters": [ 85 | "lcov", 86 | "text" 87 | ], 88 | "setupTestFrameworkScriptFile": "/src/setupJest.ts" 89 | }, 90 | "prettier": { 91 | "trailingComma": "es5", 92 | "tabWidth": 2, 93 | "semi": true, 94 | "singleQuote": true 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /demo/prerender.ts: -------------------------------------------------------------------------------- 1 | // Load zone.js for the server. 2 | import 'zone.js/dist/zone-node'; 3 | import 'reflect-metadata'; 4 | import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; 5 | import { join } from 'path'; 6 | 7 | import { enableProdMode } from '@angular/core'; 8 | // Faster server renders w/ Prod mode (dev mode never needed) 9 | enableProdMode(); 10 | 11 | // Import module map for lazy loading 12 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; 13 | import { renderModuleFactory } from '@angular/platform-server'; 14 | import { ROUTES } from './static.paths'; 15 | 16 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack 17 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main'); 18 | 19 | const BROWSER_FOLDER = join(process.cwd(), 'dist', 'browser'); 20 | 21 | // Load the index.html file containing referances to your application bundle. 22 | const index = readFileSync(join(BROWSER_FOLDER, 'index.html'), 'utf8'); 23 | 24 | let previousRender = Promise.resolve(); 25 | 26 | // Iterate each route path 27 | ROUTES.forEach(route => { 28 | var fullPath = join(BROWSER_FOLDER, route); 29 | 30 | // Make sure the directory structure is there 31 | if (!existsSync(fullPath)) { 32 | mkdirSync(fullPath); 33 | } 34 | 35 | // Writes rendered HTML to index.html, replacing the file if it already exists. 36 | previousRender = previousRender.then(_ => renderModuleFactory(AppServerModuleNgFactory, { 37 | document: index, 38 | url: route, 39 | extraProviders: [ 40 | provideModuleMap(LAZY_MODULE_MAP) 41 | ] 42 | })).then(html => writeFileSync(join(fullPath, 'index.html'), html)); 43 | }); 44 | -------------------------------------------------------------------------------- /demo/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/doc/*": { 3 | "target": "http://localhost:8080", 4 | "secure": false, 5 | "pathRewrite": {"^/doc" : ""}, 6 | "logLevel": "info" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /demo/server.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js/dist/zone-node'; 2 | import 'reflect-metadata'; 3 | import { enableProdMode } from '@angular/core'; 4 | // Express Engine 5 | import { ngExpressEngine } from '@nguniversal/express-engine'; 6 | // Import module map for lazy loading 7 | import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; 8 | 9 | import * as express from 'express'; 10 | import { join } from 'path'; 11 | 12 | // Faster server renders w/ Prod mode (dev mode never needed) 13 | enableProdMode(); 14 | 15 | // Express server 16 | const app = express(); 17 | 18 | const PORT = process.env.PORT || 4000; 19 | const DIST_FOLDER = join(process.cwd(), 'dist'); 20 | 21 | // * NOTE :: leave this as require() since this file is built Dynamically from webpack 22 | const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main'); 23 | 24 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) 25 | app.engine('html', ngExpressEngine({ 26 | bootstrap: AppServerModuleNgFactory, 27 | providers: [ 28 | provideModuleMap(LAZY_MODULE_MAP) 29 | ] 30 | })); 31 | 32 | app.set('view engine', 'html'); 33 | app.set('views', join(DIST_FOLDER, 'browser')); 34 | 35 | // Example Express Rest API endpoints 36 | // app.get('/api/**', (req, res) => { }); 37 | // Server static files from /browser 38 | app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), { 39 | maxAge: '1y' 40 | })); 41 | 42 | // All regular routes use the Universal engine 43 | app.get('*', (req, res) => { 44 | res.render('index', { req }); 45 | }); 46 | 47 | // Start up the Node server 48 | app.listen(PORT, () => { 49 | console.log(`Node Express server listening on http://localhost:${PORT}`); 50 | }); 51 | -------------------------------------------------------------------------------- /demo/src/_variables.scss: -------------------------------------------------------------------------------- 1 | $icon-font-path: '../node_modules/bootstrap-sass/assets/fonts/bootstrap/'; 2 | $fa-font-path: '../node_modules/font-awesome/fonts/'; 3 | -------------------------------------------------------------------------------- /demo/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = [ 5 | { 6 | path: '', 7 | redirectTo: 'home', 8 | pathMatch: 'full' 9 | }, 10 | { 11 | path: 'getting-started', 12 | loadChildren: 'app/getting-started/getting-started.module#GettingStartedModule' 13 | } 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forRoot(routes)], 18 | exports: [RouterModule] 19 | }) 20 | export class AppRoutingModule { } 21 | -------------------------------------------------------------------------------- /demo/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | -------------------------------------------------------------------------------- /demo/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/demo/src/app/app.component.scss -------------------------------------------------------------------------------- /demo/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { Router } from '@angular/router' 3 | import { Component } from '@angular/core' 4 | import { TestBed, async } from '@angular/core/testing' 5 | import { AppComponent } from './app.component' 6 | import { FooterComponent } from './shared/footer/footer.component' 7 | 8 | import { 9 | RouterOutletStubComponent, 10 | RouterLinkStubDirective, 11 | } from '../testing/router-stubs' 12 | import { Observable, of } from 'rxjs' 13 | 14 | @Component({ selector: 'app-header', template: '' }) 15 | class HeaderStubComponent {} 16 | 17 | class RouterStub { 18 | events: Observable = of() 19 | } 20 | 21 | // @ts-ignore 22 | describe('AppComponent', () => { 23 | // @ts-ignore 24 | beforeEach(async(() => { 25 | TestBed.configureTestingModule({ 26 | declarations: [ 27 | AppComponent, 28 | HeaderStubComponent, 29 | FooterComponent, 30 | RouterOutletStubComponent, 31 | ], 32 | providers: [{ provide: Router, useClass: RouterStub }], 33 | }) 34 | })) 35 | // @ts-ignore 36 | it('should create', async(() => { 37 | const fixture = TestBed.createComponent(AppComponent) 38 | const app = fixture.debugElement.componentInstance 39 | // @ts-ignore 40 | expect(app).toBeTruthy() 41 | })) 42 | }) 43 | -------------------------------------------------------------------------------- /demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject, PLATFORM_ID } from '@angular/core'; 2 | import { Router, NavigationEnd, RouterEvent } from '@angular/router'; 3 | import { isPlatformBrowser } from '@angular/common'; 4 | import { filter } from 'rxjs/operators'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.scss'] 10 | }) 11 | export class AppComponent { 12 | 13 | constructor(private router: Router, @Inject(PLATFORM_ID) private platformId: Object) { 14 | 15 | this.router.events.pipe( 16 | filter((event:RouterEvent) => event instanceof NavigationEnd) 17 | ).subscribe(event => { 18 | if (isPlatformBrowser(this.platformId)) { 19 | window.scroll(0, 0); 20 | } 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /demo/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { BrowserModule } from '@angular/platform-browser'; 4 | import { TransferHttpCacheModule } from '@nguniversal/common'; 5 | 6 | import { AppRoutingModule } from './app-routing.module'; 7 | import { AppSharedModule } from './shared'; 8 | import { HomeModule } from './home/home.module'; 9 | import { AppComponent } from './app.component'; 10 | import { MaterialModule } from './material.module'; 11 | 12 | @NgModule({ 13 | declarations: [AppComponent], 14 | imports: [ 15 | // Add .withServerTransition() to support Universal rendering. 16 | // The application ID can be any identifier which is unique on 17 | // the page. 18 | BrowserModule.withServerTransition({ 19 | appId: 'mat-markdown-editor-demo-id', 20 | }), 21 | TransferHttpCacheModule, 22 | FormsModule, 23 | MaterialModule, 24 | AppRoutingModule, 25 | AppSharedModule, 26 | HomeModule, 27 | ], 28 | providers: [], 29 | bootstrap: [AppComponent], 30 | }) 31 | export class AppModule {} 32 | -------------------------------------------------------------------------------- /demo/src/app/app.server.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'; 3 | import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader'; 4 | 5 | import { AppModule } from './app.module'; 6 | import { AppComponent } from './app.component'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | // The AppServerModule should import your AppModule followed 11 | // by the ServerModule from @angular/platform-server. 12 | AppModule, 13 | ServerModule, 14 | ModuleMapLoaderModule, 15 | ServerTransferStateModule, 16 | ], 17 | // Since the bootstrapped component is not inherited from your 18 | // imported AppModule, it needs to be repeated here. 19 | bootstrap: [AppComponent], 20 | }) 21 | export class AppServerModule { } 22 | -------------------------------------------------------------------------------- /demo/src/app/getting-started/getting-started-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule } from '@angular/router'; 2 | import { NgModule } from '@angular/core'; 3 | import { GettingStartedComponent } from './getting-started.component'; 4 | 5 | @NgModule({ 6 | imports: [RouterModule.forChild([ 7 | { path: '', component: GettingStartedComponent } 8 | ])], 9 | exports: [RouterModule] 10 | }) 11 | export class GettingStartedRoutingModule {} -------------------------------------------------------------------------------- /demo/src/app/getting-started/getting-started.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Getting Started

4 |
5 |
6 | 7 |
8 |
9 | 10 | Put your content here. Typically instructions about how to install/use your library. 11 |
12 |
-------------------------------------------------------------------------------- /demo/src/app/getting-started/getting-started.component.scss: -------------------------------------------------------------------------------- 1 | .getting-started{ 2 | margin-top: 1.0rem; 3 | } 4 | -------------------------------------------------------------------------------- /demo/src/app/getting-started/getting-started.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { DebugElement } from '@angular/core'; 3 | 4 | import { GettingStartedComponent } from './getting-started.component'; 5 | 6 | describe('GettingStartedComponent', () => { 7 | let component: GettingStartedComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [GettingStartedComponent] 13 | }) 14 | .compileComponents() 15 | .then(() => { 16 | fixture = TestBed.createComponent(GettingStartedComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | })); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /demo/src/app/getting-started/getting-started.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Title } from '@angular/platform-browser'; 3 | 4 | 5 | @Component({ 6 | selector: 'app-getting-started', 7 | templateUrl: './getting-started.component.html', 8 | styleUrls: ['./getting-started.component.scss'] 9 | }) 10 | export class GettingStartedComponent implements OnInit { 11 | 12 | constructor(private titleService:Title) { } 13 | 14 | ngOnInit() { 15 | this.titleService.setTitle('Getting Started | mat-markdown-editor'); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/app/getting-started/getting-started.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { GettingStartedComponent } from './getting-started.component'; 4 | import { GettingStartedRoutingModule } from './getting-started-routing.module'; 5 | 6 | @NgModule({ 7 | imports: [ 8 | CommonModule, 9 | GettingStartedRoutingModule 10 | ], 11 | declarations: [GettingStartedComponent], 12 | }) 13 | export class GettingStartedModule { } 14 | -------------------------------------------------------------------------------- /demo/src/app/home/home-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule } from '@angular/router'; 2 | import { NgModule } from '@angular/core'; 3 | import { HomeComponent } from './home.component'; 4 | 5 | @NgModule({ 6 | imports: [RouterModule.forChild([ 7 | { path: 'home', component: HomeComponent } 8 | ])], 9 | exports: [RouterModule] 10 | }) 11 | export class HomeRoutingModule {} -------------------------------------------------------------------------------- /demo/src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 | 57 | 58 |
59 |
{{ form.status | json }}
60 |
61 |
62 | -------------------------------------------------------------------------------- /demo/src/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | .logo { 2 | width: 256px; 3 | height: 256px; 4 | margin-top: 1.4rem; 5 | } 6 | 7 | .home { 8 | margin-top: 1.0rem; 9 | } 10 | 11 | button.mat-button { 12 | margin-right: 10px; 13 | } 14 | -------------------------------------------------------------------------------- /demo/src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { DebugElement } from '@angular/core'; 3 | 4 | import { HomeComponent } from './home.component'; 5 | import { LibModule } from 'mat-markdown-editor'; 6 | 7 | describe('HomeComponent', () => { 8 | let component: HomeComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [ 14 | LibModule.forRoot(),], 15 | declarations: [HomeComponent] 16 | }) 17 | .compileComponents() 18 | .then(() => { 19 | fixture = TestBed.createComponent(HomeComponent); 20 | component = fixture.componentInstance; 21 | }); 22 | })); 23 | 24 | it('should create', () => { 25 | expect(component).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /demo/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Title } from '@angular/platform-browser'; 3 | import sdk from '@stackblitz/sdk'; 4 | import { MatMarkdownEditorOptions } from 'mat-markdown-editor'; 5 | 6 | @Component({ 7 | selector: 'app-home', 8 | templateUrl: './home.component.html', 9 | styleUrls: ['./home.component.scss'], 10 | }) 11 | export class HomeComponent implements OnInit { 12 | public options: MatMarkdownEditorOptions = { 13 | enablePreviewContentClick: false, 14 | resizable: true, 15 | showBorder: true, 16 | hideIcons: {}, 17 | hideToolbar: false, 18 | height: '500px', 19 | mode: 'editor', 20 | toolbarColor: 'primary', 21 | preRender: this.preRender, 22 | }; 23 | public content = '### Example Markdown'; 24 | 25 | constructor(private titleService: Title) {} 26 | 27 | ngOnInit() { 28 | this.titleService.setTitle('Home | mat-markdown-editor'); 29 | } 30 | 31 | editOnStackBlitz() { 32 | sdk.openGithubProject('michaeldoye/mat-markdown-editor/tree/master/demo'); 33 | } 34 | preRender(markDown: any) { 35 | return markDown; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/app/home/home.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { MatMarkdownEditorModule } from 'mat-markdown-editor'; 4 | import { FormsModule } from '@angular/forms'; 5 | 6 | import { HomeRoutingModule } from './home-routing.module'; 7 | import { HomeComponent } from './home.component'; 8 | import { MaterialModule } from '../material.module'; 9 | 10 | @NgModule({ 11 | imports: [ 12 | CommonModule, 13 | MatMarkdownEditorModule.forRoot(), 14 | HomeRoutingModule, 15 | FormsModule, 16 | MaterialModule, 17 | ], 18 | declarations: [HomeComponent], 19 | }) 20 | export class HomeModule {} 21 | -------------------------------------------------------------------------------- /demo/src/app/material.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { 3 | MatAutocompleteModule, 4 | MatButtonModule, 5 | MatButtonToggleModule, 6 | MatCardModule, 7 | MatCheckboxModule, 8 | MatChipsModule, 9 | MatDatepickerModule, 10 | MatDialogModule, 11 | MatExpansionModule, 12 | MatGridListModule, 13 | MatIconModule, 14 | MatInputModule, 15 | MatListModule, 16 | MatMenuModule, 17 | MatNativeDateModule, 18 | MatPaginatorModule, 19 | MatProgressBarModule, 20 | MatProgressSpinnerModule, 21 | MatRadioModule, 22 | MatRippleModule, 23 | MatSelectModule, 24 | MatSidenavModule, 25 | MatSliderModule, 26 | MatSlideToggleModule, 27 | MatSnackBarModule, 28 | MatSortModule, 29 | MatTableModule, 30 | MatTabsModule, 31 | MatToolbarModule, 32 | MatTooltipModule, 33 | MatStepperModule, 34 | MatFormFieldModule, 35 | } from '@angular/material'; 36 | 37 | @NgModule({ 38 | imports: [ 39 | MatAutocompleteModule, 40 | MatButtonModule, 41 | MatButtonToggleModule, 42 | MatCardModule, 43 | MatCheckboxModule, 44 | MatChipsModule, 45 | MatStepperModule, 46 | MatDatepickerModule, 47 | MatDialogModule, 48 | MatExpansionModule, 49 | MatGridListModule, 50 | MatIconModule, 51 | MatInputModule, 52 | MatListModule, 53 | MatMenuModule, 54 | MatNativeDateModule, 55 | MatPaginatorModule, 56 | MatProgressBarModule, 57 | MatProgressSpinnerModule, 58 | MatRadioModule, 59 | MatRippleModule, 60 | MatSelectModule, 61 | MatSidenavModule, 62 | MatSliderModule, 63 | MatSlideToggleModule, 64 | MatSnackBarModule, 65 | MatSortModule, 66 | MatTableModule, 67 | MatTabsModule, 68 | MatToolbarModule, 69 | MatTooltipModule, 70 | MatFormFieldModule, 71 | ], 72 | exports: [ 73 | MatAutocompleteModule, 74 | MatButtonModule, 75 | MatButtonToggleModule, 76 | MatCardModule, 77 | MatCheckboxModule, 78 | MatChipsModule, 79 | MatStepperModule, 80 | MatDatepickerModule, 81 | MatDialogModule, 82 | MatExpansionModule, 83 | MatGridListModule, 84 | MatIconModule, 85 | MatInputModule, 86 | MatListModule, 87 | MatMenuModule, 88 | MatNativeDateModule, 89 | MatPaginatorModule, 90 | MatProgressBarModule, 91 | MatProgressSpinnerModule, 92 | MatRadioModule, 93 | MatRippleModule, 94 | MatSelectModule, 95 | MatSidenavModule, 96 | MatSliderModule, 97 | MatSlideToggleModule, 98 | MatSnackBarModule, 99 | MatSortModule, 100 | MatTableModule, 101 | MatTabsModule, 102 | MatToolbarModule, 103 | MatTooltipModule, 104 | MatFormFieldModule, 105 | ], 106 | }) 107 | export class MaterialModule {} 108 | -------------------------------------------------------------------------------- /demo/src/app/shared/content-wrapper/content-wrapper.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ component }}

4 |
5 |
6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
-------------------------------------------------------------------------------- /demo/src/app/shared/content-wrapper/content-wrapper.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/demo/src/app/shared/content-wrapper/content-wrapper.component.scss -------------------------------------------------------------------------------- /demo/src/app/shared/content-wrapper/content-wrapper.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { DebugElement } from '@angular/core'; 3 | 4 | import { ContentWrapperComponent } from './content-wrapper.component'; 5 | 6 | describe('ContentWrapperComponent', () => { 7 | let component: ContentWrapperComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [ContentWrapperComponent] 13 | }) 14 | .compileComponents() 15 | .then(() => { 16 | fixture = TestBed.createComponent(ContentWrapperComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | })); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /demo/src/app/shared/content-wrapper/content-wrapper.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-content-wrapper', 5 | templateUrl: './content-wrapper.component.html', 6 | styleUrls: ['./content-wrapper.component.scss'] 7 | }) 8 | export class ContentWrapperComponent implements OnInit { 9 | 10 | @Input() 11 | public component: string; 12 | 13 | constructor() { } 14 | 15 | ngOnInit() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/app/shared/footer/footer.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/app/shared/footer/footer.component.scss: -------------------------------------------------------------------------------- 1 | footer { 2 | padding: 3rem 0; 3 | font-size: 85%; 4 | background-color: #f7f7f7; 5 | text-align: left; 6 | 7 | .heart{ 8 | color: #ff005d; 9 | } 10 | 11 | p { 12 | margin-bottom: 0; 13 | } 14 | 15 | a { 16 | font-weight: 500; 17 | color: #55595c; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /demo/src/app/shared/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { DebugElement } from '@angular/core'; 3 | 4 | import { FooterComponent } from './footer.component'; 5 | 6 | describe('FooterComponent', () => { 7 | let component: FooterComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [FooterComponent] 13 | }) 14 | .compileComponents() 15 | .then(() => { 16 | fixture = TestBed.createComponent(FooterComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | })); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /demo/src/app/shared/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.scss'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /demo/src/app/shared/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 | 36 |
37 | -------------------------------------------------------------------------------- /demo/src/app/shared/header/header.component.scss: -------------------------------------------------------------------------------- 1 | .navbar { 2 | background: hsla(0,0%,100%,.95) 3 | } 4 | -------------------------------------------------------------------------------- /demo/src/app/shared/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { By } from '@angular/platform-browser'; 3 | import { DebugElement } from '@angular/core'; 4 | 5 | import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; 6 | 7 | import { HeaderComponent } from './header.component'; 8 | import { RouterLinkStubDirective, RouterLinkActiveStubDirective } from './../../../testing/router-stubs'; 9 | 10 | describe('HeaderComponent', () => { 11 | let component: HeaderComponent; 12 | let fixture: ComponentFixture; 13 | 14 | let linkDes: DebugElement[]; 15 | let links: RouterLinkStubDirective[]; 16 | 17 | beforeEach(async(() => { 18 | TestBed.configureTestingModule({ 19 | imports: [ 20 | NgbCollapseModule.forRoot() 21 | ], 22 | declarations: [ 23 | HeaderComponent, 24 | RouterLinkStubDirective, 25 | RouterLinkActiveStubDirective 26 | ] 27 | }) 28 | .compileComponents() 29 | .then(() => { 30 | fixture = TestBed.createComponent(HeaderComponent); 31 | component = fixture.componentInstance; 32 | }); 33 | })); 34 | 35 | beforeEach(() => { 36 | // trigger initial data binding 37 | fixture.detectChanges(); 38 | 39 | // find DebugElements with an attached RouterLinkStubDirective 40 | linkDes = fixture.debugElement.queryAll(By.directive(RouterLinkStubDirective)); 41 | 42 | // get the attached link directive instances using the DebugElement injectors 43 | links = linkDes.map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective); 44 | }); 45 | 46 | it('should create', () => { 47 | expect(component).toBeTruthy(); 48 | }); 49 | 50 | it('can get RouterLinks from template', () => { 51 | expect(links.length).toBe(2); // should have 2 links 52 | expect(links[0].linkParams).toBe('/home'); // 1st link should go to Home 53 | expect(links[1].linkParams).toBe('/getting-started'); // 2nd link should go to GettingStarted 54 | }); 55 | 56 | it('can click Home link in template', () => { 57 | const homeLinkDe = linkDes[0]; 58 | const homeLink = links[0]; 59 | 60 | expect(homeLink.navigatedTo).toBeNull(); // link should not have navigated yet 61 | 62 | homeLinkDe.triggerEventHandler('click', null); 63 | fixture.detectChanges(); 64 | 65 | expect(homeLink.navigatedTo).toBe('/home'); 66 | }); 67 | 68 | it('can click GettingStarted link in template', () => { 69 | const gettingStartedLinkDe = linkDes[1]; 70 | const gettingStartedLink = links[1]; 71 | 72 | expect(gettingStartedLink.navigatedTo).toBeNull(); // link should not have navigated yet 73 | 74 | gettingStartedLinkDe.triggerEventHandler('click', null); 75 | fixture.detectChanges(); 76 | 77 | expect(gettingStartedLink.navigatedTo).toBe('/getting-started'); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /demo/src/app/shared/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-header', 5 | templateUrl: './header.component.html', 6 | styleUrls: ['./header.component.scss'] 7 | }) 8 | export class HeaderComponent implements OnInit { 9 | 10 | navbarCollapsed = true; 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/app/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './shared.module'; -------------------------------------------------------------------------------- /demo/src/app/shared/shared.module.ts: -------------------------------------------------------------------------------- 1 | import { RouterModule } from '@angular/router'; 2 | import { NgModule } from '@angular/core'; 3 | import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | import { HeaderComponent } from './header/header.component'; 6 | import { FooterComponent } from './footer/footer.component'; 7 | import { ContentWrapperComponent } from './content-wrapper/content-wrapper.component'; 8 | 9 | @NgModule({ 10 | imports: [RouterModule, NgbCollapseModule.forRoot() ], 11 | exports: [HeaderComponent, FooterComponent, ContentWrapperComponent], 12 | declarations: [HeaderComponent, FooterComponent, ContentWrapperComponent], 13 | providers: [], 14 | }) 15 | export class AppSharedModule { } 16 | -------------------------------------------------------------------------------- /demo/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/demo/src/assets/.gitkeep -------------------------------------------------------------------------------- /demo/src/assets/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/demo/src/assets/.npmignore -------------------------------------------------------------------------------- /demo/src/assets/forms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/demo/src/assets/forms.png -------------------------------------------------------------------------------- /demo/src/assets/forms.svg: -------------------------------------------------------------------------------- 1 | forms -------------------------------------------------------------------------------- /demo/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /demo/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed 5 | > 0.5% 6 | last 2 versions 7 | Firefox ESR 8 | not dead 9 | # IE 9-11 -------------------------------------------------------------------------------- /demo/src/environments/environment.hmr.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | hmr: true 4 | }; 5 | -------------------------------------------------------------------------------- /demo/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | hmr: false 4 | }; 5 | -------------------------------------------------------------------------------- /demo/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | hmr: false 9 | }; 10 | -------------------------------------------------------------------------------- /demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/demo/src/favicon.ico -------------------------------------------------------------------------------- /demo/src/highlight.js.scss: -------------------------------------------------------------------------------- 1 | /* Dracula Theme v1.2.5 2 | * 3 | * https://github.com/dracula/highlightjs 4 | * 5 | * Copyright 2016-present, All rights reserved 6 | * 7 | * Code licensed under the MIT license 8 | * 9 | * @author Denis Ciccale 10 | * @author Zeno Rocha 11 | */ 12 | 13 | .hljs { 14 | display: block; 15 | overflow-x: auto; 16 | padding: 0.5em; 17 | background: #282a36; 18 | } 19 | 20 | .hljs-built_in, 21 | .hljs-selector-tag, 22 | .hljs-section, 23 | .hljs-link { 24 | color: #8be9fd; 25 | } 26 | 27 | .hljs-keyword { 28 | color: #ff79c6; 29 | } 30 | 31 | .hljs, 32 | .hljs-subst { 33 | color: #f8f8f2; 34 | } 35 | 36 | .hljs-title { 37 | color: #50fa7b; 38 | } 39 | 40 | .hljs-string, 41 | .hljs-meta, 42 | .hljs-name, 43 | .hljs-type, 44 | .hljs-attribute, 45 | .hljs-symbol, 46 | .hljs-bullet, 47 | .hljs-addition, 48 | .hljs-variable, 49 | .hljs-template-tag, 50 | .hljs-template-variable { 51 | color: #f1fa8c; 52 | } 53 | 54 | .hljs-comment, 55 | .hljs-quote, 56 | .hljs-deletion { 57 | color: #6272a4; 58 | } 59 | 60 | .hljs-keyword, 61 | .hljs-selector-tag, 62 | .hljs-literal, 63 | .hljs-title, 64 | .hljs-section, 65 | .hljs-doctag, 66 | .hljs-type, 67 | .hljs-name, 68 | .hljs-strong { 69 | font-weight: bold; 70 | } 71 | 72 | .hljs-literal, 73 | .hljs-number { 74 | color: #bd93f9; 75 | } 76 | 77 | .hljs-emphasis { 78 | font-style: italic; 79 | } -------------------------------------------------------------------------------- /demo/src/hmr.ts: -------------------------------------------------------------------------------- 1 | import { NgModuleRef, ApplicationRef } from '@angular/core'; 2 | import { createNewHosts } from '@angularclass/hmr'; 3 | 4 | export const hmrBootstrap = (module: any, bootstrap: () => Promise>) => { 5 | let ngModule: NgModuleRef; 6 | module.hot.accept(); 7 | bootstrap().then(mod => ngModule = mod); 8 | module.hot.dispose(() => { 9 | const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); 10 | const elements = appRef.components.map(c => c.location.nativeElement); 11 | const makeVisible = createNewHosts(elements); 12 | ngModule.destroy(); 13 | makeVisible(); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | mat-markdown-editor 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | 34 | 38 | 39 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Loading... 61 | 62 | 63 | -------------------------------------------------------------------------------- /demo/src/jestGlobalMocks.ts: -------------------------------------------------------------------------------- 1 | global['CSS'] = null; 2 | 3 | const mock = () => { 4 | let storage = {}; 5 | return { 6 | getItem: key => key in storage ? storage[key] : null, 7 | setItem: (key, value) => storage[key] = value || '', 8 | removeItem: key => delete storage[key], 9 | clear: () => storage = {}, 10 | }; 11 | }; 12 | 13 | Object.defineProperty(window, 'localStorage', {value: mock()}); 14 | Object.defineProperty(window, 'sessionStorage', {value: mock()}); 15 | Object.defineProperty(document, 'doctype', { 16 | value: '' 17 | }); 18 | Object.defineProperty(window, 'getComputedStyle', { 19 | value: () => { 20 | return { 21 | display: 'none', 22 | appearance: ['-webkit-appearance'] 23 | }; 24 | } 25 | }); 26 | /** 27 | * ISSUE: https://github.com/angular/material2/issues/7101 28 | * Workaround for JSDOM missing transform property 29 | */ 30 | Object.defineProperty(document.body.style, 'transform', { 31 | value: () => { 32 | return { 33 | enumerable: true, 34 | configurable: true, 35 | }; 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /demo/src/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'), 20 | reports: ['html', 'lcovonly'], 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 | }); 31 | }; -------------------------------------------------------------------------------- /demo/src/main.server.ts: -------------------------------------------------------------------------------- 1 | export { AppServerModule } from './app/app.server.module'; 2 | -------------------------------------------------------------------------------- /demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | import { hmrBootstrap } from './hmr'; 8 | 9 | import 'hammerjs'; 10 | 11 | if (environment.production) { 12 | enableProdMode(); 13 | } 14 | 15 | const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule); 16 | 17 | if (environment.hmr) { 18 | if (module[ 'hot' ]) { 19 | hmrBootstrap(module, bootstrap); 20 | } else { 21 | console.error('HMR is not enabled for webpack-dev-server!'); 22 | console.log('Are you using the --hmr flag for ng serve?'); 23 | } 24 | } else { 25 | bootstrap().catch(err => console.log(err)); 26 | } 27 | -------------------------------------------------------------------------------- /demo/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/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Web Animations `@angular/platform-browser/animations` 51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 53 | **/ 54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 55 | 56 | /** 57 | * By default, zone.js will patch all possible macroTask and DomEvents 58 | * user can disable parts of macroTask/DomEvents patch by setting following flags 59 | */ 60 | 61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 64 | 65 | /* 66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 68 | */ 69 | // (window as any).__Zone_enable_cross_context_check = true; 70 | 71 | /*************************************************************************************************** 72 | * Zone JS is required by default for Angular itself. 73 | */ 74 | import 'zone.js/dist/zone'; // Included with Angular CLI. 75 | 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | -------------------------------------------------------------------------------- /demo/src/setupJest.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular'; 2 | import './jestGlobalMocks'; 3 | -------------------------------------------------------------------------------- /demo/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | @import '_variables'; 4 | @import '~bootstrap/scss/bootstrap'; 5 | @import '~font-awesome/scss/font-awesome'; 6 | @import 'highlight.js'; 7 | @import "~@angular/material/prebuilt-themes/indigo-pink.css"; 8 | 9 | .jumbotron { 10 | //margin-top: 3.4rem; 11 | margin-bottom: 0rem; 12 | h1 { 13 | font-size: 2.5rem; 14 | margin-bottom: 1.4rem; 15 | } 16 | p { 17 | font-size: 1.2rem; 18 | } 19 | 20 | .btn{ 21 | margin: .5rem; 22 | } 23 | 24 | .buttons a{ 25 | margin: 0.2rem; 26 | } 27 | 28 | } 29 | 30 | @include media-breakpoint-up(sm) { 31 | .jumbotron { 32 | // margin-top: 3.4rem; 33 | margin-bottom: 0rem; 34 | h1 { 35 | font-size: 3.6rem; 36 | margin-bottom: 1.8rem; 37 | } 38 | p { 39 | font-size: 1.4rem; 40 | } 41 | .buttons a{ 42 | margin: 0.3rem; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /demo/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 | -------------------------------------------------------------------------------- /demo/src/testing/index.ts: -------------------------------------------------------------------------------- 1 | export * from './router-stubs'; -------------------------------------------------------------------------------- /demo/src/testing/router-stubs.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Component, Directive, Injectable, Input } from '@angular/core'; 3 | import { NavigationExtras } from '@angular/router'; 4 | // Only implements params and part of snapshot.params 5 | import { BehaviorSubject } from 'rxjs'; 6 | 7 | // export for convenience. 8 | export { ActivatedRoute, Router, RouterLink, RouterOutlet } from '@angular/router'; 9 | 10 | 11 | @Directive({ 12 | selector: '[routerLink]', 13 | host: { 14 | '(click)': 'onClick()' 15 | } 16 | }) 17 | export class RouterLinkStubDirective { 18 | @Input('routerLink') linkParams: any; 19 | navigatedTo: any = null; 20 | 21 | onClick() { 22 | this.navigatedTo = this.linkParams; 23 | } 24 | } 25 | 26 | @Directive({ 27 | selector: '[routerLinkActive]' 28 | }) 29 | export class RouterLinkActiveStubDirective { 30 | @Input('routerLinkActive') linkParams: any; 31 | } 32 | 33 | @Component({ selector: 'router-outlet', template: '' }) 34 | export class RouterOutletStubComponent { } 35 | 36 | @Injectable() 37 | export class RouterStub { 38 | navigate(commands: any[], extras?: NavigationExtras) { } 39 | } 40 | 41 | 42 | @Injectable() 43 | export class ActivatedRouteStub { 44 | 45 | // ActivatedRoute.params is Observable 46 | private subject = new BehaviorSubject(this.testParams); 47 | params = this.subject.asObservable(); 48 | 49 | // Test parameters 50 | private _testParams: {}; 51 | get testParams() { return this._testParams; } 52 | set testParams(params: {}) { 53 | this._testParams = params; 54 | this.subject.next(params); 55 | } 56 | 57 | // ActivatedRoute.snapshot.params 58 | get snapshot() { 59 | return { params: this.testParams }; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /demo/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [], 8 | "paths": { 9 | "@angular/*": ["../node_modules/@angular/*"] 10 | } 11 | }, 12 | "exclude": [ 13 | "testing/*", 14 | "test.ts", 15 | "setupJest.ts", 16 | "jestGlobalMocks.ts", 17 | "**/*.spec.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/tsconfig.server.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "testing/*", 11 | "test.ts", 12 | "setupJest.ts", 13 | "jestGlobalMocks.ts", 14 | "**/*.spec.ts" 15 | ], 16 | "angularCompilerOptions": { 17 | "entryModule": "app/app.server.module#AppServerModule" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts", 15 | "polyfills.ts" 16 | ], 17 | "include": [ 18 | "**/*.spec.ts", 19 | "**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /demo/static.paths.ts: -------------------------------------------------------------------------------- 1 | export const ROUTES = [ 2 | '/', 3 | '/getting-started/', 4 | ]; 5 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 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-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-shadowed-variable": true, 69 | "no-string-literal": false, 70 | "no-string-throw": true, 71 | "no-switch-case-fall-through": true, 72 | "no-trailing-whitespace": true, 73 | "no-unnecessary-initializer": true, 74 | "no-unused-expression": true, 75 | "no-use-before-declare": true, 76 | "no-var-keyword": true, 77 | "object-literal-sort-keys": false, 78 | "one-line": [ 79 | true, 80 | "check-open-brace", 81 | "check-catch", 82 | "check-else", 83 | "check-whitespace" 84 | ], 85 | "prefer-const": true, 86 | "quotemark": [ 87 | true, 88 | "single" 89 | ], 90 | "radix": true, 91 | "semicolon": [ 92 | true, 93 | "always" 94 | ], 95 | "triple-equals": [ 96 | true, 97 | "allow-null-check" 98 | ], 99 | "typedef-whitespace": [ 100 | true, 101 | { 102 | "call-signature": "nospace", 103 | "index-signature": "nospace", 104 | "parameter": "nospace", 105 | "property-declaration": "nospace", 106 | "variable-declaration": "nospace" 107 | } 108 | ], 109 | "unified-signatures": true, 110 | "variable-name": false, 111 | "whitespace": [ 112 | true, 113 | "check-branch", 114 | "check-decl", 115 | "check-operator", 116 | "check-separator", 117 | "check-type" 118 | ], 119 | "no-output-on-prefix": true, 120 | "use-input-property-decorator": true, 121 | "use-output-property-decorator": true, 122 | "use-host-property-decorator": true, 123 | "no-input-rename": true, 124 | "no-output-rename": true, 125 | "use-life-cycle-interface": true, 126 | "use-pipe-transform-interface": true, 127 | "component-class-suffix": true, 128 | "directive-class-suffix": true 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /demo/webpack.server.config.js: -------------------------------------------------------------------------------- 1 | // Work around for https://github.com/angular/angular-cli/issues/7200 2 | 3 | const path = require('path'); 4 | const webpack = require('webpack'); 5 | 6 | module.exports = { 7 | mode: 'none', 8 | entry: { 9 | // This is our Express server for Dynamic universal 10 | server: './server.ts', 11 | // This is an example of Static prerendering (generative) 12 | prerender: './prerender.ts' 13 | }, 14 | target: 'node', 15 | resolve: { extensions: ['.ts', '.js'] }, 16 | // Make sure we include all node_modules etc 17 | externals: [/node_modules/], 18 | output: { 19 | // Puts the output at the root of the dist folder 20 | path: path.join(__dirname, 'dist'), 21 | filename: '[name].js' 22 | }, 23 | module: { 24 | rules: [ 25 | { test: /\.ts$/, loader: 'ts-loader' } 26 | ] 27 | }, 28 | plugins: [ 29 | new webpack.ContextReplacementPlugin( 30 | // fixes WARNING Critical dependency: the request of a dependency is an expression 31 | /(.+)?angular(\\|\/)core(.+)?/, 32 | path.join(__dirname, 'src'), // location of your src 33 | {} // a map of your routes 34 | ), 35 | new webpack.ContextReplacementPlugin( 36 | // fixes WARNING Critical dependency: the request of a dependency is an expression 37 | /(.+)?express(\\|\/)(.+)?/, 38 | path.join(__dirname, 'src'), 39 | {} 40 | ) 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /greenkeeper.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": { 3 | "default": { 4 | "packages": [ 5 | "demo/package.json", 6 | "package.json" 7 | ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const del = require('del'); 3 | const gulp = require('gulp'); 4 | const acolors = require('ansi-colors'); 5 | const fancyLog = require('fancy-log'); 6 | const helpers = require('./config/helpers'); 7 | 8 | /** TSLint checker */ 9 | const tslint = require('tslint'); 10 | const gulpTslint = require('gulp-tslint'); 11 | 12 | /** External command runner */ 13 | const process = require('process'); 14 | const execSync = require('child_process').execSync; 15 | 16 | /** File Access */ 17 | const fs = require('fs'); 18 | const path = require('path'); 19 | const gulpFile = require('gulp-file'); 20 | 21 | /** To properly handle pipes on error */ 22 | const pump = require('pump'); 23 | 24 | /** Testing/Code Coverage */ 25 | const gulpCoveralls = require('gulp-coveralls'); 26 | const jestCli = require('jest-cli'); 27 | 28 | /** To order tasks */ 29 | const runSequence = require('run-sequence'); 30 | 31 | /** To compile & bundle the library with Angular & Rollup */ 32 | const ngc = (args) => new Promise((resolve, reject)=>{// Promisify version of the ngc compiler 33 | let exitCode = require('@angular/compiler-cli/src/main').main(args); 34 | resolve(exitCode); 35 | }); 36 | const rollup = require('rollup'); 37 | const rollupUglify = require('rollup-plugin-uglify'); 38 | const rollupSourcemaps = require('rollup-plugin-sourcemaps'); 39 | const rollupNodeResolve = require('rollup-plugin-node-resolve'); 40 | const rollupCommonjs = require('rollup-plugin-commonjs'); 41 | 42 | /** To load templates and styles in Angular components */ 43 | const gulpInlineNgTemplate = require('gulp-inline-ng2-template'); 44 | 45 | /** Sass style */ 46 | const sass = require('node-sass'); 47 | const cssnano = require('cssnano'); 48 | const postcss = require('postcss'); 49 | const autoprefixer = require('autoprefixer'); 50 | const stripInlineComments = require('postcss-strip-inline-comments'); 51 | 52 | //Bumping, Releasing tools 53 | const gulpGit = require('gulp-git'); 54 | const gulpBump = require('gulp-bump'); 55 | const gulpConventionalChangelog = require('gulp-conventional-changelog'); 56 | const conventionalGithubReleaser = require('conventional-github-releaser'); 57 | 58 | /** To load gulp tasks from multiple files */ 59 | const gulpHub = require('gulp-hub'); 60 | 61 | /** Documentation generation tools **/ 62 | const gulpCompodoc = require('@compodoc/gulp-compodoc'); 63 | 64 | const yargs = require('yargs'); 65 | const argv = yargs 66 | .option('version', { 67 | alias: 'v', 68 | describe: 'Enter Version to bump to', 69 | choices: ['patch', 'minor', 'major'], 70 | type: "string" 71 | }) 72 | .option('ghToken', { 73 | alias: 'gh', 74 | describe: 'Enter Github Token for releasing', 75 | type: "string" 76 | }) 77 | .version(false) // disable default --version from yargs( since v9.0.0) 78 | .argv; 79 | 80 | const config = { 81 | libraryName: 'mat-markdown-editor', 82 | unscopedLibraryName: 'mat-markdown-editor', 83 | allSrc: 'src/**/*', 84 | allTs: 'src/**/!(*.spec).ts', 85 | allSass: 'src/**/*.+(scss|sass)', 86 | allHtml: 'src/**/*.html', 87 | demoDir: 'demo/', 88 | buildDir: 'tmp/', 89 | outputDir: 'dist/', 90 | outputDemoDir: 'demo/dist/browser/', 91 | coverageDir: 'coverage/' 92 | }; 93 | 94 | const rootFolder = path.join(__dirname); 95 | const buildFolder = path.join(rootFolder, `${config.buildDir}`); 96 | const distFolder = path.join(rootFolder, `${config.outputDir}`); 97 | const es5OutputFolder = path.join(buildFolder, 'lib-es5'); 98 | const es2015OutputFolder = path.join(buildFolder, 'lib-es2015'); 99 | 100 | //Helper functions 101 | 102 | const getPackageJsonVersion = () => { 103 | // We parse the json file instead of using require because require caches 104 | // multiple calls so the version number won't be updated 105 | return JSON.parse(fs.readFileSync('./package.json', 'utf8')).version; 106 | }; 107 | 108 | const isOK = condition => { 109 | if(condition === undefined){ 110 | return acolors.yellow('[SKIPPED]'); 111 | } 112 | return condition ? acolors.green('[OK]') : acolors.red('[KO]'); 113 | }; 114 | 115 | const readyToRelease = () => { 116 | let isTravisPassing = /build #\d+ passed/.test(execSync('npm run check-travis').toString().trim()); 117 | let onMasterBranch = execSync('git symbolic-ref --short -q HEAD').toString().trim() === 'master'; 118 | let canBump = !!argv.version; 119 | let canGhRelease = argv.ghToken || process.env.CONVENTIONAL_GITHUB_RELEASER_TOKEN; 120 | let canNpmPublish = !!execSync('npm whoami').toString().trim() && execSync('npm config get registry').toString().trim() === 'https://registry.npmjs.org/'; 121 | 122 | fancyLog(`[travis-ci] Travis build on 'master' branch is passing............................................${isOK(isTravisPassing)}`); 123 | fancyLog(`[git-branch] User is currently on 'master' branch..................................................${isOK(onMasterBranch)}`); 124 | fancyLog(`[npm-publish] User is currently logged in to NPM Registry...........................................${isOK(canNpmPublish)}`); 125 | fancyLog(`[bump-version] Option '--version' provided, with value : 'major', 'minor' or 'patch'.................${isOK(canBump)}`); 126 | fancyLog(`[github-release] Option '--ghToken' provided or 'CONVENTIONAL_GITHUB_RELEASER_TOKEN' variable set......${isOK(canGhRelease)}`); 127 | 128 | return isTravisPassing && onMasterBranch && canBump && canGhRelease && canNpmPublish; 129 | }; 130 | 131 | const execCmd = (name, args, opts, ...subFolders) => { 132 | const cmd = helpers.root(subFolders, helpers.binPath(`${name}`)); 133 | return helpers.execp(`${cmd} ${args}`, opts) 134 | .catch(e => { 135 | fancyLog(acolors.red(`${name} command failed. See below for errors.\n`)); 136 | fancyLog(acolors.red(e)); 137 | process.exit(1); 138 | }); 139 | }; 140 | 141 | const execExternalCmd = (name, args, opts) => { 142 | return helpers.execp(`${name} ${args}`, opts) 143 | .catch(e => { 144 | fancyLog(acolors.red(`${name} command failed. See below for errors.\n`)); 145 | fancyLog(acolors.red(e)); 146 | process.exit(1); 147 | }); 148 | }; 149 | 150 | 151 | // Compile Sass to css 152 | const styleProcessor = (stylePath, ext, styleFile, callback) => { 153 | /** 154 | * Remove comments, autoprefixer, Minifier 155 | */ 156 | const processors = [ 157 | stripInlineComments, 158 | autoprefixer, 159 | cssnano 160 | ]; 161 | 162 | const postProcessCss = css => { 163 | postcss(processors).process(css, {from: undefined}).then(result => { 164 | result.warnings().forEach(function (warn) { 165 | fancyLog.warn(warn.toString()); 166 | }); 167 | styleFile = result.css; 168 | callback(null, styleFile); 169 | }); 170 | }; 171 | 172 | if (/\.(scss|sass)$/.test(ext[0])) { 173 | let sassObj = sass.renderSync({ file: stylePath }); 174 | if (sassObj && sassObj['css']) { 175 | let css = sassObj.css.toString('utf8'); 176 | postProcessCss(css); 177 | } 178 | } else if (/\.css$/.test(ext[0])) { 179 | postProcessCss(styleFile); 180 | } 181 | }; 182 | 183 | ///////////////////////////////////////////////////////////////////////////// 184 | // Cleaning Tasks 185 | ///////////////////////////////////////////////////////////////////////////// 186 | gulp.task('clean:dist', () => { 187 | return del(config.outputDir); 188 | }); 189 | 190 | gulp.task('clean:build', () => { 191 | return del(config.buildDir); 192 | }); 193 | 194 | gulp.task('clean:coverage', () => { 195 | return del(config.coverageDir); 196 | }); 197 | 198 | gulp.task('clean:doc', () => { 199 | return del(`${config.outputDir}/doc`); 200 | }); 201 | 202 | gulp.task('clean', ['clean:dist', 'clean:coverage', 'clean:build']); 203 | 204 | ///////////////////////////////////////////////////////////////////////////// 205 | // Compilation Tasks 206 | ///////////////////////////////////////////////////////////////////////////// 207 | 208 | gulp.task('lint', (cb) => { 209 | pump([ 210 | gulp.src(config.allTs), 211 | gulpTslint( 212 | { 213 | program: tslint.Linter.createProgram('./tsconfig.json'), 214 | formatter: 'verbose', 215 | configuration: 'tslint.json' 216 | }), 217 | gulpTslint.report() 218 | ], cb); 219 | }); 220 | 221 | // Inline Styles and Templates into components 222 | gulp.task('inline-templates', (cb) => { 223 | const options = { 224 | base: `${config.buildDir}`, 225 | styleProcessor: styleProcessor, 226 | useRelativePaths: true 227 | }; 228 | pump( 229 | [ 230 | gulp.src(config.allTs), 231 | gulpInlineNgTemplate(options), 232 | gulp.dest(`${config.buildDir}`) 233 | ], 234 | cb); 235 | }); 236 | 237 | // Prepare files for compilation 238 | gulp.task('pre-compile', (cb) => { 239 | pump([ 240 | gulp.src([config.allSrc]), 241 | gulp.dest(config.buildDir) 242 | ], cb); 243 | }); 244 | 245 | gulp.task('ng-compile',() => { 246 | return Promise.resolve() 247 | // Compile to ES5. 248 | .then(() => ngc(['--project',`${buildFolder}/tsconfig.lib.es5.json`]) 249 | .then(exitCode => exitCode === 0 ? Promise.resolve() : Promise.reject()) 250 | .then(() => fancyLog('ES5 compilation succeeded.')) 251 | ) 252 | // Compile to ES2015. 253 | .then(() => ngc(['--project',`${buildFolder}/tsconfig.lib.json`]) 254 | .then(exitCode => exitCode === 0 ? Promise.resolve() : Promise.reject()) 255 | .then(() => fancyLog('ES2015 compilation succeeded.')) 256 | ) 257 | .catch(e => { 258 | fancyLog(acolors.red('ng-compilation failed. See below for errors.\n')); 259 | fancyLog(acolors.red(e)); 260 | process.exit(1); 261 | }); 262 | }); 263 | 264 | // Lint, Prepare Build, , Sass to css, Inline templates & Styles and Ng-Compile 265 | gulp.task('compile', (cb) => { 266 | runSequence('lint', 'pre-compile', 'inline-templates', 'ng-compile', cb); 267 | }); 268 | 269 | // Build the 'dist' folder (without publishing it to NPM) 270 | gulp.task('build', ['clean'], (cb) => { 271 | runSequence('compile', 'test', 'npm-package', 'rollup-bundle', cb); 272 | }); 273 | 274 | // Same as 'build' but without cleaning temp folders (to avoid breaking demo app, if currently being served) 275 | gulp.task('build-watch', (cb) => { 276 | runSequence('compile', 'test', 'npm-package', 'rollup-bundle', cb); 277 | }); 278 | 279 | // Same as 'build-watch' but without running tests 280 | gulp.task('build-watch-no-tests', (cb) => { 281 | runSequence('compile', 'npm-package', 'rollup-bundle', cb); 282 | }); 283 | 284 | // Watch changes on (*.ts, *.html, *.sass) and Re-build library 285 | gulp.task('build:watch', ['build-watch'], () => { 286 | gulp.watch([config.allTs, config.allHtml, config.allSass], ['build-watch']); 287 | }); 288 | 289 | // Watch changes on (*.ts, *.html, *.sass) and Re-build library (without running tests) 290 | gulp.task('build:watch-fast', ['build-watch-no-tests'], () => { 291 | gulp.watch([config.allTs, config.allHtml, config.allSass], ['build-watch-no-tests']); 292 | }); 293 | 294 | 295 | ///////////////////////////////////////////////////////////////////////////// 296 | // Packaging Tasks 297 | ///////////////////////////////////////////////////////////////////////////// 298 | 299 | // Prepare 'dist' folder for publication to NPM 300 | gulp.task('npm-package', (cb) => { 301 | let pkgJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')); 302 | let targetPkgJson = {}; 303 | let fieldsToCopy = ['version', 'description', 'keywords', 'author', 'repository', 'license', 'bugs', 'homepage']; 304 | 305 | targetPkgJson['name'] = config.libraryName; 306 | 307 | //only copy needed properties from project's package json 308 | fieldsToCopy.forEach((field) => { targetPkgJson[field] = pkgJson[field]; }); 309 | 310 | targetPkgJson['main'] = `./bundles/${config.unscopedLibraryName}.umd.js`; 311 | targetPkgJson['module'] = `./esm5/${config.unscopedLibraryName}.es5.js`; 312 | targetPkgJson['es2015'] = `./esm2015/${config.unscopedLibraryName}.js`; 313 | targetPkgJson['typings'] = `./${config.unscopedLibraryName}.d.ts`; 314 | 315 | // defines project's dependencies as 'peerDependencies' for final users 316 | targetPkgJson.peerDependencies = {}; 317 | Object.keys(pkgJson.dependencies).forEach((dependency) => { 318 | // versions are defined as '^' by default, but you can customize it by editing "dependenciesRange" in '.yo-rc.json' file 319 | targetPkgJson.peerDependencies[dependency] = `^${pkgJson.dependencies[dependency].replace(/[\^~><=]/,'')}`; 320 | }); 321 | 322 | // copy the needed additional files in the 'dist' folder 323 | pump( 324 | [ 325 | gulp.src(['README.md', 'LICENSE', 'CHANGELOG.md', 326 | `${config.buildDir}/lib-es5/**/*.d.ts`, 327 | `${config.buildDir}/lib-es5/**/*.metadata.json`]), 328 | gulpFile('package.json', JSON.stringify(targetPkgJson, null, 2)), 329 | gulp.dest(config.outputDir) 330 | ], cb); 331 | }); 332 | 333 | // Bundles the library as UMD/FESM bundles using RollupJS 334 | gulp.task('rollup-bundle', (cb) => { 335 | return Promise.resolve() 336 | // Bundle lib. 337 | .then(() => { 338 | // Base configuration. 339 | const es5Input = path.join(es5OutputFolder, `${config.unscopedLibraryName}.js`); 340 | const es2015Input = path.join(es2015OutputFolder, `${config.unscopedLibraryName}.js`); 341 | const globals = { 342 | // The key here is library name, and the value is the name of the global variable name 343 | // the window object. 344 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#globals for more. 345 | 346 | // Angular dependencies 347 | '@angular/core': 'ng.core', 348 | '@angular/common': 'ng.common', 349 | 350 | // Rxjs dependencies 351 | 'rxjs/Subject': 'Rx', 352 | 'rxjs/Observable': 'Rx', 353 | 'rxjs/add/observable/fromEvent': 'Rx.Observable', 354 | 'rxjs/add/observable/forkJoin': 'Rx.Observable', 355 | 'rxjs/add/observable/of': 'Rx.Observable', 356 | 'rxjs/add/observable/merge': 'Rx.Observable', 357 | 'rxjs/add/observable/throw': 'Rx.Observable', 358 | 'rxjs/add/operator/auditTime': 'Rx.Observable.prototype', 359 | 'rxjs/add/operator/toPromise': 'Rx.Observable.prototype', 360 | 'rxjs/add/operator/map': 'Rx.Observable.prototype', 361 | 'rxjs/add/operator/filter': 'Rx.Observable.prototype', 362 | 'rxjs/add/operator/do': 'Rx.Observable.prototype', 363 | 'rxjs/add/operator/share': 'Rx.Observable.prototype', 364 | 'rxjs/add/operator/finally': 'Rx.Observable.prototype', 365 | 'rxjs/add/operator/catch': 'Rx.Observable.prototype', 366 | 'rxjs/add/observable/empty': 'Rx.Observable.prototype', 367 | 'rxjs/add/operator/first': 'Rx.Observable.prototype', 368 | 'rxjs/add/operator/startWith': 'Rx.Observable.prototype', 369 | 'rxjs/add/operator/switchMap': 'Rx.Observable.prototype', 370 | 371 | // ATTENTION: 372 | // Add any other dependency or peer dependency of your library here 373 | // This is required for UMD bundle users. 374 | // See https://github.com/tinesoft/generator-ngx-library/TROUBLESHOUTING.md if trouble 375 | 376 | 377 | }; 378 | const rollupBaseConfig = { 379 | output:{ 380 | name: _.camelCase(config.libraryName), 381 | sourcemap: true, 382 | globals: globals 383 | }, 384 | // List of dependencies 385 | // See https://github.com/rollup/rollup/wiki/JavaScript-API#external for more. 386 | external: Object.keys(globals), 387 | plugins: [ 388 | rollupCommonjs({ 389 | include: ['node_modules/rxjs/**'] 390 | }), 391 | rollupSourcemaps(), 392 | rollupNodeResolve({ 393 | jsnext: true, 394 | module: true, 395 | jail: distFolder, // to use final 'package.json' from 'dist/' 396 | }) 397 | ] 398 | }; 399 | 400 | // UMD bundle. 401 | const umdConfig = _.merge({}, rollupBaseConfig, { 402 | input: es5Input, 403 | output: { 404 | format: 'umd', 405 | file: path.join(distFolder, `bundles`, `${config.unscopedLibraryName}.umd.js`) 406 | } 407 | }); 408 | 409 | // Minified UMD bundle. 410 | const minifiedUmdConfig = _.merge({}, rollupBaseConfig, { 411 | input: es5Input, 412 | output: { 413 | format: 'umd', 414 | file: path.join(distFolder, `bundles`, `${config.unscopedLibraryName}.umd.min.js`), 415 | }, 416 | plugins: rollupBaseConfig.plugins.concat([rollupUglify({})]) 417 | }); 418 | 419 | // ESM+ES5 flat module bundle. 420 | const fesm5config = _.merge({}, rollupBaseConfig, { 421 | input: es5Input, 422 | output: { 423 | format: 'es', 424 | file: path.join(distFolder, 'esm5', `${config.unscopedLibraryName}.es5.js`), 425 | } 426 | }); 427 | 428 | // ESM+ES2015 flat module bundle. 429 | const fesm2015config = _.merge({}, rollupBaseConfig, { 430 | input: es2015Input, 431 | output: { 432 | format: 'es', 433 | file: path.join(distFolder, 'esm2015', `${config.unscopedLibraryName}.js`), 434 | } 435 | }); 436 | 437 | const allBundles = [ 438 | umdConfig, 439 | minifiedUmdConfig, 440 | fesm5config, 441 | fesm2015config 442 | ].map(cfg => rollup.rollup(cfg).then(bundle => bundle.write(cfg.output))); 443 | 444 | return Promise.all(allBundles) 445 | .then(() => fancyLog('All bundles generated successfully.')) 446 | }) 447 | .catch(e => { 448 | fancyLog(acolors.red('rollup-bundling failed. See below for errors.\n')); 449 | fancyLog(acolors.red(e)); 450 | process.exit(1); 451 | }); 452 | }); 453 | 454 | 455 | ///////////////////////////////////////////////////////////////////////////// 456 | // Documentation Tasks 457 | ///////////////////////////////////////////////////////////////////////////// 458 | gulp.task('build:doc', (cb) => { 459 | pump([ 460 | gulp.src('src/**/*.ts'), 461 | gulpCompodoc({ 462 | tsconfig: 'src/tsconfig.lib.json', 463 | hideGenerator:true, 464 | disableCoverage: true, 465 | output: `${config.outputDemoDir}/doc/` 466 | }) 467 | ], cb); 468 | }); 469 | 470 | gulp.task('serve:doc', ['clean:doc'], (cb) => { 471 | pump([ 472 | gulp.src('src/**/*.ts'), 473 | gulpCompodoc({ 474 | tsconfig: 'src/tsconfig.lib.json', 475 | serve: true, 476 | output: `${config.outputDir}/doc/` 477 | }) 478 | ], cb); 479 | }); 480 | 481 | 482 | 483 | ///////////////////////////////////////////////////////////////////////////// 484 | // Demo Tasks 485 | ///////////////////////////////////////////////////////////////////////////// 486 | const execDemoCmd = (args,opts) => { 487 | if(fs.existsSync(`${config.demoDir}/node_modules`)){ 488 | return execCmd('ng', args, opts, `/${config.demoDir}`); 489 | } 490 | else{ 491 | fancyLog(acolors.yellow(`No 'node_modules' found in '${config.demoDir}'. Installing dependencies for you...`)); 492 | return helpers.installDependencies({ cwd: `${config.demoDir}` }) 493 | .then(exitCode => exitCode === 0 ? execCmd('ng', args, opts, `/${config.demoDir}`) : Promise.reject()) 494 | .catch(e => { 495 | fancyLog(acolors.red(`ng command failed. See below for errors.\n`)); 496 | fancyLog(acolors.red(e)); 497 | process.exit(1); 498 | }); 499 | } 500 | }; 501 | 502 | gulp.task('test:demo', () => { 503 | return execExternalCmd('npm', 'run test', { cwd: `${config.demoDir}`}); 504 | }); 505 | 506 | gulp.task('serve:demo', () => { 507 | return execDemoCmd('serve --aot --proxy-config proxy.conf.json', { cwd: `${config.demoDir}` }); 508 | }); 509 | 510 | gulp.task('serve:demo-hmr', () => { 511 | return execDemoCmd('serve --configuration hmr --aot --proxy-config proxy.conf.json', { cwd: `${config.demoDir}` }); 512 | }); 513 | 514 | gulp.task('build:demo', () => { 515 | return execDemoCmd(`build --preserve-symlinks --prod --base-href /mat-markdown-editor/ --deploy-url /mat-markdown-editor/`, { cwd: `${config.demoDir}`}); 516 | }); 517 | 518 | gulp.task('serve:demo-ssr',['build:demo-ssr'], () => { 519 | return execExternalCmd('node', 'dist/server.js', { cwd: `${config.demoDir}` }); 520 | }); 521 | 522 | gulp.task('build:demo-ssr', () => { 523 | return execDemoCmd(`build --preserve-symlinks --prod`, { cwd: `${config.demoDir}`}) 524 | .then(() => execDemoCmd(`run mat-markdown-editor-demo:server`, { cwd: `${config.demoDir}` })) 525 | .then(() => execCmd('webpack', '--config webpack.server.config.js --progress --colors', { cwd: `${config.demoDir}` }, `/${config.demoDir}`)) 526 | .catch(e => { 527 | fancyLog(acolors.red(`build:demo-ssr command failed. See below for errors.\n`)); 528 | fancyLog(acolors.red(e)); 529 | process.exit(1); 530 | }); 531 | }); 532 | 533 | gulp.task('push:demo', () => { 534 | return execCmd('ngh',`--dir ${config.outputDemoDir} --message="chore(demo): :rocket: deploy new version"`); 535 | }); 536 | 537 | gulp.task('deploy:demo', (cb) => { 538 | runSequence('build:demo', 'build:doc', 'push:demo', cb); 539 | }); 540 | 541 | 542 | ///////////////////////////////////////////////////////////////////////////// 543 | // Test Tasks 544 | ///////////////////////////////////////////////////////////////////////////// 545 | gulp.task('test', (cb) => { 546 | let isTravis = !!process.env.TRAVIS; 547 | return jestCli.runCLI({ config: require('./package.json').jest, coverage: true, runInBand: isTravis, ci: isTravis }, ".").then(({ results }) => { 548 | if (!results.success) throw new Error('There are test failures!'); 549 | }); 550 | }); 551 | 552 | gulp.task('test:ci', ['clean'], (cb) => { 553 | runSequence('compile', 'test'); 554 | }); 555 | 556 | gulp.task('test:watch', (cb) => { 557 | return jestCli.runCLI({ config: require('./package.json').jest, watch: true }, ".").then(({ results }) => { 558 | if (!results.success) throw new Error('There are test failures!'); 559 | }); 560 | }); 561 | 562 | gulp.task('test:watch-no-cc', (cb) => {//no coverage (useful for debugging failing tests in browser) 563 | return jestCli.runCLI({ config: require('./package.json').jest, watch: true, coverage:false }, ".").then(({ results }) => { 564 | if (!results.success) throw new Error('There are test failures!'); 565 | }); 566 | }); 567 | 568 | ///////////////////////////////////////////////////////////////////////////// 569 | // Release Tasks 570 | ///////////////////////////////////////////////////////////////////////////// 571 | gulp.task('changelog', (cb) => { 572 | pump( 573 | [ 574 | gulp.src('CHANGELOG.md', { buffer: false }), 575 | gulpConventionalChangelog({ preset: 'angular', releaseCount: 0 }), 576 | gulp.dest('./') 577 | ], cb); 578 | }); 579 | 580 | gulp.task('github-release', (cb) => { 581 | if (!argv.ghToken && !process.env.CONVENTIONAL_GITHUB_RELEASER_TOKEN) { 582 | fancyLog(acolors.red(`You must specify a Github Token via '--ghToken' or set environment variable 'CONVENTIONAL_GITHUB_RELEASER_TOKEN' to allow releasing on Github`)); 583 | throw new Error(`Missing '--ghToken' argument and environment variable 'CONVENTIONAL_GITHUB_RELEASER_TOKEN' not set`); 584 | } 585 | 586 | conventionalGithubReleaser( 587 | { 588 | type: 'oauth', 589 | token: argv.ghToken || process.env.CONVENTIONAL_GITHUB_RELEASER_TOKEN 590 | }, 591 | { preset: 'angular' }, 592 | cb); 593 | }); 594 | 595 | gulp.task('bump-version', (cb) => { 596 | if (!argv.version) { 597 | fancyLog(acolors.red(`You must specify which version to bump to (Possible values: 'major', 'minor', and 'patch')`)); 598 | throw new Error(`Missing '--version' argument`); 599 | } 600 | 601 | pump( 602 | [ 603 | gulp.src('./package.json'), 604 | gulpBump({ type: argv.version }), 605 | gulp.dest('./'), 606 | ], cb); 607 | }); 608 | 609 | gulp.task('commit-changes', (cb) => { 610 | let version = getPackageJsonVersion(); 611 | pump( 612 | [ 613 | gulp.src('.'), 614 | gulpGit.add(), 615 | gulpGit.commit(`chore(release): bump version number to ${version}`) 616 | ], cb); 617 | }); 618 | 619 | gulp.task('push-changes', (cb) => { 620 | gulpGit.push('origin', 'master', cb); 621 | }); 622 | 623 | gulp.task('create-new-tag', (cb) => { 624 | let version = `v${getPackageJsonVersion()}`; 625 | gulpGit.tag(version, `chore(release): :sparkles: :tada: create tag for version v${version}`, (error) => { 626 | if (error) { 627 | return cb(error); 628 | } 629 | gulpGit.push('origin', 'master', { args: '--tags' }, cb); 630 | }); 631 | 632 | }); 633 | 634 | // Build and then Publish 'dist' folder to NPM 635 | gulp.task('npm-publish', ['build'], () => { 636 | return execExternalCmd('npm',`publish ${config.outputDir} --access public`) 637 | }); 638 | 639 | // Perfom pre-release checks (no actual release) 640 | gulp.task('pre-release', cb => { 641 | readyToRelease(); 642 | cb(); 643 | }); 644 | 645 | gulp.task('release', (cb) => { 646 | fancyLog('# Performing Pre-Release Checks...'); 647 | if (!readyToRelease()) { 648 | fancyLog(acolors.red('# Pre-Release Checks have failed. Please fix them and try again. Aborting...')); 649 | cb(); 650 | } 651 | else { 652 | fancyLog(acolors.green('# Pre-Release Checks have succeeded. Continuing...')); 653 | runSequence( 654 | 'bump-version', 655 | 'changelog', 656 | 'commit-changes', 657 | 'push-changes', 658 | 'create-new-tag', 659 | 'github-release', 660 | 'npm-publish', 661 | 'deploy:demo', 662 | (error) => { 663 | if (error) { 664 | fancyLog(acolors.red(error.message)); 665 | } else { 666 | fancyLog(acolors.green('RELEASE FINISHED SUCCESSFULLY')); 667 | } 668 | cb(error); 669 | }); 670 | } 671 | }); 672 | 673 | 674 | ///////////////////////////////////////////////////////////////////////////// 675 | // Utility Tasks 676 | ///////////////////////////////////////////////////////////////////////////// 677 | 678 | // Link 'dist' folder (create a local 'ng-scrollreveal' package that symlinks to it) 679 | // This way, we can have the demo project declare a dependency on 'ng-scrollreveal' (as it should) 680 | // and, thanks to 'npm link ng-scrollreveal' on demo project, be sure to always use the latest built 681 | // version of the library ( which is in 'dist/' folder) 682 | gulp.task('link', () => { 683 | return execExternalCmd('npm', 'link', { cwd: `${config.outputDir}` }); 684 | }); 685 | 686 | gulp.task('unlink', () => { 687 | return execExternalCmd('npm', 'unlink', { cwd: `${config.outputDir}` }); 688 | }); 689 | 690 | // Upload code coverage report to coveralls.io (will be triggered by Travis CI on successful build) 691 | gulp.task('coveralls', (cb) => { 692 | pump( 693 | [ 694 | gulp.src(`${config.coverageDir}/lcov.info`), 695 | gulpCoveralls() 696 | ], cb); 697 | }); 698 | 699 | gulp.task('default', ['build']); 700 | 701 | // Load additional tasks 702 | gulpHub(['./config/gulp-tasks/*.js']); 703 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/karma.conf.js'); 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mat-markdown-editor", 3 | "description": "Material design markdown editor", 4 | "version": "0.0.8", 5 | "homepage": "https://github.com/michaeldoye/mat-markdown-editor", 6 | "author": { 7 | "name": "Michael Doye", 8 | "url": "https://github.com/michaeldoye" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/michaeldoye/mat-markdown-editor.git" 13 | }, 14 | "license": "MIT", 15 | "keywords": [ 16 | "markdown", 17 | "text editor", 18 | "angular", 19 | "material design" 20 | ], 21 | "bugs": { 22 | "url": "https://github.com/michaeldoye/mat-markdown-editor/issues" 23 | }, 24 | "private": true, 25 | "scripts": { 26 | "start": "gulp build", 27 | "test": " gulp test", 28 | "demo": " gulp build:demo", 29 | "check-travis": " travis-status --repo=michaeldoye/mat-markdown-editor --branch=master --fail-pending || echo 'Not yet passing'" 30 | }, 31 | "dependencies": { 32 | "@angular/cdk": "^7.3.3", 33 | "@angular/common": "7.2.8", 34 | "@angular/core": "7.2.8", 35 | "@angular/flex-layout": "^7.0.0-beta.23", 36 | "@angular/forms": "^7.2.8", 37 | "@angular/material": "^7.3.3", 38 | "gh-got": "^8.1.0", 39 | "jest-cli": "^24.3.1", 40 | "tsickle": "^0.34.3" 41 | }, 42 | "devDependencies": { 43 | "@angular/animations": "^7.2.8", 44 | "@angular/compiler": "7.2.8", 45 | "@angular/compiler-cli": "7.2.8", 46 | "@angular/platform-browser": "7.2.8", 47 | "@angular/platform-browser-dynamic": "7.2.8", 48 | "@angular/platform-server": "7.2.8", 49 | "@compodoc/gulp-compodoc": "0.0.10", 50 | "@types/jest": "24.0.11", 51 | "@types/lodash": "4.14.123", 52 | "@types/node": "11.11.0", 53 | "angular-cli-ghpages": "0.5.3", 54 | "angular2-template-loader": "0.6.2", 55 | "ansi-colors": "3.2.4", 56 | "autoprefixer": "9.5.0", 57 | "awesome-typescript-loader": "5.2.1", 58 | "codelyzer": "4.5.0", 59 | "commitplease": "3.2.0", 60 | "conventional-github-releaser": "^3.1.2", 61 | "core-js": "2.6.5", 62 | "css-loader": "2.1.1", 63 | "cssnano": "4.1.10", 64 | "del": "4.0.0", 65 | "fancy-log": "1.3.3", 66 | "gulp": "^3.9.1", 67 | "gulp-bump": "3.1.3", 68 | "gulp-conventional-changelog": "2.0.10", 69 | "gulp-coveralls": "0.1.4", 70 | "gulp-file": "0.4.0", 71 | "gulp-git": "2.9.0", 72 | "gulp-hub": "4.2.0", 73 | "gulp-inline-ng2-template": "5.0.1", 74 | "gulp-tslint": "8.1.4", 75 | "html-loader": "0.5.5", 76 | "jest": "24.3.1", 77 | "jest-preset-angular": "7.0.1", 78 | "lodash": "4.17.11", 79 | "node-sass": "4.11.0", 80 | "postcss": "7.0.14", 81 | "postcss-strip-inline-comments": "0.1.5", 82 | "prettier": "1.16.4", 83 | "pump": "3.0.0", 84 | "raw-loader": "1.0.0", 85 | "rollup": "0.58.2", 86 | "rollup-plugin-commonjs": "9.1.3", 87 | "rollup-plugin-node-resolve": "3.3.0", 88 | "rollup-plugin-sourcemaps": "0.4.2", 89 | "rollup-plugin-uglify": "3.0.0", 90 | "run-sequence": "2.2.1", 91 | "rxjs": "6.4.0", 92 | "sass-loader": "7.1.0", 93 | "source-map-loader": "0.2.4", 94 | "to-string-loader": "1.1.5", 95 | "travis-status": "3.0.1", 96 | "tslint": "5.13.1", 97 | "typescript": "3.1.1", 98 | "yargs": "13.2.2", 99 | "zone.js": "0.8.29" 100 | }, 101 | "engines": { 102 | "node": ">=8.0.0" 103 | }, 104 | "jest": { 105 | "preset": "jest-preset-angular", 106 | "roots": [ 107 | "/src/" 108 | ], 109 | "coverageReporters": [ 110 | "lcov", 111 | "text" 112 | ], 113 | "coveragePathIgnorePatterns": [ 114 | "/node_modules/", 115 | "/config", 116 | "/dist/" 117 | ], 118 | "setupTestFrameworkScriptFile": "/config/setupJest.ts" 119 | }, 120 | "greenkeeper": { 121 | "ignore": [ 122 | "@angular/core", 123 | "@angular/common", 124 | "@angular/compiler", 125 | "@angular/platform-server", 126 | "@angular/platform-browser", 127 | "@angular/platform-browser-dynamic", 128 | "@angular/compiler-cli", 129 | "zone.js", 130 | "rxjs", 131 | "tslint", 132 | "gulp-tslint", 133 | "typescript", 134 | "awesome-typescript-loader", 135 | "codelyzer", 136 | "@angular/animations", 137 | "@types/jasmine", 138 | "gulp", 139 | "rollup", 140 | "rollup-plugin-commonjs", 141 | "rollup-plugin-node-resolve", 142 | "rollup-plugin-uglify" 143 | ] 144 | }, 145 | "commitplease": { 146 | "style": "angular", 147 | "types": [ 148 | "feat", 149 | "fix", 150 | "docs", 151 | "style", 152 | "refactor", 153 | "perf", 154 | "test", 155 | "chore", 156 | "revert", 157 | "demo" 158 | ], 159 | "scope": "\\S+.*" 160 | }, 161 | "prettier": { 162 | "bracketSpacing": true, 163 | "trailingComma": "es5", 164 | "tabWidth": 2, 165 | "semi": true, 166 | "singleQuote": true, 167 | "htmlWhitespaceSensitivity": "css" 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './module/lib.module'; 2 | -------------------------------------------------------------------------------- /src/module/editor/editor.component.html: -------------------------------------------------------------------------------- 1 |
8 |
9 | 16 | 17 | 18 |
19 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 | 42 |
43 |
44 | -------------------------------------------------------------------------------- /src/module/editor/editor.component.scss: -------------------------------------------------------------------------------- 1 | .md-editor-container { 2 | position: relative; 3 | height: 100%; 4 | margin-bottom: 15px; 5 | &.border { 6 | border: 1px solid rgba(0, 0, 0, 0.1); 7 | } 8 | &.fullscreen { 9 | margin: 0; 10 | position: fixed; 11 | border: 0; 12 | top: 0; 13 | left: 0; 14 | width: 100% !important; 15 | height: 100% !important; 16 | z-index: 99; 17 | } 18 | &.md-editor-resizable:not(.fullscreen) { 19 | resize: both; 20 | overflow: auto; 21 | display: inline-block; 22 | width: 100%; 23 | .md-footer { 24 | z-index: -1; 25 | } 26 | } 27 | .md-layout { 28 | height: 100%; 29 | display: flex; 30 | flex-direction: column; 31 | .tool-bar { 32 | .btn-group { 33 | } 34 | } 35 | .editor-container { 36 | flex: 1; 37 | display: flex; 38 | & > div { 39 | flex: 1; 40 | } 41 | .editor-panel-container { 42 | height: 100%; 43 | } 44 | .editor-panel { 45 | height: 100%; 46 | .ace-editor { 47 | height: 100%; 48 | min-height: 100%; 49 | } 50 | } 51 | } 52 | .preview-panel { 53 | .material-icons { 54 | vertical-align: top; 55 | margin-bottom: 0.2em; 56 | margin-left: -0.8em; 57 | } 58 | height: 100%; 59 | border-left: 1px solid rgba(0, 0, 0, 0.1); 60 | background-color: white; 61 | padding: 10px; 62 | overflow-y: auto; 63 | } 64 | .md-footer { 65 | .length-view { 66 | flex: 1; 67 | padding: 4px 2px 0 2px; 68 | font-size: 12px; 69 | line-height: 16px; 70 | } 71 | .resize-btn { 72 | width: 17px; 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/module/editor/editor.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | ViewChild, 4 | forwardRef, 5 | Attribute, 6 | Input, 7 | AfterViewInit, 8 | OnInit, 9 | OnDestroy, 10 | ElementRef, 11 | } from '@angular/core'; 12 | import { 13 | NG_VALUE_ACCESSOR, 14 | ControlValueAccessor, 15 | NG_VALIDATORS, 16 | Validator, 17 | AbstractControl, 18 | ValidationErrors, 19 | } from '@angular/forms'; 20 | import { DomSanitizer } from '@angular/platform-browser'; 21 | import { MatMarkdownEditorOptions } from '../lib.interface'; 22 | import { markDownCode, markDownTable, markDownListItem } from '../utils'; 23 | 24 | declare let ace: any; 25 | declare let marked: any; 26 | declare let hljs: any; 27 | 28 | @Component({ 29 | // tslint:disable-next-line: component-selector 30 | selector: 'mat-markdown-editor', 31 | templateUrl: './editor.component.html', 32 | styleUrls: ['./editor.component.scss'], 33 | providers: [ 34 | { 35 | provide: NG_VALUE_ACCESSOR, 36 | useExisting: forwardRef(() => MatMarkdownEditorComponent), 37 | multi: true, 38 | }, 39 | { 40 | provide: NG_VALIDATORS, 41 | useExisting: forwardRef(() => MatMarkdownEditorComponent), 42 | multi: true, 43 | }, 44 | ], 45 | }) 46 | export class MatMarkdownEditorComponent 47 | implements ControlValueAccessor, Validator, OnInit, AfterViewInit, OnDestroy { 48 | @ViewChild('aceEditor') public aceEditorContainer: ElementRef; 49 | @Input() public options: MatMarkdownEditorOptions; 50 | 51 | public showPreviewPanel = true; 52 | public isFullScreen = false; 53 | public previewHtml: any; 54 | public editor: any; 55 | 56 | private _renderMarkTimeout: any; 57 | private _markdownValue: any; 58 | private _options: any = {}; 59 | private _markedOpt: any; 60 | 61 | private _onChange = (_: any) => {}; 62 | private _onTouched = () => {}; 63 | 64 | public get markdownValue(): any { 65 | return this._markdownValue || ''; 66 | } 67 | public set markdownValue(value: any) { 68 | this._markdownValue = value; 69 | this._onChange(value); 70 | 71 | if (this.options.preRender && this.options.preRender instanceof Function) { 72 | value = this.options.preRender(value); 73 | } 74 | if (value !== null && value !== undefined) { 75 | if (this._renderMarkTimeout) { 76 | clearTimeout(this._renderMarkTimeout); 77 | } 78 | this._renderMarkTimeout = setTimeout(() => { 79 | const html = marked(value || '', this._markedOpt); 80 | this.previewHtml = this._domSanitizer.bypassSecurityTrustHtml(html); 81 | }, 100); 82 | } 83 | } 84 | 85 | constructor( 86 | @Attribute('required') public required: boolean = false, 87 | @Attribute('maxlength') public maxlength: number = -1, 88 | private _domSanitizer: DomSanitizer 89 | ) {} 90 | 91 | ngOnInit() { 92 | const editorElement = this.aceEditorContainer.nativeElement; 93 | this.editor = ace.edit(editorElement); 94 | 95 | const markedRender = new marked.Renderer(); 96 | markedRender.code = markDownCode; 97 | markedRender.table = markDownTable; 98 | markedRender.listitem = markDownListItem; 99 | const markedjsOpt = { 100 | renderer: markedRender, 101 | highlight: (code: any) => hljs.highlightAuto(code).value, 102 | }; 103 | this._markedOpt = Object.assign({}, this.options.markedjsOpt, markedjsOpt); 104 | } 105 | 106 | ngAfterViewInit() { 107 | this.editor.$blockScrolling = Infinity; 108 | this.editor.getSession().setUseWrapMode(true); 109 | this.editor.getSession().setMode('ace/mode/markdown'); 110 | this.editor.setValue(this.markdownValue || '', 1); 111 | this.editor.setOption('scrollPastEnd', this._options.scrollPastEnd || 0); 112 | 113 | this.editor.on('change', () => { 114 | this.markdownValue = this.editor.getValue(); 115 | }); 116 | } 117 | 118 | writeValue(value: any | Array): void { 119 | setTimeout(() => { 120 | this.markdownValue = value; 121 | if (typeof value !== 'undefined' && this.editor) { 122 | this.editor.setValue(value || '', 1); 123 | } 124 | }, 1); 125 | } 126 | 127 | registerOnChange(fn: (_: any) => {}): void { 128 | this._onChange = fn; 129 | } 130 | 131 | registerOnTouched(fn: () => {}): void { 132 | this._onTouched = fn; 133 | } 134 | 135 | validate(c: AbstractControl): ValidationErrors { 136 | let result: any = null; 137 | if (this.required && this.markdownValue.length === 0) { 138 | result = { required: true }; 139 | } 140 | if (this.maxlength > 0 && this.markdownValue.length > this.maxlength) { 141 | result = { maxlength: true }; 142 | } 143 | return result; 144 | } 145 | 146 | onTogglePreview(isOpen: boolean) { 147 | this.showPreviewPanel = isOpen; 148 | } 149 | 150 | onFullScreen(isFullScreen: boolean) { 151 | this.isFullScreen = isFullScreen; 152 | this.editor.resize(); 153 | } 154 | 155 | previewPanelClick(event: Event) { 156 | if (this.options.enablePreviewContentClick !== true) { 157 | event.preventDefault(); 158 | event.stopImmediatePropagation(); 159 | } 160 | } 161 | 162 | ngOnDestroy() { 163 | return this.editor && this.editor.destroy(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/module/editor/toolbar/toolbar.component.html: -------------------------------------------------------------------------------- 1 | 8 |
9 | 18 | 27 | 36 | 45 | 46 |
47 | 48 |
49 | 58 | 67 | 68 |
69 | 70 |
71 | 82 | 93 | 102 | 103 |
104 | 105 |
106 | 117 |
118 | 119 | 120 | 121 |
122 | 132 | 142 |
143 |
144 | -------------------------------------------------------------------------------- /src/module/editor/toolbar/toolbar.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldoye/mat-markdown-editor/229a4b1c6d6876987d421b98e737688210c95a6c/src/module/editor/toolbar/toolbar.component.scss -------------------------------------------------------------------------------- /src/module/editor/toolbar/toolbar.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | Input, 4 | Output, 5 | EventEmitter, 6 | Renderer2, 7 | } from '@angular/core'; 8 | 9 | @Component({ 10 | // tslint:disable-next-line: component-selector 11 | selector: 'mat-markdown-editor-toolbar', 12 | templateUrl: './toolbar.component.html', 13 | styleUrls: ['./toolbar.component.scss'], 14 | }) 15 | export class EditorToolbarComponent { 16 | @Input() public options: any; 17 | @Input() public isFullScreen: boolean; 18 | @Input() private editor: any; 19 | @Output() public onTogglePreview = new EventEmitter(); 20 | @Output() public onFullScreen = new EventEmitter(); 21 | 22 | public previewIsOpen = true; 23 | private _editorResizeTimer: any; 24 | 25 | constructor(private _renderer: Renderer2) {} 26 | 27 | insertContent(type: string, customContent?: string) { 28 | if (!this.editor) { 29 | return; 30 | } 31 | let selectedText = this.editor.getSelectedText(); 32 | let startSize = 2; 33 | let initText = ''; 34 | const isSelected = !!selectedText; 35 | const range = this.editor.selection.getRange(); 36 | switch (type) { 37 | case 'Bold': 38 | initText = 'Bold Text'; 39 | selectedText = `**${selectedText || initText}**`; 40 | break; 41 | case 'Italic': 42 | initText = 'Italic Text'; 43 | selectedText = `*${selectedText || initText}*`; 44 | startSize = 1; 45 | break; 46 | case 'Heading': 47 | initText = 'Heading'; 48 | selectedText = `# ${selectedText || initText}`; 49 | break; 50 | case 'Reference': 51 | initText = 'Reference'; 52 | selectedText = `> ${selectedText || initText}`; 53 | break; 54 | case 'Link': 55 | selectedText = `[${selectedText}](http://)`; 56 | startSize = 1; 57 | break; 58 | case 'Image': 59 | selectedText = `![](http://)`; 60 | break; 61 | case 'Ul': 62 | selectedText = `- ${selectedText || initText}`; 63 | break; 64 | case 'Ol': 65 | selectedText = `1. ${selectedText || initText}`; 66 | startSize = 3; 67 | break; 68 | case 'Code': 69 | initText = 'Source Code'; 70 | selectedText = 71 | '```language\r\n' + (selectedText || initText) + '\r\n```'; 72 | startSize = 3; 73 | break; 74 | case 'Custom': 75 | selectedText = customContent; 76 | startSize = 0; 77 | break; 78 | } 79 | this.editor.session.replace(range, selectedText); 80 | if (!isSelected) { 81 | range.start.column += startSize; 82 | range.end.column = range.start.column + initText.length; 83 | this.editor.selection.setRange(range); 84 | } 85 | this.editor.focus(); 86 | } 87 | 88 | togglePreview() { 89 | this.previewIsOpen = !this.previewIsOpen; 90 | this.onTogglePreview.emit(this.previewIsOpen); 91 | this.editorResize(); 92 | } 93 | 94 | fullScreen() { 95 | this.isFullScreen = !this.isFullScreen; 96 | this._renderer.setStyle( 97 | document.body, 98 | 'overflowY', 99 | this.isFullScreen ? 'hidden' : 'auto' 100 | ); 101 | this.onFullScreen.emit(this.isFullScreen); 102 | this.editorResize(); 103 | } 104 | 105 | editorResize(timeOut: number = 100) { 106 | if (!this.editor) { 107 | return; 108 | } 109 | if (this._editorResizeTimer) { 110 | clearTimeout(this._editorResizeTimer); 111 | } 112 | this._editorResizeTimer = setTimeout(() => { 113 | this.editor.resize(); 114 | this.editor.focus(); 115 | }, timeOut); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/module/lib.interface.ts: -------------------------------------------------------------------------------- 1 | export interface MatMarkdownEditorOptions { 2 | showBorder?: boolean; // Show editor component's border 3 | // tslint:disable-next-line: max-line-length 4 | hideIcons?: object; // ['Bold', 'Italic', 'Heading', 'Reference', 'Link', 'Image', 'Ul', 'Ol', 'Code', 'TogglePreview', 'FullScreen'], Default is empty 5 | scrollPastEnd?: number; // The option for ace editor 6 | enablePreviewContentClick?: boolean; // Allow user fire the click event on the preview panel, like href etc. 7 | resizable?: boolean; // Allow resize the editor 8 | markedjsOpt?: MarkedjsOption; // The markedjs option, see https://marked.js.org/#/USING_ADVANCED.md#options 9 | hideToolbar?: boolean; 10 | height?: string; 11 | mode?: string; 12 | preRender?: Function; 13 | toolbarColor?: string; 14 | } 15 | 16 | export interface MarkedjsOption { 17 | baseUrl?: string; // Default null 18 | breaks?: boolean; // Default false 19 | gfm?: boolean; // Default true 20 | headerIds?: boolean; // Default true 21 | headerPrefix?: string; // Default '' 22 | langPrefix?: string; // Default 'language-' 23 | mangle?: boolean; // Default true 24 | pedantic?: boolean; // Default false 25 | sanitize?: boolean; // Default false 26 | sanitizer?: Function; // Default null 27 | silent?: boolean; // Default false 28 | smartLists?: boolean; // Default false 29 | smartypants?: boolean; // Default false 30 | tables?: boolean; // Default true 31 | xhtml?: boolean; // Default false 32 | } 33 | -------------------------------------------------------------------------------- /src/module/lib.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule, ModuleWithProviders } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | 6 | import { MatMarkdownEditorComponent } from './editor/editor.component'; 7 | import { LibService } from './service/lib.service'; 8 | import { MaterialModule } from './material.module'; 9 | import { FlexLayoutModule } from '@angular/flex-layout'; 10 | import { EditorToolbarComponent } from './editor/toolbar/toolbar.component'; 11 | 12 | export { MatMarkdownEditorComponent } from './editor/editor.component'; 13 | export { LibService } from './service/lib.service'; 14 | export { MatMarkdownEditorOptions, MarkedjsOption } from './lib.interface'; 15 | 16 | @NgModule({ 17 | imports: [ 18 | CommonModule, 19 | FormsModule, 20 | MaterialModule, 21 | ReactiveFormsModule, 22 | BrowserAnimationsModule, 23 | FlexLayoutModule, 24 | ], 25 | exports: [MatMarkdownEditorComponent], 26 | declarations: [MatMarkdownEditorComponent, EditorToolbarComponent], 27 | }) 28 | export class MatMarkdownEditorModule { 29 | static forRoot(): ModuleWithProviders { 30 | return { 31 | ngModule: MatMarkdownEditorModule, 32 | providers: [LibService], 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/module/material.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { 3 | MatAutocompleteModule, 4 | MatButtonModule, 5 | MatButtonToggleModule, 6 | MatCardModule, 7 | MatCheckboxModule, 8 | MatChipsModule, 9 | MatDatepickerModule, 10 | MatDialogModule, 11 | MatExpansionModule, 12 | MatGridListModule, 13 | MatIconModule, 14 | MatInputModule, 15 | MatListModule, 16 | MatMenuModule, 17 | MatNativeDateModule, 18 | MatPaginatorModule, 19 | MatProgressBarModule, 20 | MatProgressSpinnerModule, 21 | MatRadioModule, 22 | MatRippleModule, 23 | MatSelectModule, 24 | MatSidenavModule, 25 | MatSliderModule, 26 | MatSlideToggleModule, 27 | MatSnackBarModule, 28 | MatSortModule, 29 | MatTableModule, 30 | MatTabsModule, 31 | MatToolbarModule, 32 | MatTooltipModule, 33 | MatStepperModule, 34 | } from '@angular/material'; 35 | 36 | @NgModule({ 37 | imports: [ 38 | MatAutocompleteModule, 39 | MatButtonModule, 40 | MatButtonToggleModule, 41 | MatCardModule, 42 | MatCheckboxModule, 43 | MatChipsModule, 44 | MatStepperModule, 45 | MatDatepickerModule, 46 | MatDialogModule, 47 | MatExpansionModule, 48 | MatGridListModule, 49 | MatIconModule, 50 | MatInputModule, 51 | MatListModule, 52 | MatMenuModule, 53 | MatNativeDateModule, 54 | MatPaginatorModule, 55 | MatProgressBarModule, 56 | MatProgressSpinnerModule, 57 | MatRadioModule, 58 | MatRippleModule, 59 | MatSelectModule, 60 | MatSidenavModule, 61 | MatSliderModule, 62 | MatSlideToggleModule, 63 | MatSnackBarModule, 64 | MatSortModule, 65 | MatTableModule, 66 | MatTabsModule, 67 | MatToolbarModule, 68 | MatTooltipModule, 69 | ], 70 | exports: [ 71 | MatAutocompleteModule, 72 | MatButtonModule, 73 | MatButtonToggleModule, 74 | MatCardModule, 75 | MatCheckboxModule, 76 | MatChipsModule, 77 | MatStepperModule, 78 | MatDatepickerModule, 79 | MatDialogModule, 80 | MatExpansionModule, 81 | MatGridListModule, 82 | MatIconModule, 83 | MatInputModule, 84 | MatListModule, 85 | MatMenuModule, 86 | MatNativeDateModule, 87 | MatPaginatorModule, 88 | MatProgressBarModule, 89 | MatProgressSpinnerModule, 90 | MatRadioModule, 91 | MatRippleModule, 92 | MatSelectModule, 93 | MatSidenavModule, 94 | MatSliderModule, 95 | MatSlideToggleModule, 96 | MatSnackBarModule, 97 | MatSortModule, 98 | MatTableModule, 99 | MatTabsModule, 100 | MatToolbarModule, 101 | MatTooltipModule, 102 | ], 103 | }) 104 | export class MaterialModule {} 105 | -------------------------------------------------------------------------------- /src/module/service/lib.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { LibService } from './lib.service'; 4 | 5 | describe('LibService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [LibService] 9 | }); 10 | }); 11 | 12 | it('should create service', inject([LibService], (service: LibService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | 16 | it('should say hello to stranger', inject([LibService], (service: LibService) => { 17 | expect(service.sayHello()).toBe('Hello Stanger!'); 18 | })); 19 | 20 | it('should say hello to provided user', inject([LibService], (service: LibService) => { 21 | expect(service.sayHello('ng-hacker')).toBe('Hello ng-hacker!'); 22 | })); 23 | }); 24 | -------------------------------------------------------------------------------- /src/module/service/lib.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class LibService { 5 | constructor() { } 6 | sayHello(name?: string) { 7 | return `Hello ${name || 'Stanger'}!`; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/module/utils/index.ts: -------------------------------------------------------------------------------- 1 | declare let hljs: any; 2 | 3 | export function markDownListItem(text: string): string { 4 | if (!/^\s*\[[x ]]\s*/.test(text)) { 5 | return `
  • ${text}
  • `; 6 | } else { 7 | text = text 8 | .replace( 9 | /^\s*\[ ]\s*/, 10 | 'check_box_outline_blank ' 11 | ) 12 | .replace( 13 | /^\s*\[x]\s*/, 14 | 'check_box ' 15 | ); 16 | return `
  • ${text}
  • `; 17 | } 18 | } 19 | 20 | export function markDownTable(header: string, body: string): string { 21 | return `\n\n${header}\n\n${body}\n
    \n`; 22 | } 23 | 24 | export function markDownCode(code: any, language: any): string { 25 | const validLang = !!(language && hljs.getLanguage(language)); 26 | const highlighted = validLang ? hljs.highlight(language, code).value : code; 27 | return `
    ${highlighted}
    `; 28 | } 29 | -------------------------------------------------------------------------------- /src/tsconfig.lib.es5.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "outDir": "../tmp/lib-es5/", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "files": [ 10 | "./index.ts" 11 | ], 12 | "angularCompilerOptions": { 13 | "strictMetadataEmit": true, 14 | "skipTemplateCodegen": true, 15 | "genDir": "../tmp/lib-gen-dir/", 16 | "flatModuleOutFile": "mat-markdown-editor.js", 17 | "flatModuleId": "mat-markdown-editor", 18 | "annotateForClosureCompiler": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../tmp/lib-es2015/", 5 | "target": "es2015", 6 | "rootDir": "./", 7 | "baseUrl": "", 8 | "types": [ "node"] 9 | }, 10 | "files": [ 11 | "./index.ts" 12 | ], 13 | "angularCompilerOptions": { 14 | "strictMetadataEmit": true, 15 | "skipTemplateCodegen": true, 16 | "genDir": "../tmp/lib-gen-dir/", 17 | "flatModuleOutFile": "mat-markdown-editor.js", 18 | "flatModuleId": "mat-markdown-editor", 19 | "annotateForClosureCompiler": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "", 5 | "module": "commonjs", 6 | "declaration": false, 7 | "emitDecoratorMetadata": true, 8 | "typeRoots": [ 9 | "../node_modules/@types" 10 | ] 11 | }, 12 | "awesomeTypescriptLoaderOptions": { 13 | "useWebpackText": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es2015", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "inlineSources": true, 8 | "declaration": true, 9 | "experimentalDecorators": true, 10 | "noImplicitAny": true, 11 | "suppressImplicitAnyIndexErrors": true, 12 | "skipLibCheck": true, 13 | "stripInternal": true, 14 | "lib": [ 15 | "es2015", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true, 18 | "rxjs" 19 | ], 20 | "import-spacing": true, 21 | "indent": [ 22 | true, 23 | "spaces" 24 | ], 25 | "interface-over-type-literal": true, 26 | "label-position": true, 27 | "max-line-length": [ 28 | true, 29 | 140 30 | ], 31 | "member-access": false, 32 | "member-ordering": [ 33 | true, 34 | "static-before-instance", 35 | "variables-before-functions" 36 | ], 37 | "no-arg": true, 38 | "no-bitwise": true, 39 | "no-console": [ 40 | true, 41 | "debug", 42 | "info", 43 | "time", 44 | "timeEnd", 45 | "trace" 46 | ], 47 | "no-construct": true, 48 | "no-debugger": true, 49 | "no-duplicate-super": true, 50 | "no-empty": false, 51 | "no-empty-interface": true, 52 | "no-eval": true, 53 | "no-inferrable-types": [ 54 | true, 55 | "ignore-params" 56 | ], 57 | "no-misused-new": true, 58 | "no-non-null-assertion": true, 59 | "no-shadowed-variable": true, 60 | "no-string-literal": false, 61 | "no-string-throw": true, 62 | "no-switch-case-fall-through": true, 63 | "no-trailing-whitespace": true, 64 | "no-unnecessary-initializer": true, 65 | "no-unused-expression": true, 66 | "no-use-before-declare": true, 67 | "no-var-keyword": true, 68 | "object-literal-sort-keys": false, 69 | "one-line": [ 70 | true, 71 | "check-open-brace", 72 | "check-catch", 73 | "check-else", 74 | "check-whitespace" 75 | ], 76 | "prefer-const": true, 77 | "quotemark": [ 78 | true, 79 | "single" 80 | ], 81 | "radix": true, 82 | "semicolon": [ 83 | "always" 84 | ], 85 | "triple-equals": [ 86 | true, 87 | "allow-null-check" 88 | ], 89 | "typedef-whitespace": [ 90 | true, 91 | { 92 | "call-signature": "nospace", 93 | "index-signature": "nospace", 94 | "parameter": "nospace", 95 | "property-declaration": "nospace", 96 | "variable-declaration": "nospace" 97 | } 98 | ], 99 | "unified-signatures": true, 100 | "variable-name": false, 101 | "whitespace": [ 102 | true, 103 | "check-branch", 104 | "check-decl", 105 | "check-operator", 106 | "check-separator", 107 | "check-type" 108 | ], 109 | "directive-selector": [ 110 | true, 111 | "attribute", 112 | "ngx-mde", 113 | "camelCase" 114 | ], 115 | "component-selector": [ 116 | true, 117 | "element", 118 | "ngx-mde", 119 | "kebab-case" 120 | ], 121 | "use-input-property-decorator": true, 122 | "use-output-property-decorator": true, 123 | "use-host-property-decorator": true, 124 | "no-input-rename": true, 125 | "no-output-rename": true, 126 | "use-life-cycle-interface": true, 127 | "use-pipe-transform-interface": true, 128 | "component-class-suffix": true, 129 | "directive-class-suffix": true 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./config/webpack.test.js'); 2 | --------------------------------------------------------------------------------