下载CSDN、简书、掘金、博客园、微信公众号、知乎专栏、脚本之家、51CTO、程序员大本营、吾爱破解、B站、思否、轻识、腾讯云、阿里云、华为云等文章保存为Word/Markdown文件

下载保存博客文章为word/markdown,已支持CSDN、简书、掘金、知乎专栏、博客园、微信公众号、脚本之家、51CTO、程序员大本营、吾爱破解、腾讯云、阿里云、华为云、B站专栏、思否、轻识、百家号、百度经验、码农教程等,脚本仅限学习,请大家尊重版权。

目前为 2023-10-31 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 下载CSDN、简书、掘金、博客园、微信公众号、知乎专栏、脚本之家、51CTO、程序员大本营、吾爱破解、B站、思否、轻识、腾讯云、阿里云、华为云等文章保存为Word/Markdown文件
  3. // @namespace https://waahah.xyz/
  4. // @version 0.1.9
  5. // @description 下载保存博客文章为word/markdown,已支持CSDN、简书、掘金、知乎专栏、博客园、微信公众号、脚本之家、51CTO、程序员大本营、吾爱破解、腾讯云、阿里云、华为云、B站专栏、思否、轻识、百家号、百度经验、码农教程等,脚本仅限学习,请大家尊重版权。
  6. // @author waahah
  7. // @require https://unpkg.com/html-docx-js/dist/html-docx.js
  8. // @match *://blog.csdn.net/*
  9. // @match *://www.jianshu.com/p/*
  10. // @match *://juejin.cn/post/*
  11. // @match *://zhuanlan.zhihu.com/p/*
  12. // @match *://www.cnblogs.com/*/p/*
  13. // @match *://www.cnblogs.com/*/archive/*
  14. // @match *://www.jb51.net/article/*
  15. // @match *://blog.51cto.com/u_*
  16. // @match *://www.pianshen.com/article/*
  17. // @match *://www.360doc.com/content/*
  18. // @match *://baijiahao.baidu.com/s?id=*
  19. // @match *://jingyan.baidu.com/article/*
  20. // @match *://www.52pojie.cn/thread-*
  21. // @match *://cloud.tencent.com/developer/article/*
  22. // @match *://developer.aliyun.com/article/*
  23. // @match *://huaweicloud.csdn.net/*
  24. // @match *://www.bilibili.com/read/*
  25. // @match *://weibo.com/ttarticle/p/show*
  26. // @match *://www.weibo.com/ttarticle/p/show*
  27. // @match *://mp.weixin.qq.com/s*
  28. // @match *://segmentfault.com/*/*
  29. // @match *://www.qinglite.cn/doc/*
  30. // @match *://www.manongjc.com/detail*
  31. // @license Apache-2.0
  32. // @icon data:image/svg+xml,%3Csvg t='1691941995383' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='1514' width='200' height='200'%3E%3Cpath d='M320 864 320 0l480 0 0 192 0 32L1024 224l0 640L320 864zM928 320l-512 0 0 32 512 0L928 320zM928 448l-512 0 0 32 512 0L928 448zM928 576l-512 0 0 32 512 0L928 576zM928 704l-512 0 0 32 512 0L928 704zM832 0l19.2 0L1024 160 1024 192l-192 0L832 0zM288 896l320 0L704 896l0 128L0 1024 0 160l288 0 0 320-192 0L96 512l192 0 0 96-192 0L96 640l192 0 0 96-192 0L96 768l192 0 0 96-192 0L96 896 288 896z' p-id='1515'%3E%3C/path%3E%3C/svg%3E
  33. // @grant none
  34. // @run-at document-idle
  35. // ==/UserScript==
  36. //修复支持表格、删除线、任务列表、checkbox任务
  37. var turndownPluginGfm = (function (exports) {
  38. 'use strict';
  39. var highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/;
  40. function highlightedCodeBlock(turndownService) {
  41. turndownService.addRule('highlightedCodeBlock', {
  42. filter: function (node) {
  43. var firstChild = node.firstChild;
  44. return (
  45. node.nodeName === 'DIV' &&
  46. highlightRegExp.test(node.className) &&
  47. firstChild &&
  48. firstChild.nodeName === 'PRE'
  49. )
  50. },
  51. replacement: function (content, node, options) {
  52. var className = node.className || '';
  53. var language = (className.match(highlightRegExp) || [null, ''])[1];
  54. return (
  55. '\n\n' + options.fence + language + '\n' +
  56. node.firstChild.textContent +
  57. '\n' + options.fence + '\n\n'
  58. )
  59. }
  60. });
  61. }
  62. function strikethrough(turndownService) {
  63. turndownService.addRule('strikethrough', {
  64. filter: ['del', 's', 'strike'],
  65. replacement: function (content) {
  66. return '~' + content + '~'
  67. }
  68. });
  69. }
  70. var indexOf = Array.prototype.indexOf;
  71. var every = Array.prototype.every;
  72. var rules = {};
  73. rules.tableCell = {
  74. filter: ['th', 'td'],
  75. replacement: function (content, node) {
  76. return cell(content, node)
  77. }
  78. };
  79. rules.tableRow = {
  80. filter: 'tr',
  81. replacement: function (content, node) {
  82. var borderCells = '';
  83. var alignMap = { left: ':--', right: '--:', center: ':-:' };
  84. if (isHeadingRow(node)) {
  85. for (var i = 0; i < node.childNodes.length; i++) {
  86. var border = '---';
  87. var align = (
  88. node.childNodes[i].getAttribute('align') || ''
  89. ).toLowerCase();
  90. if (align) border = alignMap[align] || border;
  91. borderCells += cell(border, node.childNodes[i]);
  92. }
  93. }
  94. return '\n' + content + (borderCells ? '\n' + borderCells : '')
  95. }
  96. };
  97. rules.table = {
  98. // Only convert tables with a heading row.
  99. // Tables with no heading row are kept using `keep` (see below).
  100. filter: function (node) {
  101. return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0])
  102. },
  103. replacement: function (content) {
  104. // Ensure there are no blank lines
  105. content = content.replace('\n\n', '\n');
  106. return '\n\n' + content + '\n\n'
  107. }
  108. };
  109. rules.tableSection = {
  110. filter: ['thead', 'tbody', 'tfoot'],
  111. replacement: function (content) {
  112. return content
  113. }
  114. };
  115. // A tr is a heading row if:
  116. // - the parent is a THEAD
  117. // - or if its the first child of the TABLE or the first TBODY (possibly
  118. // following a blank THEAD)
  119. // - and every cell is a TH
  120. function isHeadingRow(tr) {
  121. var parentNode = tr.parentNode;
  122. return (
  123. parentNode.nodeName === 'THEAD' ||
  124. (
  125. parentNode.firstChild === tr &&
  126. (parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) &&
  127. every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' })
  128. )
  129. )
  130. }
  131. function isFirstTbody(element) {
  132. var previousSibling = element.previousSibling;
  133. return (
  134. element.nodeName === 'TBODY' && (
  135. !previousSibling ||
  136. (
  137. previousSibling.nodeName === 'THEAD' &&
  138. /^\s*$/i.test(previousSibling.textContent)
  139. )
  140. )
  141. )
  142. }
  143. function cell(content, node) {
  144. var index = indexOf.call(node.parentNode.childNodes, node);
  145. var prefix = ' ';
  146. if (index === 0) prefix = '| ';
  147. return prefix + content + ' |'
  148. }
  149. function tables(turndownService) {
  150. turndownService.keep(function (node) {
  151. return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0])
  152. });
  153. for (var key in rules) turndownService.addRule(key, rules[key]);
  154. }
  155. function taskListItems(turndownService) {
  156. turndownService.addRule('taskListItems', {
  157. filter: function (node) {
  158. return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
  159. },
  160. replacement: function (content, node) {
  161. return (node.checked ? '[x]' : '[ ]') + ' '
  162. }
  163. });
  164. }
  165. function gfm(turndownService) {
  166. turndownService.use([
  167. highlightedCodeBlock,
  168. strikethrough,
  169. tables,
  170. taskListItems
  171. ]);
  172. }
  173. exports.gfm = gfm;
  174. exports.highlightedCodeBlock = highlightedCodeBlock;
  175. exports.strikethrough = strikethrough;
  176. exports.tables = tables;
  177. exports.taskListItems = taskListItems;
  178. return exports;
  179. }({}));
  180. var TurndownService = (function () {
  181. 'use strict';
  182. function extend(destination) {
  183. for (var i = 1; i < arguments.length; i++) {
  184. var source = arguments[i];
  185. for (var key in source) {
  186. if (source.hasOwnProperty(key)) destination[key] = source[key];
  187. }
  188. }
  189. return destination
  190. }
  191. function repeat(character, count) {
  192. return Array(count + 1).join(character)
  193. }
  194. function trimLeadingNewlines(string) {
  195. return string.replace(/^\n*/, '')
  196. }
  197. function trimTrailingNewlines(string) {
  198. // avoid match-at-end regexp bottleneck, see #370
  199. var indexEnd = string.length;
  200. while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--;
  201. return string.substring(0, indexEnd)
  202. }
  203. var blockElements = [
  204. 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',
  205. 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',
  206. 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',
  207. 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',
  208. 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',
  209. 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'
  210. ];
  211. function isBlock(node) {
  212. return is(node, blockElements)
  213. }
  214. var voidElements = [
  215. 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',
  216. 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'
  217. ];
  218. function isVoid(node) {
  219. return is(node, voidElements)
  220. }
  221. function hasVoid(node) {
  222. return has(node, voidElements)
  223. }
  224. var meaningfulWhenBlankElements = [
  225. 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',
  226. 'AUDIO', 'VIDEO'
  227. ];
  228. function isMeaningfulWhenBlank(node) {
  229. return is(node, meaningfulWhenBlankElements)
  230. }
  231. function hasMeaningfulWhenBlank(node) {
  232. return has(node, meaningfulWhenBlankElements)
  233. }
  234. function is(node, tagNames) {
  235. return tagNames.indexOf(node.nodeName) >= 0
  236. }
  237. function has(node, tagNames) {
  238. return (
  239. node.getElementsByTagName &&
  240. tagNames.some(function (tagName) {
  241. return node.getElementsByTagName(tagName).length
  242. })
  243. )
  244. }
  245. var rules = {};
  246. rules.paragraph = {
  247. filter: 'p',
  248. replacement: function (content) {
  249. return '\n\n' + content + '\n\n'
  250. }
  251. };
  252. rules.lineBreak = {
  253. filter: 'br',
  254. replacement: function (content, node, options) {
  255. return options.br + '\n'
  256. }
  257. };
  258. rules.heading = {
  259. filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
  260. replacement: function (content, node, options) {
  261. var hLevel = Number(node.nodeName.charAt(1));
  262. if (options.headingStyle === 'setext' && hLevel < 3) {
  263. var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
  264. return (
  265. '\n\n' + content + '\n' + underline + '\n\n'
  266. )
  267. } else {
  268. return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
  269. }
  270. }
  271. };
  272. rules.blockquote = {
  273. filter: 'blockquote',
  274. replacement: function (content) {
  275. content = content.replace(/^\n+|\n+$/g, '');
  276. content = content.replace(/^/gm, '> ');
  277. return '\n\n' + content + '\n\n'
  278. }
  279. };
  280. rules.list = {
  281. filter: ['ul', 'ol'],
  282. replacement: function (content, node) {
  283. var parent = node.parentNode;
  284. if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
  285. return '\n' + content
  286. } else {
  287. return '\n\n' + content + '\n\n'
  288. }
  289. }
  290. };
  291. rules.listItem = {
  292. filter: 'li',
  293. replacement: function (content, node, options) {
  294. content = content
  295. .replace(/^\n+/, '') // remove leading newlines
  296. .replace(/\n+$/, '\n') // replace trailing newlines with just a single one
  297. .replace(/\n/gm, '\n '); // indent
  298. var prefix = options.bulletListMarker + ' ';
  299. var parent = node.parentNode;
  300. if (parent.nodeName === 'OL') {
  301. var start = parent.getAttribute('start');
  302. var index = Array.prototype.indexOf.call(parent.children, node);
  303. prefix = (start ? Number(start) + index : index + 1) + '. ';
  304. }
  305. return (
  306. prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
  307. )
  308. }
  309. };
  310. rules.indentedCodeBlock = {
  311. filter: function (node, options) {
  312. return (
  313. options.codeBlockStyle === 'indented' &&
  314. node.nodeName === 'PRE' &&
  315. node.firstChild &&
  316. node.firstChild.nodeName === 'CODE'
  317. )
  318. },
  319. replacement: function (content, node, options) {
  320. return (
  321. '\n\n ' +
  322. node.firstChild.textContent.replace(/\n/g, '\n ') +
  323. '\n\n'
  324. )
  325. }
  326. };
  327. rules.fencedCodeBlock = {
  328. filter: function (node, options) {
  329. return (
  330. options.codeBlockStyle === 'fenced' &&
  331. node.nodeName === 'PRE' &&
  332. node.firstChild &&
  333. node.firstChild.nodeName === 'CODE'
  334. )
  335. },
  336. replacement: function (content, node, options) {
  337. var className = node.firstChild.getAttribute('class') || '';
  338. var language = (className.match(/language-(\S+)/) || [null, ''])[1];
  339. var code = node.firstChild.textContent;
  340. var fenceChar = options.fence.charAt(0);
  341. var fenceSize = 3;
  342. var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');
  343. var match;
  344. while ((match = fenceInCodeRegex.exec(code))) {
  345. if (match[0].length >= fenceSize) {
  346. fenceSize = match[0].length + 1;
  347. }
  348. }
  349. var fence = repeat(fenceChar, fenceSize);
  350. return (
  351. '\n\n' + fence + language + '\n' +
  352. code.replace(/\n$/, '') +
  353. '\n' + fence + '\n\n'
  354. )
  355. }
  356. };
  357. rules.horizontalRule = {
  358. filter: 'hr',
  359. replacement: function (content, node, options) {
  360. return '\n\n' + options.hr + '\n\n'
  361. }
  362. };
  363. rules.inlineLink = {
  364. filter: function (node, options) {
  365. return (
  366. options.linkStyle === 'inlined' &&
  367. node.nodeName === 'A' &&
  368. node.getAttribute('href')
  369. )
  370. },
  371. replacement: function (content, node) {
  372. var href = node.getAttribute('href');
  373. var title = cleanAttribute(node.getAttribute('title'));
  374. if (title) title = ' "' + title + '"';
  375. return '[' + content + '](' + href + title + ')'
  376. }
  377. };
  378. rules.referenceLink = {
  379. filter: function (node, options) {
  380. return (
  381. options.linkStyle === 'referenced' &&
  382. node.nodeName === 'A' &&
  383. node.getAttribute('href')
  384. )
  385. },
  386. replacement: function (content, node, options) {
  387. var href = node.getAttribute('href');
  388. var title = cleanAttribute(node.getAttribute('title'));
  389. if (title) title = ' "' + title + '"';
  390. var replacement;
  391. var reference;
  392. switch (options.linkReferenceStyle) {
  393. case 'collapsed':
  394. replacement = '[' + content + '][]';
  395. reference = '[' + content + ']: ' + href + title;
  396. break
  397. case 'shortcut':
  398. replacement = '[' + content + ']';
  399. reference = '[' + content + ']: ' + href + title;
  400. break
  401. default:
  402. var id = this.references.length + 1;
  403. replacement = '[' + content + '][' + id + ']';
  404. reference = '[' + id + ']: ' + href + title;
  405. }
  406. this.references.push(reference);
  407. return replacement
  408. },
  409. references: [],
  410. append: function (options) {
  411. var references = '';
  412. if (this.references.length) {
  413. references = '\n\n' + this.references.join('\n') + '\n\n';
  414. this.references = []; // Reset references
  415. }
  416. return references
  417. }
  418. };
  419. rules.emphasis = {
  420. filter: ['em', 'i'],
  421. replacement: function (content, node, options) {
  422. if (!content.trim()) return ''
  423. return options.emDelimiter + content + options.emDelimiter
  424. }
  425. };
  426. rules.strong = {
  427. filter: ['strong', 'b'],
  428. replacement: function (content, node, options) {
  429. if (!content.trim()) return ''
  430. return options.strongDelimiter + content + options.strongDelimiter
  431. }
  432. };
  433. rules.code = {
  434. filter: function (node) {
  435. var hasSiblings = node.previousSibling || node.nextSibling;
  436. var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
  437. return node.nodeName === 'CODE' && !isCodeBlock
  438. },
  439. replacement: function (content) {
  440. if (!content) return ''
  441. content = content.replace(/\r?\n|\r/g, ' ');
  442. var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : '';
  443. var delimiter = '`';
  444. var matches = content.match(/`+/gm) || [];
  445. while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
  446. return delimiter + extraSpace + content + extraSpace + delimiter
  447. }
  448. };
  449. rules.image = {
  450. filter: 'img',
  451. replacement: function (content, node) {
  452. var alt = cleanAttribute(node.getAttribute('alt'));
  453. var src = node.getAttribute('src') || '';
  454. var title = cleanAttribute(node.getAttribute('title'));
  455. var titlePart = title ? ' "' + title + '"' : '';
  456. return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
  457. }
  458. };
  459. function cleanAttribute(attribute) {
  460. return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
  461. }
  462. /**
  463. * Manages a collection of rules used to convert HTML to Markdown
  464. */
  465. function Rules(options) {
  466. this.options = options;
  467. this._keep = [];
  468. this._remove = [];
  469. this.blankRule = {
  470. replacement: options.blankReplacement
  471. };
  472. this.keepReplacement = options.keepReplacement;
  473. this.defaultRule = {
  474. replacement: options.defaultReplacement
  475. };
  476. this.array = [];
  477. for (var key in options.rules) this.array.push(options.rules[key]);
  478. }
  479. Rules.prototype = {
  480. add: function (key, rule) {
  481. this.array.unshift(rule);
  482. },
  483. keep: function (filter) {
  484. this._keep.unshift({
  485. filter: filter,
  486. replacement: this.keepReplacement
  487. });
  488. },
  489. remove: function (filter) {
  490. this._remove.unshift({
  491. filter: filter,
  492. replacement: function () {
  493. return ''
  494. }
  495. });
  496. },
  497. forNode: function (node) {
  498. if (node.isBlank) return this.blankRule
  499. var rule;
  500. if ((rule = findRule(this.array, node, this.options))) return rule
  501. if ((rule = findRule(this._keep, node, this.options))) return rule
  502. if ((rule = findRule(this._remove, node, this.options))) return rule
  503. return this.defaultRule
  504. },
  505. forEach: function (fn) {
  506. for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
  507. }
  508. };
  509. function findRule(rules, node, options) {
  510. for (var i = 0; i < rules.length; i++) {
  511. var rule = rules[i];
  512. if (filterValue(rule, node, options)) return rule
  513. }
  514. return void 0
  515. }
  516. function filterValue(rule, node, options) {
  517. var filter = rule.filter;
  518. if (typeof filter === 'string') {
  519. if (filter === node.nodeName.toLowerCase()) return true
  520. } else if (Array.isArray(filter)) {
  521. if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
  522. } else if (typeof filter === 'function') {
  523. if (filter.call(rule, node, options)) return true
  524. } else {
  525. throw new TypeError('`filter` needs to be a string, array, or function')
  526. }
  527. }
  528. /**
  529. * The collapseWhitespace function is adapted from collapse-whitespace
  530. * by Luc Thevenard.
  531. *
  532. * The MIT License (MIT)
  533. *
  534. * Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>
  535. *
  536. * Permission is hereby granted, free of charge, to any person obtaining a copy
  537. * of this software and associated documentation files (the "Software"), to deal
  538. * in the Software without restriction, including without limitation the rights
  539. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  540. * copies of the Software, and to permit persons to whom the Software is
  541. * furnished to do so, subject to the following conditions:
  542. *
  543. * The above copyright notice and this permission notice shall be included in
  544. * all copies or substantial portions of the Software.
  545. *
  546. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  547. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  548. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  549. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  550. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  551. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  552. * THE SOFTWARE.
  553. */
  554. /**
  555. * collapseWhitespace(options) removes extraneous whitespace from an the given element.
  556. *
  557. * @param {Object} options
  558. */
  559. function collapseWhitespace(options) {
  560. var element = options.element;
  561. var isBlock = options.isBlock;
  562. var isVoid = options.isVoid;
  563. var isPre = options.isPre || function (node) {
  564. return node.nodeName === 'PRE'
  565. };
  566. if (!element.firstChild || isPre(element)) return
  567. var prevText = null;
  568. var keepLeadingWs = false;
  569. var prev = null;
  570. var node = next(prev, element, isPre);
  571. while (node !== element) {
  572. if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
  573. var text = node.data.replace(/[ \r\n\t]+/g, ' ');
  574. if ((!prevText || / $/.test(prevText.data)) &&
  575. !keepLeadingWs && text[0] === ' ') {
  576. text = text.substr(1);
  577. }
  578. // `text` might be empty at this point.
  579. if (!text) {
  580. node = remove(node);
  581. continue
  582. }
  583. node.data = text;
  584. prevText = node;
  585. } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
  586. if (isBlock(node) || node.nodeName === 'BR') {
  587. if (prevText) {
  588. prevText.data = prevText.data.replace(/ $/, '');
  589. }
  590. prevText = null;
  591. keepLeadingWs = false;
  592. } else if (isVoid(node) || isPre(node)) {
  593. // Avoid trimming space around non-block, non-BR void elements and inline PRE.
  594. prevText = null;
  595. keepLeadingWs = true;
  596. } else if (prevText) {
  597. // Drop protection if set previously.
  598. keepLeadingWs = false;
  599. }
  600. } else {
  601. node = remove(node);
  602. continue
  603. }
  604. var nextNode = next(prev, node, isPre);
  605. prev = node;
  606. node = nextNode;
  607. }
  608. if (prevText) {
  609. prevText.data = prevText.data.replace(/ $/, '');
  610. if (!prevText.data) {
  611. remove(prevText);
  612. }
  613. }
  614. }
  615. /**
  616. * remove(node) removes the given node from the DOM and returns the
  617. * next node in the sequence.
  618. *
  619. * @param {Node} node
  620. * @return {Node} node
  621. */
  622. function remove(node) {
  623. var next = node.nextSibling || node.parentNode;
  624. node.parentNode.removeChild(node);
  625. return next
  626. }
  627. /**
  628. * next(prev, current, isPre) returns the next node in the sequence, given the
  629. * current and previous nodes.
  630. *
  631. * @param {Node} prev
  632. * @param {Node} current
  633. * @param {Function} isPre
  634. * @return {Node}
  635. */
  636. function next(prev, current, isPre) {
  637. if ((prev && prev.parentNode === current) || isPre(current)) {
  638. return current.nextSibling || current.parentNode
  639. }
  640. return current.firstChild || current.nextSibling || current.parentNode
  641. }
  642. /*
  643. * Set up window for Node.js
  644. */
  645. var root = (typeof window !== 'undefined' ? window : {});
  646. /*
  647. * Parsing HTML strings
  648. */
  649. function canParseHTMLNatively() {
  650. var Parser = root.DOMParser;
  651. var canParse = false;
  652. // Adapted from https://gist.github.com/1129031
  653. // Firefox/Opera/IE throw errors on unsupported types
  654. try {
  655. // WebKit returns null on unsupported types
  656. if (new Parser().parseFromString('', 'text/html')) {
  657. canParse = true;
  658. }
  659. } catch (e) { }
  660. return canParse
  661. }
  662. function createHTMLParser() {
  663. var Parser = function () { };
  664. {
  665. if (shouldUseActiveX()) {
  666. Parser.prototype.parseFromString = function (string) {
  667. var doc = new window.ActiveXObject('htmlfile');
  668. doc.designMode = 'on'; // disable on-page scripts
  669. doc.open();
  670. doc.write(string);
  671. doc.close();
  672. return doc
  673. };
  674. } else {
  675. Parser.prototype.parseFromString = function (string) {
  676. var doc = document.implementation.createHTMLDocument('');
  677. doc.open();
  678. doc.write(string);
  679. doc.close();
  680. return doc
  681. };
  682. }
  683. }
  684. return Parser
  685. }
  686. function shouldUseActiveX() {
  687. var useActiveX = false;
  688. try {
  689. document.implementation.createHTMLDocument('').open();
  690. } catch (e) {
  691. if (window.ActiveXObject) useActiveX = true;
  692. }
  693. return useActiveX
  694. }
  695. var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
  696. function RootNode(input, options) {
  697. var root;
  698. if (typeof input === 'string') {
  699. var doc = htmlParser().parseFromString(
  700. // DOM parsers arrange elements in the <head> and <body>.
  701. // Wrapping in a custom element ensures elements are reliably arranged in
  702. // a single element.
  703. '<x-turndown id="turndown-root">' + input + '</x-turndown>',
  704. 'text/html'
  705. );
  706. root = doc.getElementById('turndown-root');
  707. } else {
  708. root = input.cloneNode(true);
  709. }
  710. collapseWhitespace({
  711. element: root,
  712. isBlock: isBlock,
  713. isVoid: isVoid,
  714. isPre: options.preformattedCode ? isPreOrCode : null
  715. });
  716. return root
  717. }
  718. var _htmlParser;
  719. function htmlParser() {
  720. _htmlParser = _htmlParser || new HTMLParser();
  721. return _htmlParser
  722. }
  723. function isPreOrCode(node) {
  724. return node.nodeName === 'PRE' || node.nodeName === 'CODE'
  725. }
  726. function Node(node, options) {
  727. node.isBlock = isBlock(node);
  728. node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode;
  729. node.isBlank = isBlank(node);
  730. node.flankingWhitespace = flankingWhitespace(node, options);
  731. return node
  732. }
  733. function isBlank(node) {
  734. return (
  735. !isVoid(node) &&
  736. !isMeaningfulWhenBlank(node) &&
  737. /^\s*$/i.test(node.textContent) &&
  738. !hasVoid(node) &&
  739. !hasMeaningfulWhenBlank(node)
  740. )
  741. }
  742. function flankingWhitespace(node, options) {
  743. if (node.isBlock || (options.preformattedCode && node.isCode)) {
  744. return { leading: '', trailing: '' }
  745. }
  746. var edges = edgeWhitespace(node.textContent);
  747. // abandon leading ASCII WS if left-flanked by ASCII WS
  748. if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {
  749. edges.leading = edges.leadingNonAscii;
  750. }
  751. // abandon trailing ASCII WS if right-flanked by ASCII WS
  752. if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {
  753. edges.trailing = edges.trailingNonAscii;
  754. }
  755. return { leading: edges.leading, trailing: edges.trailing }
  756. }
  757. function edgeWhitespace(string) {
  758. var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);
  759. return {
  760. leading: m[1], // whole string for whitespace-only strings
  761. leadingAscii: m[2],
  762. leadingNonAscii: m[3],
  763. trailing: m[4], // empty for whitespace-only strings
  764. trailingNonAscii: m[5],
  765. trailingAscii: m[6]
  766. }
  767. }
  768. function isFlankedByWhitespace(side, node, options) {
  769. var sibling;
  770. var regExp;
  771. var isFlanked;
  772. if (side === 'left') {
  773. sibling = node.previousSibling;
  774. regExp = / $/;
  775. } else {
  776. sibling = node.nextSibling;
  777. regExp = /^ /;
  778. }
  779. if (sibling) {
  780. if (sibling.nodeType === 3) {
  781. isFlanked = regExp.test(sibling.nodeValue);
  782. } else if (options.preformattedCode && sibling.nodeName === 'CODE') {
  783. isFlanked = false;
  784. } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
  785. isFlanked = regExp.test(sibling.textContent);
  786. }
  787. }
  788. return isFlanked
  789. }
  790. var reduce = Array.prototype.reduce;
  791. var escapes = [
  792. [/\\/g, '\\\\'],
  793. [/\*/g, '\\*'],
  794. [/^-/g, '\\-'],
  795. [/^\+ /g, '\\+ '],
  796. [/^(=+)/g, '\\$1'],
  797. [/^(#{1,6}) /g, '\\$1 '],
  798. [/`/g, '\\`'],
  799. [/^~~~/g, '\\~~~'],
  800. [/\[/g, '\\['],
  801. [/\]/g, '\\]'],
  802. [/^>/g, '\\>'],
  803. [/_/g, '\\_'],
  804. [/^(\d+)\. /g, '$1\\. ']
  805. ];
  806. function TurndownService(options) {
  807. if (!(this instanceof TurndownService)) return new TurndownService(options)
  808. var defaults = {
  809. rules: rules,
  810. headingStyle: 'setext',
  811. hr: '* * *',
  812. bulletListMarker: '*',
  813. codeBlockStyle: 'indented',
  814. fence: '```',
  815. emDelimiter: '_',
  816. strongDelimiter: '**',
  817. linkStyle: 'inlined',
  818. linkReferenceStyle: 'full',
  819. br: ' ',
  820. preformattedCode: false,
  821. blankReplacement: function (content, node) {
  822. return node.isBlock ? '\n\n' : ''
  823. },
  824. keepReplacement: function (content, node) {
  825. return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
  826. },
  827. defaultReplacement: function (content, node) {
  828. return node.isBlock ? '\n\n' + content + '\n\n' : content
  829. }
  830. };
  831. this.options = extend({}, defaults, options);
  832. this.rules = new Rules(this.options);
  833. }
  834. TurndownService.prototype = {
  835. /**
  836. * The entry point for converting a string or DOM node to Markdown
  837. * @public
  838. * @param {String|HTMLElement} input The string or DOM node to convert
  839. * @returns A Markdown representation of the input
  840. * @type String
  841. */
  842. turndown: function (input) {
  843. if (!canConvert(input)) {
  844. throw new TypeError(
  845. input + ' is not a string, or an element/document/fragment node.'
  846. )
  847. }
  848. if (input === '') return ''
  849. var output = process.call(this, new RootNode(input, this.options));
  850. return postProcess.call(this, output)
  851. },
  852. /**
  853. * Add one or more plugins
  854. * @public
  855. * @param {Function|Array} plugin The plugin or array of plugins to add
  856. * @returns The Turndown instance for chaining
  857. * @type Object
  858. */
  859. use: function (plugin) {
  860. if (Array.isArray(plugin)) {
  861. for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
  862. } else if (typeof plugin === 'function') {
  863. plugin(this);
  864. } else {
  865. throw new TypeError('plugin must be a Function or an Array of Functions')
  866. }
  867. return this
  868. },
  869. /**
  870. * Adds a rule
  871. * @public
  872. * @param {String} key The unique key of the rule
  873. * @param {Object} rule The rule
  874. * @returns The Turndown instance for chaining
  875. * @type Object
  876. */
  877. addRule: function (key, rule) {
  878. this.rules.add(key, rule);
  879. return this
  880. },
  881. /**
  882. * Keep a node (as HTML) that matches the filter
  883. * @public
  884. * @param {String|Array|Function} filter The unique key of the rule
  885. * @returns The Turndown instance for chaining
  886. * @type Object
  887. */
  888. keep: function (filter) {
  889. this.rules.keep(filter);
  890. return this
  891. },
  892. /**
  893. * Remove a node that matches the filter
  894. * @public
  895. * @param {String|Array|Function} filter The unique key of the rule
  896. * @returns The Turndown instance for chaining
  897. * @type Object
  898. */
  899. remove: function (filter) {
  900. this.rules.remove(filter);
  901. return this
  902. },
  903. /**
  904. * Escapes Markdown syntax
  905. * @public
  906. * @param {String} string The string to escape
  907. * @returns A string with Markdown syntax escaped
  908. * @type String
  909. */
  910. escape: function (string) {
  911. return escapes.reduce(function (accumulator, escape) {
  912. return accumulator.replace(escape[0], escape[1])
  913. }, string)
  914. }
  915. };
  916. /**
  917. * Reduces a DOM node down to its Markdown string equivalent
  918. * @private
  919. * @param {HTMLElement} parentNode The node to convert
  920. * @returns A Markdown representation of the node
  921. * @type String
  922. */
  923. function process(parentNode) {
  924. var self = this;
  925. return reduce.call(parentNode.childNodes, function (output, node) {
  926. node = new Node(node, self.options);
  927. var replacement = '';
  928. if (node.nodeType === 3) {
  929. replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
  930. } else if (node.nodeType === 1) {
  931. replacement = replacementForNode.call(self, node);
  932. }
  933. return join(output, replacement)
  934. }, '')
  935. }
  936. /**
  937. * Appends strings as each rule requires and trims the output
  938. * @private
  939. * @param {String} output The conversion output
  940. * @returns A trimmed version of the ouput
  941. * @type String
  942. */
  943. function postProcess(output) {
  944. var self = this;
  945. this.rules.forEach(function (rule) {
  946. if (typeof rule.append === 'function') {
  947. output = join(output, rule.append(self.options));
  948. }
  949. });
  950. return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
  951. }
  952. /**
  953. * Converts an element node to its Markdown equivalent
  954. * @private
  955. * @param {HTMLElement} node The node to convert
  956. * @returns A Markdown representation of the node
  957. * @type String
  958. */
  959. function replacementForNode(node) {
  960. var rule = this.rules.forNode(node);
  961. var content = process.call(this, node);
  962. var whitespace = node.flankingWhitespace;
  963. if (whitespace.leading || whitespace.trailing) content = content.trim();
  964. return (
  965. whitespace.leading +
  966. rule.replacement(content, node, this.options) +
  967. whitespace.trailing
  968. )
  969. }
  970. /**
  971. * Joins replacement to the current output with appropriate number of new lines
  972. * @private
  973. * @param {String} output The current conversion output
  974. * @param {String} replacement The string to append to the output
  975. * @returns Joined output
  976. * @type String
  977. */
  978. function join(output, replacement) {
  979. var s1 = trimTrailingNewlines(output);
  980. var s2 = trimLeadingNewlines(replacement);
  981. var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
  982. var separator = '\n\n'.substring(0, nls);
  983. return s1 + separator + s2
  984. }
  985. /**
  986. * Determines whether an input can be converted
  987. * @private
  988. * @param {String|HTMLElement} input Describe this parameter
  989. * @returns Describe what it returns
  990. * @type String|Object|Array|Boolean|Number
  991. */
  992. function canConvert(input) {
  993. return (
  994. input != null && (
  995. typeof input === 'string' ||
  996. (input.nodeType && (
  997. input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
  998. ))
  999. )
  1000. )
  1001. }
  1002. return TurndownService;
  1003. }());
  1004. (async function() {
  1005. /**
  1006. * 遵循开源协议,转载请注明出处谢谢
  1007. */
  1008. 'use strict';
  1009. const webUrl = window.location.href;
  1010. const headline = document.title;
  1011. const host = location.host;
  1012. const InterfaceList = [
  1013. { "host": "blog.csdn.net", "el": "article.baidu_pl", "cut_str": "_" },
  1014. { "host": "www.jianshu.com", "el": "article._2rhmJa", "cut_str": " - " },
  1015. { "host": "juejin.cn", "el": ".article-viewer.markdown-body.result", "cut_str": " - " },
  1016. { "host": "zhuanlan.zhihu.com", "el": ".Post-RichTextContainer", "cut_str": " - " },
  1017. { "host": "www.cnblogs.com", "el": "#cnblogs_post_body", "cut_str": " - " },
  1018. { "host": "www.jb51.net", "el": "#content", "cut_str": "_" },
  1019. { "host": "blog.51cto.com", "el": "#result", "cut_str": "_" },
  1020. { "host": "www.pianshen.com", "el": ".blogpost-body", "cut_str": " - " },
  1021. { "host": "www.360doc.com", "el": "#artContent", "cut_str": "" },
  1022. { "host": "baijiahao.baidu.com", "el": "div[data-testid='article']", "cut_str": "" },
  1023. { "host": "jingyan.baidu.com", "el": ".exp-content-outer", "cut_str": "-" },
  1024. { "host": "www.52pojie.cn", "el": ".t_f", "cut_str": " - " },
  1025. { "host": "cloud.tencent.com", "el": ".mod-content__markdown", "cut_str": "-" },
  1026. { "host": "developer.aliyun.com", "el": ".content-wrapper", "cut_str": "-" },
  1027. { "host": "huaweicloud.csdn.net", "el": ".main-content", "cut_str": "_" },
  1028. { "host": "www.bilibili.com", "el": "#read-article-holder", "cut_str": " - " },
  1029. { "host": "weibo.com", "el": ".main_editor", "cut_str": "" },
  1030. { "host": "www.weibo.com", "el": ".main_editor", "cut_str": "" },
  1031. { "host": "mp.weixin.qq.com", "el": "#js_content", "cut_str": "" },
  1032. { "host": "segmentfault.com", "el": ".article.fmt.article-content", "cut_str": "- SegmentFault 思否" },
  1033. { "host": "www.qinglite.cn", "el": ".markdown-body", "cut_str": "-" },
  1034. { "host": "www.manongjc.com", "el": "#code_example", "cut_str": " - " }
  1035. ]
  1036. const utils = {
  1037. async addMeta () {
  1038. const meta = document.createElement('meta');
  1039. meta.setAttribute('http-equiv', "Content-Security-Policy");
  1040. meta.content = `default-src *; connect-src * ws://* wss://*; style-src * 'unsafe-inline' 'unsafe-eval'; media-src * ; img-src * data:; font-src * ; script-src * 'unsafe-inline' 'unsafe-eval';`;
  1041. const dom = document.head || document.documentElement;
  1042. dom.appendChild(meta);
  1043. },
  1044. async css (css) {
  1045. const myStyle = document.createElement('style');
  1046. myStyle.textContent = css;
  1047. const doc = document.head || document.documentElement;
  1048. doc.appendChild(myStyle);
  1049. },
  1050. async node (node) {
  1051. const myDiv = document.createElement('div');
  1052. myDiv.innerHTML = node;
  1053. const doc = document.body || document.documentElement;
  1054. doc.appendChild(myDiv);
  1055. },
  1056. async load_web_script (list) {
  1057. try {
  1058. for (const url of list) {
  1059. if(!document.querySelector(`script[src="${url}"]`)){
  1060. const script = document.createElement("script");
  1061. script.src = url;
  1062. script.async = false;
  1063. document.body.append(script);
  1064. }
  1065. }
  1066. } catch (e) {
  1067. console.error(e);
  1068. }
  1069. },
  1070.  
  1071. async exportdoc(el, docName) {
  1072. const elementContent = document.querySelector(el).innerHTML;
  1073. /*const doc = new Docx();
  1074. doc.fromHTML(elementContent);
  1075. doc.createDocx(`${docName}.docx`);*/
  1076. let wordContent = htmlDocx.asBlob(elementContent);
  1077. const blobURL = URL.createObjectURL(wordContent);
  1078. const link = document.createElement('a');
  1079. link.href = blobURL;
  1080. link.download = `${docName}.docx`;
  1081. link.click();
  1082. URL.revokeObjectURL(blobURL);
  1083.  
  1084. }
  1085. }
  1086. await utils.css(`
  1087. #zuihuitao {
  1088. cursor: pointer;
  1089. position: fixed;
  1090. top: 100px;
  1091. left: 0px;
  1092. width: 0px;
  1093. z-index: 2147483647;
  1094. font-size: 12px;
  1095. text-align: left;
  1096. }
  1097.  
  1098. #zuihuitao .logo {
  1099. position: absolute;
  1100. right: 0;
  1101. width: 1.375rem;
  1102. padding: 10px 2px;
  1103. text-align: center;
  1104. color: #fff;
  1105. cursor: auto;
  1106. user-select: none;
  1107. border-radius: 0 4px 4px 0;
  1108. transform: translate3d(100%, 5%, 0);
  1109. background: deepskyblue;
  1110. }
  1111.  
  1112. #zuihuitao .die {
  1113. display: none;
  1114. position: absolute;
  1115. left: 24px;
  1116. top: 0;
  1117. text-align: center;
  1118. background-color: #04b4ae;
  1119. border: 1px solid gray;
  1120. }
  1121.  
  1122. #zuihuitao .die li {
  1123. font-size: 12px;
  1124. color: #fff;
  1125. text-align: center;
  1126. width: 60px;
  1127. line-height: 21px;
  1128. float: left;
  1129. border: 1px solid gray;
  1130. border-radius: 6px 6px 6px 6px;
  1131. padding: 0 4px;
  1132. margin: 4px 2px;
  1133. list-style-type: none;
  1134. }
  1135.  
  1136. #zuihuitao .die li:hover {
  1137. color: #fff;
  1138. background: #fe2e64;
  1139. }
  1140.  
  1141. @media print {
  1142. body {
  1143. display: block !important;
  1144. }
  1145. }
  1146.  
  1147. * {
  1148. -webkit-user-select: text;
  1149. -moz-user-select: text;
  1150. -ms-user-select: text;
  1151. user-select: text;
  1152. }
  1153.  
  1154. .add {
  1155. background-color: #fe2e64;
  1156. }
  1157.  
  1158. .btn-success {
  1159. position: fixed;
  1160. font-weight: 400;
  1161. color: #fff;
  1162. background-color: #28a745;
  1163. border-color: #28a745;
  1164. text-align: center;
  1165. vertical-align: middle;
  1166. border: 1px solid transparent;
  1167. padding: 0.375rem 0.75rem;
  1168. font-size: 1rem;
  1169. line-height: 1.5;
  1170. border-radius: 0.25rem;
  1171. z-index: 2147483647;
  1172. cursor: pointer;
  1173. }
  1174. `);
  1175. const html = `<div id='zuihuitao'>
  1176. <div class='item_text'>
  1177. <div class="logo"><a id="m">文档下载</a></div>
  1178. <div class='die' >
  1179. <div style='display:flex;'>
  1180. <div style='width:128px; padding:0px 0;'>
  1181. <br>
  1182. <div style='font-size:16px; text-align:center; color:#fff; line-height:21px;'>导出Markdown</div>
  1183. <ul style='margin:0 24px;'>
  1184. <li id="li0">下载</li>
  1185. <div style='clear:both;'></div>
  1186. </ul>
  1187. <br>
  1188. <div style='font-size:16px; text-align:center; color:#fff; line-height:21px;'>导出Word</div>
  1189. <ul style='margin:0 24px;'>
  1190. <li id="li1">下载</li>
  1191. <div style='clear:both;'></div>
  1192. </ul>
  1193. <br>
  1194. </div>
  1195. </div>
  1196. </div>
  1197. </div>
  1198. </div>
  1199. </div>`;
  1200. await utils.node(html);
  1201. document.getElementsByClassName('item_text')[0].addEventListener('mouseover', () => {
  1202. document.getElementsByClassName('die')[0].style.display = 'block';
  1203. });
  1204. document.getElementsByClassName('item_text')[0].addEventListener('mouseout', () => {
  1205. document.getElementsByClassName('die')[0].style.display = 'none';
  1206. })
  1207. const cut_title = async (title, cut_str) => {
  1208. try{
  1209. const new_title = title.split(cut_str)[0];
  1210. return new_title;
  1211. }
  1212. catch(e){
  1213. console.log(e);
  1214. return title;
  1215. }
  1216. }
  1217. const save_md = async (el, title) => {
  1218. const turndownService = new TurndownService();
  1219. const gfm = turndownPluginGfm.gfm;
  1220. turndownService.use(gfm);
  1221. turndownService.remove('style');
  1222. let ele = document.querySelector(el);
  1223. let markdown = turndownService.turndown(ele);
  1224. //console.log(markdown);
  1225. let filename = `${title}.md`;
  1226. const downloadLink = document.createElement('a');
  1227. downloadLink.setAttribute('download', filename);
  1228. let markdownContent = `${markdown}\n\n本文转自 <${webUrl}>,如有侵权,请联系删除。`;
  1229. //downloadLink.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(markdownContent);
  1230. const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8' });
  1231. let blobURL = URL.createObjectURL(blob);
  1232. downloadLink.setAttribute('href', blobURL);
  1233. //document.body.appendChild(downloadLink);
  1234. downloadLink.click();
  1235. URL.revokeObjectURL(blob);
  1236. }
  1237. const getData = async () => {
  1238. let new_headline;
  1239. for (const even in InterfaceList) {
  1240. if (host == InterfaceList[even].host) {
  1241. let ele = InterfaceList[even].el;
  1242. let cut = InterfaceList[even].cut_str;
  1243. if(cut != ''){
  1244. new_headline = await cut_title(headline, cut);
  1245. }else{
  1246. new_headline = document.title;
  1247. }
  1248.  
  1249. const data = {
  1250. title: new_headline,
  1251. el: ele
  1252. }
  1253.  
  1254. return data;
  1255. }
  1256. }
  1257. }
  1258.  
  1259. const exportMd = async () => {
  1260.  
  1261. const data = await getData();
  1262.  
  1263. await save_md(data.el, data.title);
  1264.  
  1265. }
  1266. document.getElementById('li0').addEventListener('click', async () => {
  1267. await exportMd().then(
  1268. res => {
  1269. document.getElementsByClassName('die')[0].style.block = 'none';
  1270. console.log(`文件 ${res}.md 已开始下载~`);
  1271. }
  1272. ).catch(
  1273. err => {
  1274. console.log(err);
  1275. }
  1276. );
  1277. });
  1278.  
  1279. document.getElementById('li1').addEventListener('click', async () => {
  1280.  
  1281. const data = await getData();
  1282. await utils.exportdoc(data.el, data.title);
  1283.  
  1284. });
  1285. })();