Skip to content

Commit 9e2cab1

Browse files
committed
Support overriding the built-in render function
... and therefore drop explicit support for rendering with Handlebars templates.
1 parent 0126aca commit 9e2cab1

File tree

4 files changed

+97
-50
lines changed

4 files changed

+97
-50
lines changed

Changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## Next release
2+
3+
- Drop explicit support for Handlebars
4+
- Instead support overriding of a built-in render function
5+
16
## 0.5.0
27

38
- Don't depend on lodash anymore (#6)

README.md

+49-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# markdown-it-html5-embed
2-
This is a plugin for markdown-it which adds support for embedding audio/video in the HTML5 way, by using <video>/<audio> tags.
2+
This is a plugin for markdown-it which adds support for embedding audio/video in the HTML5 way, by using `<video>`/`<audio>` tags.
33

44
## Install
55

@@ -153,22 +153,48 @@ Here is a description of the content: test link
153153
</video>
154154
```
155155

156-
### Handlebars templates
156+
### Alternative render functions
157157

158158
Options:
159159
```js
160-
templateName: "media-embed_tpl"
160+
renderFn: function(properties, attributes) {/* ... */}
161161
```
162162

163-
If you want to render media embed using Handlebars template, you can set `templateName` option and the plugin will try to find
164-
the template using global `HandlebarsTemplates` array and render using this template.
163+
By default the plugin renders media with just plain html media tags. However you may want to customize media rendering appropriate for your front-end framework or approach.
164+
165+
You can do this by defining a custom rendering function.
166+
167+
For example, here is a function you can use to render a media embed with Handlebars:
168+
169+
```js
170+
function handleBarsRenderFn(properties, attributes) {
171+
return HandlebarsTemplates[this]({
172+
media_type: properties.mediaType,
173+
attributes: attributes,
174+
mimetype: properties.mimeType,
175+
source_url: properties.url,
176+
title: properties.title,
177+
fallback: properties.fallback,
178+
needs_cover: properties.mediaType === "video"
179+
});
180+
}
181+
```
165182

166183
You can access the descriptive content (e.g., "test link" above) via the
167184
`{{title}}` variable. It will be set to "Untitled video" or "Untitled audio"
168185
if no title was set. You can access the fallback text ("Your browser does not
169186
support ...") via the `{{fallback}}` variable. See below for how to
170187
customize/translate the text.
171188

189+
Then you can just set this function as a `renderFn` option on the plugin initialization:
190+
191+
```js
192+
// ... options setting code ...
193+
renderFn: handleBarsRenderFn.bind("templateName"),
194+
```
195+
196+
More on render function arguments see at the [`renderFn`](#renderFn) option description.
197+
172198
## Options reference
173199

174200
#### attributes
@@ -232,13 +258,27 @@ The argument is a result of regexp match, and has a structure similar to that on
232258

233259
Default: `undefined`, allow everything.
234260

235-
#### templateName
261+
#### renderFn
262+
263+
Function. Override the built-in render function. The function accepts exactly 2 arguments.
264+
265+
```js
266+
function customRenderFn(properties, attributes) { /* ... */ }
267+
```
268+
269+
`properties` is an `Object` which contains properties of a detected and parsed media reference. `properties` `Object` contains following keys:
236270

237-
String. If the plugin is used in a Rails asset pipeline along with the handlebars_assets gem, then you can use a Handlebars template to control the output of the plugin. This option specifies the name of the template to use, which will be picked from the HandlebarsTemplates array.
271+
key|type|meaning
272+
-|-
273+
fallback|String|Fallback text for the case when the client (e.g. browser) doesn't support HTML5 `<audio>`/`<video>`
274+
mediaType|String|`"video"` or `"audio"`
275+
mimeType|String|Media mime type resolved by a URL ending (media file extension)
276+
title|String|Title for the media (which could be optionally provided in the markup)
277+
url|String|Media URL
238278

239-
If HandlebarsTemplates is undefined, this option is ignored.
279+
`attributes` is the attributes passed from the plugin options, see [`attributes`](#attributes) option description.
240280

241-
Default: `undefined`, don't use Handlebars.
281+
A custom render function must return a `String` value which contains HTML for embedding at the appropriate place.
242282

243283
#### useImageSyntax
244284

lib/index.js

+15-32
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var Mimoza = require('mimoza');
1515
// you have to provide a translation function via options.translateFn.
1616
//
1717
// The "untitled video" / "untitled audio" messages are only relevant to usage
18-
// inside Handlebars templates, where you can access the title between [] as
18+
// inside alternative render functions, where you can access the title between [] as
1919
// {{title}}, and this text is used if no title is provided.
2020
var messages = {
2121
en: {
@@ -69,7 +69,7 @@ function parseToken(tokens, idx, env) {
6969
}
7070

7171
if (parsed.mediaType !== null) {
72-
// For use as titles in handlebars templates, we store the description
72+
// For use as titles in alternative render functions, we store the description
7373
// in parsed.title. For use as fallback text, we store it in parsed.fallback
7474
// alongside the standard fallback text.
7575
parsed.fallback = translate({
@@ -99,35 +99,14 @@ function isAllowedMimeType(parsed, options) {
9999
(!options.isAllowedMimeType || options.isAllowedMimeType([parsed.mimeType, parsed.mediaType]));
100100
}
101101

102-
function renderMediaEmbed(parsed, options) {
103-
var attributes = options.attributes[parsed.mediaType];
104-
var useHandlebars = false;
102+
function renderMediaEmbed(parsed, mediaAttributes) {
103+
var attributes = mediaAttributes[parsed.mediaType];
105104

106-
if (options.templateName) {
107-
if (typeof HandlebarsTemplates === "undefined") {
108-
console.log("handlebars_assets is not on the assets pipeline; fall back to the usual mode");
109-
} else {
110-
useHandlebars = true;
111-
}
112-
}
113-
114-
if (useHandlebars) {
115-
return HandlebarsTemplates[options.templateName]({
116-
media_type: parsed.mediaType,
117-
attributes: attributes,
118-
mimetype: parsed.mimeType,
119-
source_url: parsed.url,
120-
title: parsed.title,
121-
fallback: parsed.fallback,
122-
needs_cover: parsed.mediaType === "video"
123-
});
124-
} else {
125-
return ['<' + parsed.mediaType + ' ' + attributes + '>',
126-
'<source type="' + parsed.mimeType + '" src="' + parsed.url + '"></source>',
127-
parsed.fallback,
128-
'</' + parsed.mediaType + '>'
129-
].join('\n');
130-
}
105+
return ['<' + parsed.mediaType + ' ' + attributes + '>',
106+
'<source type="' + parsed.mimeType + '" src="' + parsed.url + '"></source>',
107+
parsed.fallback,
108+
'</' + parsed.mediaType + '>'
109+
].join('\n');
131110
}
132111

133112
function html5EmbedRenderer(tokens, idx, options, env, renderer, defaultRender) {
@@ -141,7 +120,7 @@ function html5EmbedRenderer(tokens, idx, options, env, renderer, defaultRender)
141120
clearTokens(tokens, idx + 1);
142121
}
143122

144-
return renderMediaEmbed(parsed, options.html5embed);
123+
return renderMediaEmbed(parsed, options.html5embed.attributes);
145124
}
146125

147126
function forEachLinkOpen(state, action) {
@@ -244,7 +223,7 @@ module.exports = function html5_embed_plugin(md, options) {
244223
return;
245224
}
246225

247-
result += renderMediaEmbed(parsed, options);
226+
result += renderMediaEmbed(parsed, options.attributes);
248227
});
249228
if (result.length) {
250229
result += "\n";
@@ -290,4 +269,8 @@ module.exports = function html5_embed_plugin(md, options) {
290269
translate = typeof options.translateFn == 'function' ?
291270
options.translateFn.bind(options.messages) :
292271
translate.bind(options.messages);
272+
273+
if (typeof options.renderFn == 'function') {
274+
renderMediaEmbed = options.renderFn;
275+
}
293276
};

test/test.js

+28-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
var path = require('path');
44
var generate = require('markdown-it-testgen');
55

6+
function clearBindings() {
7+
// Don't re-use cached function with old bindings
8+
delete require.cache[require.resolve('../lib')];
9+
}
10+
611
// For testing custom messages and translations
712
var customMessages = {
813
en: {
@@ -58,15 +63,28 @@ describe('markdown-it-html5-embed mime type filtering', function() {
5863
});
5964

6065
describe('markdown-it-html5-embed with handlebars', function() {
61-
before(function() {
62-
var Handlebars = require("handlebars");
63-
global.HandlebarsTemplates = { "template": Handlebars.compile("<h1>{{title}}</h1><div class=\"body\"><{{media_type}} {{attributes}}><source type=\"{{mimetype}}\" src=\"{{source_url}}\"/></{{media_type}}></div>") };
64-
});
66+
clearBindings();
67+
68+
var Handlebars = require("handlebars");
69+
global.HandlebarsTemplates = { "template": Handlebars.compile("<h1>{{title}}</h1><div class=\"body\"><{{media_type}} {{attributes}}><source type=\"{{mimetype}}\" src=\"{{source_url}}\"/></{{media_type}}></div>") };
70+
71+
function handleBarsRenderFn(parsed, mediaAttributes) {
72+
var attributes = mediaAttributes[parsed.mediaType];
73+
return HandlebarsTemplates[this]({
74+
media_type: parsed.mediaType,
75+
attributes: attributes,
76+
mimetype: parsed.mimeType,
77+
source_url: parsed.url,
78+
title: parsed.title,
79+
fallback: parsed.fallback,
80+
needs_cover: parsed.mediaType === "video"
81+
});
82+
}
6583

6684
var option = {
6785
html5embed: {
6886
useLinkSyntax: true,
69-
templateName: "template",
87+
renderFn: handleBarsRenderFn.bind("template"),
7088
attributes: {
7189
"video": "",
7290
"audio": ""
@@ -77,6 +95,8 @@ describe('markdown-it-html5-embed with handlebars', function() {
7795
var md = require('markdown-it')().use(require('../lib'), option);
7896

7997
generate(path.join(__dirname, 'fixtures/with-handlebars.txt'), md);
98+
99+
clearBindings();
80100
});
81101

82102
describe("embedding with [[html5embed]] clause", function() {
@@ -115,8 +135,8 @@ describe('markdown-it-html5-embed with image syntax + custom messages', function
115135
messages: customMessages
116136
}
117137
};
118-
// Don't re-use cached function with old bindings
119-
delete require.cache[require.resolve('../lib')];
138+
139+
clearBindings();
120140

121141
var md = require('markdown-it')().use(require('../lib'), option);
122142
generate(path.join(__dirname, 'fixtures/image-syntax-custom-messages.txt'), md);
@@ -145,8 +165,7 @@ describe('markdown-it-html5-embed with image syntax + custom translation fn', fu
145165
}
146166
};
147167

148-
// Don't re-use cached function with old bindings
149-
delete require.cache[require.resolve('../lib')];
168+
clearBindings();
150169

151170
var md = require('markdown-it')().use(require('../lib'), option);
152171
var env = { language: 'de' };

0 commit comments

Comments
 (0)