previewer.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. 'use strict';
  2. const YAML = require('yamljs');
  3. const Hexo = require('./hexo');
  4. const __ = require('lodash');
  5. const Promise = require('bluebird');
  6. const url = require('url');
  7. var rEscapeContent = /<escape(?:[^>]*)>([\s\S]*?)<\/escape>/g;
  8. var rSwigVar = /\{\{[\s\S]*?\}\}/g;
  9. var rSwigComment = /\{#[\s\S]*?#\}/g;
  10. var rSwigBlock = /\{%[\s\S]*?%\}/g;
  11. var rSwigFullBlock = /\{% *(.+?)(?: *| +.*)%\}[\s\S]+?\{% *end\1 *%\}/g;
  12. var placeholder = '\uFFFC';
  13. var rPlaceholder = /(?:<|&lt;)\!--\uFFFC(\d+)--(?:>|&gt;)/g;
  14. global.lodash = require('lodash');
  15. global.ctx = global.hexo = new Hexo();
  16. moeApp.setHexo(hexo);
  17. function Previewer() {
  18. }
  19. Previewer.prototype.render = function (content, MoeMark, options, callback) {
  20. hexo.isLoadedTag || hexo.loadTags();
  21. var data = {
  22. highlightEx: hexo.config.highlightEx,
  23. content: content
  24. };
  25. var cache = [];
  26. var tag = hexo.extend.tag;
  27. function escapeContent(str) {
  28. return '<!--' + placeholder + (cache.push(str) - 1) + '-->';
  29. }
  30. function tryFilterHeader() {
  31. data.content = data.content.replace(/^---+([\w\W]+?)---+/, function () {
  32. data = __.extend(data, YAML.parse(arguments[1]))
  33. return '';
  34. });
  35. }
  36. function before_post_render() {
  37. hexo.execFilterSync('before_post_render', data, {context: hexo});
  38. }
  39. function escapeTag() {
  40. data.content = data.content.toString()
  41. .replace(rEscapeContent, escapeContent)
  42. .replace(rSwigFullBlock, escapeContent)
  43. .replace(rSwigBlock, escapeContent)
  44. .replace(rSwigComment, '')
  45. .replace(rSwigVar, escapeContent);
  46. }
  47. function markdownContent() {
  48. MoeMark(data.content, options, function (err, content) {
  49. data.content = content;
  50. });
  51. }
  52. function backTag() {
  53. // Replace cache data with real contents
  54. data.content = data.content.replace(rPlaceholder, function () {
  55. return cache[arguments[1]];
  56. });
  57. // Render with Nunjucks
  58. data.content = tag.render(data.content, data);
  59. }
  60. function after_post_render() {
  61. hexo.execFilter('after_post_render', data, {context: hexo});
  62. }
  63. function checkRes() {
  64. let contentHtml = $('<div></div>');
  65. contentHtml.html(data.content);
  66. let imgs = contentHtml.find('img') || [];
  67. for (let img of imgs) {
  68. let src = img.getAttribute('src');
  69. let srcLocal = '';
  70. if (src && (url.parse(src).protocol === null)) {
  71. if (!fs.existsSync(src)) {
  72. srcLocal = imgManager.resolvePath(src)|| '';
  73. //首先查询用户设置目录
  74. if (!srcLocal && moeApp.config.get('image-source-center')) {
  75. srcLocal = path.join(moeApp.config.get('image-source-center'), src);
  76. if (!fs.existsSync(srcLocal))
  77. srcLocal = '';
  78. }
  79. //再查询Hexo资源目录
  80. if (!srcLocal && moeApp.useHexo && hexo.config.__basedir) {
  81. srcLocal = path.join(hexo.config.__basedir, 'source', src);
  82. if (!fs.existsSync(srcLocal))
  83. srcLocal = '';
  84. }
  85. //最后查询文档所在目录
  86. if (!srcLocal)
  87. srcLocal = path.join(hexoWindow.directory, src);
  88. //最后查询文档所在目录
  89. if (!srcLocal)
  90. srcLocal = path.join(moeApp.storePath,'images');
  91. img.id = src;
  92. img.setAttribute('localImg', true);
  93. src = url.resolve('file://', srcLocal);
  94. }
  95. }
  96. img.setAttribute('src', src);
  97. }
  98. data.content = contentHtml.html();
  99. }
  100. if (moeApp.useHexo) {
  101. Promise.resolve()
  102. .then(tryFilterHeader).catch(console.log)
  103. .then(before_post_render).catch(console.log)
  104. .then(escapeTag).catch(console.log)
  105. .then(markdownContent, markdownContent).catch(console.log)
  106. .then(backTag).catch(console.log)
  107. .then(after_post_render).catch(console.log)
  108. .then(checkRes).catch(console.log)
  109. .then(function () {
  110. callback(data.content)
  111. })
  112. } else {
  113. Promise.resolve()
  114. .then(markdownContent, markdownContent).catch(console.log)
  115. .then(checkRes).catch(console.log)
  116. .then(function () {
  117. callback(data.content)
  118. })
  119. }
  120. };
  121. module.exports = Previewer;