diff --git a/README.md b/README.md index d3572bd..9039a38 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Option | Type | Default | Descrip `containerClassName` | `string` \| `null` | `'block-embed'` | Class name for image container element. `serviceClassPrefix` | `string` | `'block-embed-service-'` | Prefix for service name in CSS class. `outputPlayerSize` | `boolean` | `true` | Indicates if 'width' and 'height' attributes are written to output. +`allowInstancePlayerSizeDefinition` | `boolean` | `false` | Indicates whether individual player instances found within content may override the default size. Used by e.g.: `@[youtube](lJIrF4YjHfQ##400x300)` `allowFullScreen` | `boolean` | `true` | Indicates whether embed iframe should be allowed to enter full screen mode. `filterUrl` | `function` \| `null` | `null` | A function that customizes url output. Signature: `function (url: string, serviceName: string, videoID: string, options: object): string` | | | diff --git a/lib/PluginEnvironment.js b/lib/PluginEnvironment.js index 1ead8c6..5c04d9a 100644 --- a/lib/PluginEnvironment.js +++ b/lib/PluginEnvironment.js @@ -41,6 +41,7 @@ class PluginEnvironment { containerClassName: "block-embed", serviceClassPrefix: "block-embed-service-", outputPlayerSize: true, + allowInstancePlayerSizeDefinition: false, allowFullScreen: true, filterUrl: null }; diff --git a/lib/renderer.js b/lib/renderer.js index cf86fc3..e672f3f 100644 --- a/lib/renderer.js +++ b/lib/renderer.js @@ -9,8 +9,9 @@ function renderer(tokens, idx, options, _env) { let service = videoToken.info.service; let videoID = videoToken.info.videoID; + let videoDimensionsInfo = videoToken.info.videoDimensionsInfo; - return service.getEmbedCode(videoID); + return service.getEmbedCode(videoID, videoDimensionsInfo); } diff --git a/lib/services/VideoServiceBase.js b/lib/services/VideoServiceBase.js index 6defdce..6cf2875 100644 --- a/lib/services/VideoServiceBase.js +++ b/lib/services/VideoServiceBase.js @@ -37,7 +37,7 @@ class VideoServiceBase { return filterUrlDelegate(videoUrl, this.name, videoID, this.env.options); } - getEmbedCode(videoID) { + getEmbedCode(videoID, videoDimensionsInfo) { let containerClassNames = []; if (this.env.options.containerClassName) { containerClassNames.push(this.env.options.containerClassName); @@ -51,12 +51,16 @@ class VideoServiceBase { iframeAttributeList.push([ "src", this.getFilteredVideoUrl(videoID) ]); iframeAttributeList.push([ "frameborder", 0 ]); + // collect default player dimensions from config and allow override from player instance, if available + let playerWidth = videoDimensionsInfo.Width || this.options.width; + let playerHeight = videoDimensionsInfo.Height || this.options.height; + // ouptut width and height if we are configured to do so (and values are valid) if (this.env.options.outputPlayerSize === true) { - if (this.options.width !== undefined && this.options.width !== null) { - iframeAttributeList.push([ "width", this.options.width ]); + if (playerWidth !== undefined && playerWidth !== null) { + iframeAttributeList.push([ "width", playerWidth ]); } - if (this.options.height !== undefined && this.options.height !== null) { - iframeAttributeList.push([ "height", this.options.height ]); + if (playerHeight !== undefined && playerHeight !== null) { + iframeAttributeList.push([ "height", playerHeight ]); } } diff --git a/lib/tokenizer.js b/lib/tokenizer.js index 7d58938..65fc530 100644 --- a/lib/tokenizer.js +++ b/lib/tokenizer.js @@ -90,13 +90,33 @@ function tokenizer(state, startLine, endLine, silent) { if (!silent) { let token = state.push("video", "div", 0); + // object for storing and passing what we know about the player instance dimensions + let videoDimensionsInfo = {}; + // configuration option allows us to parse player size for individual player instances + if (this.options.allowInstancePlayerSizeDefinition === true) { + const videoReferenceComponents = videoReference.split("##"); + if (videoReferenceComponents.length > 1) { + // first component is url / ID + videoReference = videoReferenceComponents[0]; + // second component is size information + // either a width/height or a single aspect ratio value (as height percentage of width) + // find if is a string split by 'x' i.e. XXXxYYY + const videoDimensionsComponents = videoReferenceComponents[1].split("x"); + if (videoDimensionsComponents.length === 2) { + // should be width and height + videoDimensionsInfo.Width = videoDimensionsComponents[0]; + videoDimensionsInfo.Height = videoDimensionsComponents[1]; + } + } + } token.markup = state.src.slice(startPos, pointer.pos); token.block = true; token.info = { serviceName: serviceName, service: service, videoReference: videoReference, - videoID: service.extractVideoID(videoReference) + videoID: service.extractVideoID(videoReference), + videoDimensionsInfo: videoDimensionsInfo }; token.map = [ startLine, pointer.line + 1 ]; diff --git a/test/fixtures/instance-size-attributes.txt b/test/fixtures/instance-size-attributes.txt new file mode 100644 index 0000000..ff9f3d3 --- /dev/null +++ b/test/fixtures/instance-size-attributes.txt @@ -0,0 +1,13 @@ +Coverage. Instance size attributes + +. +@[vimeo](19706846##123x45) +. +
+. + +. +@[example](x##5x6) +. +
+. diff --git a/test/test.js b/test/test.js index a7f5c12..852fc1e 100644 --- a/test/test.js +++ b/test/test.js @@ -65,6 +65,13 @@ describe("markdown-it-video", function () { }); }); + describe("with instance size attributes", function () { + testFixtureWithExampleService("instance-size-attributes", { + allowFullScreen: true, + allowInstancePlayerSizeDefinition: true + }); + }); + describe("providing custom services", function () { testFixture("custom-service", { services: {