diff --git a/src/cleanMarkup.js b/src/cleanMarkup.js index 9775b96..3db9f4a 100644 --- a/src/cleanMarkup.js +++ b/src/cleanMarkup.js @@ -1,8 +1,10 @@ -import m from 'mithril/render/hyperscript' +import hyperscript from 'mithril/render/hyperscript' import render from './lib/mithril-node-render' import isNode from 'detect-node' +const m = hyperscript + import fetch from './fetch' import { tidyOptions, youtubeKey } from './constants' @@ -71,7 +73,7 @@ export function cleanMarkup (html, callback) { m('img', {src: thumbnail, alt: title}) ), m('figcaption', m('a', {href: youtubeUrl}, caption)) - ])) + ]), {strict: true}) }) html = html.replace('
', '
') diff --git a/src/lib/mithril-node-render.js b/src/lib/mithril-node-render.js index b3b63cc..8a2e0c6 100644 --- a/src/lib/mithril-node-render.js +++ b/src/lib/mithril-node-render.js @@ -1,5 +1,9 @@ 'use strict' +var VOID_TAGS = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', + 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', + 'wbr', '!doctype'] + function isArray (thing) { return Object.prototype.toString.call(thing) === '[object Array]' } @@ -21,9 +25,9 @@ function escapeHtml (s, replaceDoubleQuote) { if (typeof (s) !== 'string') { s = s + '' } - s = s.replace(/&/g, '&').replace(//g, '>') + s = s.replace(/\&/g, '&').replace(//g, '>') if (replaceDoubleQuote) { - return s.replace(/"/g, '"') + return s.replace(/\"/g, '"') } return s } @@ -65,12 +69,15 @@ function createAttrString (view, escapeAttributeValue) { }).join('') } -function createChildrenContent (view) { +function createChildrenContent (view, options) { + if (view.text != null) { + return options.escapeString(view.text) + } if (isArray(view.children) && !view.children.length) { return '' } - return render(view.children) + return render(view.children, options) } function render (view, options) { @@ -78,7 +85,8 @@ function render (view, options) { var defaultOptions = { escapeAttributeValue: escapeHtml, - escapeString: escapeHtml + escapeString: escapeHtml, + strict: false } Object.keys(defaultOptions).forEach(function (key) { @@ -104,21 +112,31 @@ function render (view, options) { } // compontent - if (view.view) { - var scope = view.controller ? new view.controller() : {} - var result = render(view.view(scope), options) - if (scope.onunload) { - scope.onunload() + if (typeof view.tag === 'object' && view.tag.view) { + var compontent = view.tag + var node = view + if (compontent.oninit) { + compontent.oninit(node) + } + var result = render(compontent.view(node), options) + if (compontent.onremove) { + compontent.onremove(node) } return result } - if (view.$trusted) { - return '' + view + if (view.tag === '<') { + return '' + view.children } - var children = createChildrenContent(view) - if (!children) { - return '<' + view.tag + createAttrString(view, options.escapeAttributeValue) + '/>' + var children = createChildrenContent(view, options) + if (view.tag === '#') { + return options.escapeString(children) + } + if (view.tag === '[') { + return '' + children + } + if (!children && (options.strict || VOID_TAGS.indexOf(view.tag.toLowerCase()) >= 0)) { + return '<' + view.tag + createAttrString(view, options.escapeAttributeValue) + (options.strict ? '/' : '') + '>' } return [ '<', view.tag, createAttrString(view, options.escapeAttributeValue), '>', diff --git a/src/templates.js b/src/templates.js index 7e43186..9d0dc4d 100644 --- a/src/templates.js +++ b/src/templates.js @@ -1,5 +1,5 @@ -import m from 'mithril/render/hyperscript' +import hyperscript from 'mithril/render/hyperscript' import trust from 'mithril/render/trust' import render from './lib/mithril-node-render' import { pd as pretty } from 'pretty-data' @@ -8,6 +8,9 @@ import zeroFill from 'zero-fill' import { cleanMarkup } from './cleanMarkup' import { NS } from './constants' +const m = hyperscript +m.trust = trust + function nth (d) { if (d > 3 && d < 21) return 'th' switch (d % 10) { @@ -42,8 +45,8 @@ export function createChapter (ch, html, callback) { chapter = chapter.substring(0, pos) let sections = [ - m('div#chapter_container', trust(chapter)), - authorNotes ? m('div#author_notes', {className: authorNotesPos < chapterPos ? 'top' : 'bottom'}, trust(authorNotes)) : null + m('div#chapter_container', m.trust(chapter)), + authorNotes ? m('div#author_notes', {className: authorNotesPos < chapterPos ? 'top' : 'bottom'}, m.trust(authorNotes)) : null ] if (authorNotes && authorNotesPos < chapterPos) { @@ -59,7 +62,7 @@ export function createChapter (ch, html, callback) { ]), m('body', sections) ]) - ) + , {strict: true}) cleanMarkup(chapterPage, (html) => { callback(html) @@ -124,7 +127,7 @@ export function createOpf (ffc) { m('reference', {type: 'toc', title: 'Contents', href: 'Text/nav.xhtml'}) ]) ]) - )) + , {strict: true})) // console.log(contentOpf) return contentOpf } @@ -157,7 +160,7 @@ export function createNcx (ffc) { [ch.title, 'Text/chapter_' + zeroFill(3, num + 1) + '.xhtml'] )))) ]) - )) + , {strict: true})) // console.log(tocNcx) return tocNcx } @@ -181,7 +184,7 @@ export function createNav (ffc) { ]) ]) ]) - )) + , {strict: true})) // console.log(navDocument) return navDocument } @@ -210,7 +213,7 @@ export function createCoverPage (coverFilename, w, h) { ]), m('body', {'epub:type': 'cover'}, body) ]) - )) + , {strict: true})) // console.log(coverPage) return coverPage } @@ -250,7 +253,7 @@ export function createTitlePage (ffc) { 'This story is a sequel to ', m('a', {href: ffc.storyInfo.prequel.url}, ffc.storyInfo.prequel.title) ]), m('hr')] : null, - m('#description', trust(ffc.storyInfo.description)), + m('#description', m.trust(ffc.storyInfo.description)), m('hr'), m('.extra_story_data', [ ffc.storyInfo.publishDate && dateBox('First Published', new Date(ffc.storyInfo.publishDate * 1000)), @@ -261,7 +264,7 @@ export function createTitlePage (ffc) { ]) ]) ]) - )) + , {strict: true})) // console.log(titlePage) return titlePage }