├── .babelrc ├── .coveralls.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.yml ├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── lib ├── PluginEnvironment.js ├── index.js ├── renderer.js ├── services │ ├── PreziService.js │ ├── VideoServiceBase.js │ ├── VimeoService.js │ ├── VineService.js │ └── YouTubeService.js └── tokenizer.js ├── package.json └── test ├── .eslintrc.yml ├── fakes └── CustomService.js ├── fixtures ├── custom-class-names.txt ├── custom-service.txt ├── filtered-url.txt ├── services │ ├── prezi.txt │ ├── vimeo.txt │ ├── vine.txt │ └── youtube.txt ├── tag-syntax.txt ├── without-allowfullscreen-attributes.txt └── without-size-attributes.txt └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "es2015" ] 3 | } 4 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; Grab the EditorConfig extension for Visual Studio: 2 | ; https://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328 3 | 4 | ; Top-most EditorConfig file 5 | root = true 6 | 7 | ; Unix-style newlines with a newline ending every file 8 | [*] 9 | end_of_line = LF 10 | insert_final_newline = true 11 | indent_style = space 12 | indent_size = 2 13 | trim_trailing_whitespace = true 14 | 15 | [*.{md,yaml}] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | dist/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | es6: true 4 | node: true 5 | extends: xo 6 | rules: 7 | array-bracket-spacing: 8 | - error 9 | - always 10 | curly: 11 | - error 12 | - multi-line 13 | dot-location: off 14 | dot-notation: off 15 | indent: 16 | - error 17 | - 2 18 | - SwitchCase: 1 19 | max-len: off 20 | no-multiple-empty-lines: 21 | - error 22 | - max: 2 23 | maxBOF: 0 24 | maxEOF: 1 25 | no-negated-condition: off 26 | no-return-assign: off 27 | no-unused-vars: 28 | - error 29 | - argsIgnorePattern: "^_" 30 | varsIgnorePattern: "^(given|should)$" 31 | no-var: error 32 | object-curly-spacing: 33 | - error 34 | - always 35 | one-var: 36 | - error 37 | - initialized: never 38 | operator-linebreak: 39 | - error 40 | - before 41 | padded-blocks: 42 | - error 43 | - classes: always 44 | switches: never 45 | quotes: 46 | - error 47 | - double 48 | - allowTemplateLiterals: true 49 | avoidEscape: true 50 | quote-props: off 51 | require-jsdoc: off 52 | space-before-function-paren: 53 | - error 54 | - anonymous: always 55 | named: never 56 | valid-jsdoc: 57 | - error 58 | - prefer: 59 | return: returns 60 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto eol=lf 3 | 4 | *.css text 5 | *.html text 6 | *.ini text 7 | *.js text 8 | *.jsdoc text 9 | *.json text 10 | *.md text 11 | *.nj text 12 | *.styl text 13 | *.ts text 14 | *.txt text 15 | *.yaml text 16 | 17 | *.pdf binary 18 | *.png binary 19 | *.rar binary 20 | *.jpg binary 21 | *.zip binary 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Private files 2 | _private 3 | 4 | # Build output 5 | /dist/ 6 | 7 | # Vim 8 | *.swp 9 | 10 | # Logs 11 | logs 12 | *.log 13 | npm-debug.log* 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directory 36 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 37 | node_modules 38 | 39 | # Optional npm cache directory 40 | .npm 41 | 42 | # Optional REPL history 43 | .node_repl_history 44 | 45 | # OS X 46 | .DS_Store 47 | 48 | # Windows 49 | Thumbs.db 50 | ehthumbs.db 51 | Desktop.ini 52 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /coverage/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4' 4 | - '5' 5 | - '6' 6 | after_success: npm run test-coverage-ci 7 | sudo: false 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright for portions of project markdown-it-video are held by the original 4 | authors (c) 2015-2016. All other copyright (c) 2016 Rotorz Limited. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # markdown-it-block-embed [](https://travis-ci.org/rotorz/markdown-it-block-embed) 2 | 3 | [](https://badge.fury.io/js/markdown-it-block-embed) 4 | [](https://david-dm.org/rotorz/markdown-it-block-embed) 5 | [](https://david-dm.org/rotorz/markdown-it-block-embed#info=devDependencies) 6 | 7 | Plugin for markdown-it that detects and outputs block level embeds such as videos and supports custom embed services. 8 | 9 | This project started as a fork of the [markdown-it-video](https://github.com/brianjgeiger/markdown-it-video) 10 | package but for the most part has been rewritten to behave as a block element rather than 11 | an inline one. Implementation of embed services were separated and additional options have 12 | been added to control the output of the generated embed code. 13 | 14 | 15 | Example input: 16 | ```markdown 17 | Here is an embedded video: 18 | 19 | @[youtube](lJIrF4YjHfQ) 20 | ``` 21 | 22 | Output (with default options): 23 | ```html 24 |
33 | ``` 34 | 35 | 36 | ## Install 37 | 38 | ``` 39 | $ npm install --save markdown-it-block-embed 40 | ``` 41 | 42 | 43 | ## Usage 44 | 45 | ```javascript 46 | var md = require("markdown-it")(); 47 | var blockEmbedPlugin = require("markdown-it-block-embed"); 48 | 49 | md.use(blockEmbedPlugin, { 50 | containerClassName: "video-embed" 51 | }); 52 | 53 | var input = "@[youtube](lJIrF4YjHfQ)"; 54 | var output = md.render(input); 55 | 56 | console.log(output); 57 | ``` 58 | 59 | 60 | ## Options 61 | 62 | Option | Type | Default | Description 63 | :--------------------|:---------------------|:-------------------------|:------------------------------------------------------------------------------------------------------------------------------------------ 64 | `containerClassName` | `string` \| `null` | `'block-embed'` | Class name for image container element. 65 | `serviceClassPrefix` | `string` | `'block-embed-service-'` | Prefix for service name in CSS class. 66 | `outputPlayerSize` | `boolean` | `true` | Indicates if 'width' and 'height' attributes are written to output. 67 | `allowFullScreen` | `boolean` | `true` | Indicates whether embed iframe should be allowed to enter full screen mode. 68 | `filterUrl` | `function` \| `null` | `null` | A function that customizes url output. Signature: `function (url: string, serviceName: string, videoID: string, options: object): string` 69 | | | | 70 | `services.{name}` | `function` | - | A function that constructs a new instance of the service. Can extend `VideoServiceBase`. 71 | `services.youtube` | `function` | `YouTubeService` | Implementation of the 'youtube' embed service. Can be overridden by a custom implementation. 72 | `services.vimeo` | `function` | `VimeoService` | Implementation of the 'vimeo' embed service. Can be overridden by a custom implementation. 73 | `services.vine` | `function` | `VineService` | Implementation of the 'vine' embed service. Can be overridden by a custom implementation. 74 | `services.prezi` | `function` | `PreziService` | Implementation of the 'prezi' embed service. Can be overridden by a custom implementation. 75 | | | | 76 | `{service-name}` | `object` | - | Options can be supplied to embed services. 77 | | | | 78 | `youtube.width` | `number` | `640` | Width of YouTube embed. 79 | `youtube.height` | `number` | `390` | Height of YouTube embed. 80 | | | | 81 | `vimeo.width` | `number` | `500` | Width of Vimeo embed. 82 | `vimeo.height` | `number` | `281` | Height of Vimeo embed. 83 | | | | 84 | `vine.width` | `number` | `600` | Width of Vine embed. 85 | `vine.height` | `number` | `600` | Height of Vine embed. 86 | `vine.embed` | `string` | `'simple'` | Type of embed; for instance, `'simple'` or `'postcard'` (see https://dev.twitter.com/web/vine). 87 | | | | 88 | `prezi.width` | `number` | `550` | Width of Prezi embed. 89 | `prezi.height` | `number` | `400` | Height of Prezi embed. 90 | 91 | 92 | ## Supported Services 93 | 94 | HTML embed codes are currently automatically output for the following services: 95 | 96 | - YouTube 97 | - Vimeo 98 | - Vine 99 | - Prezi 100 | 101 | Custom embed services can be specifying in the options that you provide to the 102 | `markdown-it-block-embed` plugin. 103 | 104 | 105 | ### YouTube 106 | 107 | ```md 108 | @[youtube](lJIrF4YjHfQ) 109 | ``` 110 | 111 | is interpreted as 112 | 113 | ```html 114 | 123 | ``` 124 | 125 | Alternately, you could use a number of different YouTube URL formats rather than just the video id. 126 | 127 | ```md 128 | @[youtube](http://www.youtube.com/embed/lJIrF4YjHfQ) 129 | @[youtube](https://www.youtube.com/watch?v=lJIrF4YjHfQ&feature=feedrec_centerforopenscience_index) 130 | @[youtube](http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/QdK8U-VIH_o) 131 | @[youtube](http://www.youtube.com/v/lJIrF4YjHfQ?fs=1&hl=en_US&rel=0) 132 | @[youtube](http://www.youtube.com/watch?v=lJIrF4YjHfQ#t=0m10s) 133 | @[youtube](http://www.youtube.com/embed/lJIrF4YjHfQ?rel=0) 134 | @[youtube](http://www.youtube.com/watch?v=lJIrF4YjHfQ) 135 | @[youtube](http://youtu.be/lJIrF4YjHfQ) 136 | ``` 137 | 138 | ### Vimeo 139 | 140 | ```md 141 | @[vimeo](19706846) 142 | ``` 143 | 144 | is interpreted as 145 | 146 | ```html 147 | 156 | ``` 157 | 158 | Alternately, you could use the url instead of just the video id. 159 | 160 | ```md 161 | @[vimeo](https://vimeo.com/19706846) 162 | @[vimeo](https://player.vimeo.com/video/19706846) 163 | ``` 164 | 165 | ### Vine 166 | 167 | ```md 168 | @[vine](bjHh0zHdgZT) 169 | ``` 170 | 171 | is interpreted as 172 | 173 | ```html 174 | 183 | ``` 184 | 185 | Alternately, you could use the url, or even the whole embed tag instead of just the video id. 186 | 187 | ```md 188 | @[vine](https://vine.co/v/bjHh0zHdgZT/embed/simple) 189 | @[vine](https://vine.co/v/bjHh0zHdgZT/embed/postcard?audio=1) 190 | @[vine]() 191 | ``` 192 | 193 | ### Prezi 194 | 195 | ```md 196 | @[prezi](1kkxdtlp4241) 197 | ``` 198 | 199 | is interpreted as 200 | 201 | ```html 202 | 211 | ``` 212 | 213 | Alternately, you could use the url. 214 | 215 | ```md 216 | @[prezi](https://prezi.com/1kkxdtlp4241/valentines-day/) 217 | @[prezi](https://prezi.com/e3g83t83nw03/destination-prezi-template/) 218 | @[prezi](https://prezi.com/prg6t46qgzik/anatomy-of-a-social-powered-customer-service-win/) 219 | ``` 220 | 221 | 222 | ## Contribution Agreement 223 | 224 | This project is licensed under the MIT license (see LICENSE). To be in the best 225 | position to enforce these licenses the copyright status of this project needs to 226 | be as simple as possible. To achieve this the following terms and conditions 227 | must be met: 228 | 229 | - All contributed content (including but not limited to source code, text, 230 | image, videos, bug reports, suggestions, ideas, etc.) must be the 231 | contributors own work. 232 | 233 | - The contributor disclaims all copyright and accepts that their contributed 234 | content will be released to the public domain. 235 | 236 | - The act of submitting a contribution indicates that the contributor agrees 237 | with this agreement. This includes (but is not limited to) pull requests, issues, 238 | tickets, e-mails, newsgroups, blogs, forums, etc. 239 | -------------------------------------------------------------------------------- /lib/PluginEnvironment.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | "use strict"; 5 | 6 | const YouTubeService = require("./services/YouTubeService"); 7 | const VimeoService = require("./services/VimeoService"); 8 | const VineService = require("./services/VineService"); 9 | const PreziService = require("./services/PreziService"); 10 | 11 | 12 | class PluginEnvironment { 13 | 14 | constructor(md, options) { 15 | this.md = md; 16 | this.options = Object.assign(this.getDefaultOptions(), options); 17 | 18 | this._initServices(); 19 | } 20 | 21 | _initServices() { 22 | let defaultServiceBindings = { 23 | "youtube": YouTubeService, 24 | "vimeo": VimeoService, 25 | "vine": VineService, 26 | "prezi": PreziService 27 | }; 28 | 29 | let serviceBindings = Object.assign({}, defaultServiceBindings, this.options.services); 30 | let services = {}; 31 | for (let serviceName of Object.keys(serviceBindings)) { 32 | let _serviceClass = serviceBindings[serviceName]; 33 | services[serviceName] = new _serviceClass(serviceName, this.options[serviceName], this); 34 | } 35 | 36 | this.services = services; 37 | } 38 | 39 | getDefaultOptions() { 40 | return { 41 | containerClassName: "block-embed", 42 | serviceClassPrefix: "block-embed-service-", 43 | outputPlayerSize: true, 44 | allowFullScreen: true, 45 | filterUrl: null 46 | }; 47 | } 48 | 49 | } 50 | 51 | 52 | module.exports = PluginEnvironment; 53 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | "use strict"; 5 | 6 | const PluginEnvironment = require("./PluginEnvironment"); 7 | const renderer = require("./renderer"); 8 | const tokenizer = require("./tokenizer"); 9 | 10 | 11 | function setup(md, options) { 12 | let env = new PluginEnvironment(md, options); 13 | 14 | md.block.ruler.before("fence", "video", tokenizer.bind(env), { 15 | alt: [ "paragraph", "reference", "blockquote", "list" ] 16 | }); 17 | md.renderer.rules["video"] = renderer.bind(env); 18 | } 19 | 20 | 21 | module.exports = setup; 22 | -------------------------------------------------------------------------------- /lib/renderer.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | "use strict"; 5 | 6 | 7 | function renderer(tokens, idx, options, _env) { 8 | let videoToken = tokens[idx]; 9 | 10 | let service = videoToken.info.service; 11 | let videoID = videoToken.info.videoID; 12 | 13 | return service.getEmbedCode(videoID); 14 | } 15 | 16 | 17 | module.exports = renderer; 18 | -------------------------------------------------------------------------------- /lib/services/PreziService.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | "use strict"; 5 | 6 | const VideoServiceBase = require("./VideoServiceBase"); 7 | 8 | 9 | class PreziService extends VideoServiceBase { 10 | 11 | getDefaultOptions() { 12 | return { width: 550, height: 400 }; 13 | } 14 | 15 | extractVideoID(reference) { 16 | let match = reference.match(/^https:\/\/prezi.com\/(.[^/]+)/); 17 | return match ? match[1] : reference; 18 | } 19 | 20 | getVideoUrl(videoID) { 21 | let escapedVideoID = this.env.md.utils.escapeHtml(videoID); 22 | return "https://prezi.com/embed/" + escapedVideoID 23 | + "/?bgcolor=ffffff&lock_to_path=0&autoplay=0&autohide_ctrls=0&" 24 | + "landing_data=bHVZZmNaNDBIWnNjdEVENDRhZDFNZGNIUE43MHdLNWpsdFJLb2ZHanI5N1lQVHkxSHFxazZ0UUNCRHloSXZROHh3PT0&" 25 | + "landing_sign=1kD6c0N6aYpMUS0wxnQjxzSqZlEB8qNFdxtdjYhwSuI"; 26 | } 27 | 28 | } 29 | 30 | 31 | module.exports = PreziService; 32 | -------------------------------------------------------------------------------- /lib/services/VideoServiceBase.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | "use strict"; 5 | 6 | 7 | function defaultUrlFilter(url, _videoID, _serviceName, _options) { 8 | return url; 9 | } 10 | 11 | 12 | class VideoServiceBase { 13 | 14 | constructor(name, options, env) { 15 | this.name = name; 16 | this.options = Object.assign(this.getDefaultOptions(), options); 17 | this.env = env; 18 | } 19 | 20 | getDefaultOptions() { 21 | return {}; 22 | } 23 | 24 | extractVideoID(reference) { 25 | return reference; 26 | } 27 | 28 | getVideoUrl(_videoID) { 29 | throw new Error("not implemented"); 30 | } 31 | 32 | getFilteredVideoUrl(videoID) { 33 | let filterUrlDelegate = typeof this.env.options.filterUrl === "function" 34 | ? this.env.options.filterUrl 35 | : defaultUrlFilter; 36 | let videoUrl = this.getVideoUrl(videoID); 37 | return filterUrlDelegate(videoUrl, this.name, videoID, this.env.options); 38 | } 39 | 40 | getEmbedCode(videoID) { 41 | let containerClassNames = []; 42 | if (this.env.options.containerClassName) { 43 | containerClassNames.push(this.env.options.containerClassName); 44 | } 45 | 46 | let escapedServiceName = this.env.md.utils.escapeHtml(this.name); 47 | containerClassNames.push(this.env.options.serviceClassPrefix + escapedServiceName); 48 | 49 | let iframeAttributeList = []; 50 | iframeAttributeList.push([ "type", "text/html" ]); 51 | iframeAttributeList.push([ "src", this.getFilteredVideoUrl(videoID) ]); 52 | iframeAttributeList.push([ "frameborder", 0 ]); 53 | 54 | if (this.env.options.outputPlayerSize === true) { 55 | if (this.options.width !== undefined && this.options.width !== null) { 56 | iframeAttributeList.push([ "width", this.options.width ]); 57 | } 58 | if (this.options.height !== undefined && this.options.height !== null) { 59 | iframeAttributeList.push([ "height", this.options.height ]); 60 | } 61 | } 62 | 63 | if (this.env.options.allowFullScreen === true) { 64 | iframeAttributeList.push([ "webkitallowfullscreen" ]); 65 | iframeAttributeList.push([ "mozallowfullscreen" ]); 66 | iframeAttributeList.push([ "allowfullscreen" ]); 67 | } 68 | 69 | let iframeAttributes = iframeAttributeList 70 | .map(pair => 71 | pair[1] !== undefined 72 | ? `${pair[0]}="${pair[1]}"` 73 | : pair[0] 74 | ) 75 | .join(" "); 76 | 77 | return `Paragraph before
15 | 16 | . 17 | 18 | . 19 | @[example](video-123) 20 | 21 | Paragraph after 22 | . 23 | 24 |Paragraph after
25 | . 26 | 27 | . 28 | Paragraph before 29 | 30 | @[example](video-123) 31 | 32 | Paragraph after 33 | . 34 |Paragraph before
35 | 36 |Paragraph after
37 | . 38 | 39 | . 40 | > Inside block quote: 41 | > 42 | > @[example](video-123) 43 | . 44 |45 |48 | . 49 | 50 | . 51 | > > > Inside multiple block quotes: 52 | > > > 53 | > > > @[example](video-123) 54 | . 55 |Inside block quote:
46 | 47 |
56 |63 | . 64 | 65 | 66 | Coverage. Missing service name 67 | 68 | . 69 | @[](x) 70 | . 71 | 72 | . 73 | 74 | 75 | Coverage. Missing embed reference (consistent with images) 76 | 77 | . 78 | @[example]() 79 | . 80 | 81 | . 82 | 83 | 84 | Coverage. Extra spacing inside tag syntax 85 | 86 | . 87 | @[ example ]( video-123 ) 88 | . 89 | 90 | . 91 | 92 | . 93 | @[example]( 94 | video-123 ) 95 | . 96 | 97 | . 98 | 99 | . 100 | @[example]( 101 | video-123 102 | ) 103 | . 104 | 105 | . 106 | 107 | . 108 | @[ 109 | example 110 | ]( 111 | video-123 112 | ) 113 | . 114 | 115 | . 116 | 117 | 118 | Coverage. Invalid extra spacing inside tag syntax (consistent with images) 119 | 120 | . 121 | @[ 122 | example 123 | ] 124 | ( 125 | video-123 126 | ) 127 | . 128 |57 |62 |58 |61 |Inside multiple block quotes:
59 | 60 |
@[ 129 | example 130 | ] 131 | ( 132 | video-123 133 | )
134 | . 135 | 136 | 137 | Coverage. Trailing whitespace after embed tag \/ 138 | . 139 | @[example](video-123) 140 | . 141 | 142 | . 143 | 144 | 145 | Coverage. Usage of unknown service 146 | 147 | . 148 | @[unknown-service](video-123) 149 | . 150 | 151 | . 152 | 153 | 154 | Coverage. Invalid inline tag syntax 155 | 156 | . 157 | @[]example(video-123) 158 | . 159 |@[]example(video-123)
160 | . 161 | 162 | . 163 | @[(example] 164 | . 165 |@[(example]
166 | . 167 | 168 | . 169 | text before @[example](video-123) 170 | . 171 |text before @example
172 | . 173 | 174 | . 175 | @[example](video-123) text after 176 | . 177 |@example text after
178 | . 179 | 180 | . 181 | Line above embed tag 182 | @[example](video-123) 183 | . 184 |Line above embed tag 185 | @example
186 | . 187 | 188 | . 189 | @[example](video-123) 190 | Line below embed tag 191 | . 192 |@example 193 | Line below embed tag
194 | . 195 | 196 | . 197 | Line above embed tag 198 | @[example](video-123) 199 | Line below embed tag 200 | . 201 |Line above embed tag 202 | @example 203 | Line below embed tag
204 | . 205 | 206 | . 207 | Code snippet: 208 | 209 | @[example](video-123) 210 | . 211 |Code snippet:
212 |@[example](video-123)
213 |
214 | .
215 |
--------------------------------------------------------------------------------
/test/fixtures/without-allowfullscreen-attributes.txt:
--------------------------------------------------------------------------------
1 | Coverage. Without 'allowfullscreen' attributes
2 |
3 | .
4 | @[example](video-123)
5 | .
6 |
7 | .
8 |
9 | .
10 | @[example](x)
11 | .
12 |
13 | .
14 |
--------------------------------------------------------------------------------
/test/fixtures/without-size-attributes.txt:
--------------------------------------------------------------------------------
1 | Coverage. Without 'width' and 'height' attributes
2 |
3 | .
4 | @[example](video-123)
5 | .
6 |
7 | .
8 |
9 | .
10 | @[example](x)
11 | .
12 |
13 | .
14 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Rotorz Limited and portions by original markdown-it-video authors
2 | // Licensed under the MIT license. See LICENSE file in the project root.
3 |
4 | "use strict";
5 |
6 | const path = require("path");
7 | const generate = require("markdown-it-testgen");
8 |
9 | const CustomService = require("./fakes/CustomService");
10 |
11 |
12 | function setupMarkdownIt() {
13 | return require("markdown-it")({
14 | html: true,
15 | linkify: true,
16 | typography: true
17 | });
18 | }
19 |
20 | function testFixture(fixtureName, options) {
21 | let md = setupMarkdownIt().use(require("../lib"), options);
22 | generate(path.join(__dirname, `fixtures/${fixtureName}.txt`), md);
23 | }
24 |
25 | function testFixtureWithExampleService(fixtureName, options) {
26 | let vanillaOptions = {
27 | services: {
28 | // Testing with fake service to avoid coupling with specific services.
29 | "example": CustomService
30 | }
31 | };
32 | testFixture(fixtureName, Object.assign({}, vanillaOptions, options));
33 | }
34 |
35 |
36 | describe("markdown-it-video", function () {
37 |
38 | describe("vanilla embed tag syntax", function () {
39 | testFixtureWithExampleService("tag-syntax");
40 | });
41 |
42 | describe("with custom class names", function () {
43 | testFixtureWithExampleService("custom-class-names", {
44 | containerClassName: "custom-container",
45 | serviceClassPrefix: "custom-container--service-"
46 | });
47 | });
48 |
49 | describe("without size attributes", function () {
50 | testFixtureWithExampleService("without-size-attributes", {
51 | example: { width: 123, height: 456 },
52 | outputPlayerSize: false
53 | });
54 | });
55 |
56 | describe("without allowfullscreen attributes", function () {
57 | testFixtureWithExampleService("without-allowfullscreen-attributes", {
58 | allowFullScreen: false
59 | });
60 | });
61 |
62 | describe("with filtered url", function () {
63 | testFixtureWithExampleService("filtered-url", {
64 | filterUrl: (url, serviceName, videoID, options) => `${url}?a=${serviceName}&b=${videoID}&c=${options.containerClassName}`
65 | });
66 | });
67 |
68 | describe("providing custom services", function () {
69 | testFixture("custom-service", {
70 | services: {
71 | "custom": CustomService,
72 | "youtube": CustomService
73 | },
74 | custom: {
75 | magicNumber: 123
76 | }
77 | });
78 | });
79 |
80 | for (let serviceName of [ "prezi", "vimeo", "vine", "youtube" ]) {
81 | describe(`service: ${serviceName}`, function () {
82 | testFixture(`services/${serviceName}`);
83 | });
84 | }
85 |
86 | });
87 |
--------------------------------------------------------------------------------