var Q = require('q'); var _ = require('lodash'); var path = require('path'); var cheerio = require('cheerio'); var links = require('./links'); var imgUtils = require('./images'); var fs = require('./fs'); function replaceText($, el, search, replace, text_only ) { return $(el).each(function(){ var node = this.firstChild, val, new_val, // Elements to be removed at the end. remove = []; // Only continue if firstChild exists. if ( node ) { // Loop over all childNodes. do { // Only process text nodes. if ( node.nodeType === 3 ) { // The original node value. val = node.nodeValue; // The new value. new_val = val.replace( search, replace ); // Only replace text if the new value is actually different! if ( new_val !== val ) { if ( !text_only && /\|\:])/g, "\\$1"); }; // Adapt an html snippet to be relative to a base folder function normalizeHtml(src, options) { var $ = cheerio.load(src); var toConvert = []; $("img").each(function() { var src = $(this).attr("src"); // Transform as absolute if (links.isRelative(src)) { src = links.toAbsolute(src, options.base, options.output); } // Convert if needed if (options.convertImages) { var ext = path.extname(src); if (_.contains(imgUtils.INVALID, ext)) { // Replace extension var dest = path.join(path.dirname(src), path.basename(src, ext)+".png"); // Absolute with input dest = path.resolve(options.book.root, dest); // Get a name that doesn't exists dest = fs.getUniqueFilename(dest); // Reset as relative to book dest = path.relative(options.book.root, dest); options.book.log.debug.ln("detect invalid image (will be converted to png):", src); toConvert.push({ source: src, dest: dest }); src = dest; } } $(this).attr("src", src); }); $("a").each(function() { var href = $(this).attr("href"); if (links.isRelative(href)) { var absolutePath = path.join(options.base, href); // If is in navigation relative: change extsnio nto be .html if (options.navigation[absolutePath]) href = links.changeExtension(href, ".html"); // Transform as absolute href = links.toAbsolute(href, options.base, options.output); } else { $(this).attr("target", "_blank"); } // Transform extension $(this).attr("href", href); }); // Replace glossayr terms _.each(options.glossary, function(term) { var r = new RegExp( "\\b(" + pregQuote(term.name.toLowerCase()) + ")\\b" , 'gi' ); var includedInFiles = false; $("*").each(function() { replaceText($, this, r, function(match) { if (!includedInFiles) { includedInFiles = true; term.files = term.files || []; term.files.push(options.navigation[options.input]); } return ""+match+""; }); }); }); return { html: $.html(), images: toConvert }; }; // Convert svg images to png function convertImages(images, options) { return _.reduce(images, function(prev, image) { return prev.then(function() { var imgin = path.resolve(options.book.root, image.source); var imgout = path.resolve(options.book.options.output, image.dest); options.book.log.debug("convert image", image.source, "to", image.dest, "..."); return imgUtils.convert(imgin, imgout) .then(function() { options.book.log.debug.ok(); }, function() { options.book.log.debug.fail(); }); }); }, Q()); }; // Adapt page content to be relative to a base folder function normalizePage(sections, options) { options = _.defaults(options || {}, { // Current book book: null, // Do we need to convert svg? convertImages: false, // Current file path input: ".", // Navigation to use to transform path navigation: {}, // Directory parent of the file currently in rendering process base: "./", // Directory parent from the html output output: "./", // Glossary terms glossary: [] }); // List of images to convert var toConvert = []; sections = _.map(sections, function(section) { if (section.type != "normal") return section; var out = normalizeHtml(section.content, options);; toConvert = toConvert.concat(out.images); section.content = out.html; return section; }); return Q() .then(function() { return convertImages(toConvert, options); }) .thenResolve(sections); }; // Extract text from sections function extractText(sections) { return _.reduce(sections, function(prev, section) { if (section.type != "normal") return prev; var $ = cheerio.load(section.content); $("*").each(function() { prev = prev+" "+$(this).text(); }); return prev; }, ""); }; module.exports = { normalize: normalizePage, extractText: extractText };