From a028a7c2bb00eba5335746a2ee214f661a843a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=86=89?= Date: Fri, 1 Nov 2019 17:24:18 +0800 Subject: [PATCH 1/5] feat: add code block line numbers --- docs/PREFERENCES.md | 1 + src/main/preferences/schema.json | 5 ++ src/muya/lib/assets/styles/index.css | 46 +++++++++++++++++++ src/muya/lib/config/index.js | 1 + .../renderBlock/renderContainerBlock.js | 14 +++++- .../render/renderBlock/renderLineNumber.js | 22 +++++++++ .../components/editorWithTabs/editor.vue | 9 ++++ src/renderer/prefComponents/editor/index.vue | 6 +++ src/renderer/store/preferences.js | 1 + static/preference.json | 1 + 10 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/muya/lib/parser/render/renderBlock/renderLineNumber.js diff --git a/docs/PREFERENCES.md b/docs/PREFERENCES.md index 48c5f252..848b122f 100644 --- a/docs/PREFERENCES.md +++ b/docs/PREFERENCES.md @@ -31,6 +31,7 @@ Preferences can be controlled and modified in the settings window or via the `pr | textDirection | String | ltr | The writing text direction, optional value: `ltr` or `rtl` | | codeFontSize | Number | 14 | Font size on code block, the range is 12 ~ 28 | | codeFontFamily | String | `DejaVu Sans Mono` | Code font family | +| codeBlockLineNumbers | Boolean | true | Whether to show the line numbers in code block | | trimUnnecessaryCodeBlockEmptyLines | Boolean | true | Whether to trim the beginning and end empty line in Code block | | hideQuickInsertHint | Boolean | false | Hide hint for quickly creating paragraphs | | imageDropAction | String | folder | The default behavior after paste or drag the image to Mark Text, upload it to the image cloud (if configured), move to the specified folder, insert the path | diff --git a/src/main/preferences/schema.json b/src/main/preferences/schema.json index 03755007..4f026f6a 100644 --- a/src/main/preferences/schema.json +++ b/src/main/preferences/schema.json @@ -94,6 +94,11 @@ "type": "string", "pattern": "^[_A-z0-9]+((-|\\s)*[_A-z0-9])*$" }, + "codeBlockLineNumbers": { + "description": "Editor--Whether to show the line numbers", + "type": "boolean", + "default": true + }, "trimUnnecessaryCodeBlockEmptyLines": { "description": "Editor--Trim the beginning and ending empty lines in code block", "type": "boolean" diff --git a/src/muya/lib/assets/styles/index.css b/src/muya/lib/assets/styles/index.css index 3dcf2f98..ad9c542b 100644 --- a/src/muya/lib/assets/styles/index.css +++ b/src/muya/lib/assets/styles/index.css @@ -1107,3 +1107,49 @@ span.ag-reference-link { .vega-embed { padding-right: 0; } + +pre[class*="language-"].line-numbers { + position: relative; + padding-left: 2.5em; + counter-reset: linenumber; +} + +pre[class*="language-"].line-numbers > code { + position: relative; + white-space: inherit; +} + +figure:not(.ag-active) pre[class*="language-"].line-numbers { + display: none; +} + +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -2.5em; + width: 2.5em; /* works for line-numbers below 1000 lines */ + letter-spacing: -1px; + + user-select: none; + +} + +.line-numbers-rows > span { + pointer-events: none; + display: block; + counter-increment: linenumber; +} + +.line-numbers-rows > span:before { + content: counter(linenumber); + color: var(--editorColor30); + display: block; + padding-right: .8em; + text-align: right; + transform: scale(.8); + position: relative; + top: .05em; +} + diff --git a/src/muya/lib/config/index.js b/src/muya/lib/config/index.js index 22eb6db1..3b2c1a97 100644 --- a/src/muya/lib/config/index.js +++ b/src/muya/lib/config/index.js @@ -254,6 +254,7 @@ export const MUYA_DEFAULT_OPTION = { bulletListMarker: '-', orderListDelimiter: '.', tabSize: 4, + codeBlockLineNumbers: true, // bullet/list marker width + listIndentation, tab or Daring Fireball Markdown (4 spaces) --> list indentation listIndentation: 1, frontmatterType: '-', diff --git a/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js b/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js index 5f16112d..551980ac 100644 --- a/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js +++ b/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js @@ -1,6 +1,7 @@ import { CLASS_OR_ID } from '../../../config' import { renderTableTools } from './renderToolBar' import { renderEditIcon } from './renderContainerEditIcon' +import renderLineNumberRows from './renderLineNumber' import { renderLeftBar, renderBottomBar } from './renderTableDargBar' import { h } from '../snabbdom' @@ -45,8 +46,17 @@ export default function renderContainerBlock (parent, block, activeBlocks, match }) } - if (/code|pre/.test(type) && typeof lang === 'string' && !!lang) { - selector += `.language-${lang.replace(/[#.]{1}/g, '')}` + if (/code|pre/.test(type)) { + if (typeof lang === 'string' && !!lang) { + selector += `.language-${lang.replace(/[#.]{1}/g, '')}` + } + if (this.muya.options.codeBlockLineNumbers) { + if (type === 'pre') { + selector += '.line-numbers' + } else { + children.unshift(renderLineNumberRows(block.children[0])) + } + } Object.assign(data.attrs, { spellcheck: 'false' }) } diff --git a/src/muya/lib/parser/render/renderBlock/renderLineNumber.js b/src/muya/lib/parser/render/renderBlock/renderLineNumber.js new file mode 100644 index 00000000..c0ddb7b0 --- /dev/null +++ b/src/muya/lib/parser/render/renderBlock/renderLineNumber.js @@ -0,0 +1,22 @@ +import { h } from '../snabbdom' + +const NEW_LINE_EXP = /\n(?!$)/g + +const renderLineNumberRows = codeContent => { + const { text } = codeContent + const match = text.match(NEW_LINE_EXP) + let linesNum = match ? match.length + 1 : 1 + if (text.endsWith('\n')) { + linesNum++ + } + const data = { + attrs: { + 'aria-hidden': true + } + } + const children = [...new Array(linesNum)].map(() => h('span')) + + return h('span.line-numbers-rows', data, children) +} + +export default renderLineNumberRows diff --git a/src/renderer/components/editorWithTabs/editor.vue b/src/renderer/components/editorWithTabs/editor.vue index fa432767..091cffeb 100644 --- a/src/renderer/components/editorWithTabs/editor.vue +++ b/src/renderer/components/editorWithTabs/editor.vue @@ -140,6 +140,7 @@ export default { fontSize: state => state.preferences.fontSize, codeFontSize: state => state.preferences.codeFontSize, codeFontFamily: state => state.preferences.codeFontFamily, + codeBlockLineNumbers: state => state.preferences.codeBlockLineNumbers, trimUnnecessaryCodeBlockEmptyLines: state => state.preferences.trimUnnecessaryCodeBlockEmptyLines, editorFontFamily: state => state.preferences.editorFontFamily, hideQuickInsertHint: state => state.preferences.hideQuickInsertHint, @@ -312,6 +313,12 @@ export default { }) } }, + codeBlockLineNumbers: function (value, oldValue) { + const { editor } = this + if (value !== oldValue && editor) { + editor.setOptions({ codeBlockLineNumbers: value }, true) + } + }, codeFontFamily: function (value, oldValue) { if (value !== oldValue) { addCommonStyle({ @@ -443,6 +450,7 @@ export default { tabSize, fontSize, lineHeight, + codeBlockLineNumbers, listIndentation, frontmatterType, superSubScript, @@ -485,6 +493,7 @@ export default { tabSize, fontSize, lineHeight, + codeBlockLineNumbers, listIndentation, frontmatterType, superSubScript, diff --git a/src/renderer/prefComponents/editor/index.vue b/src/renderer/prefComponents/editor/index.vue index 28edac3c..033e080b 100644 --- a/src/renderer/prefComponents/editor/index.vue +++ b/src/renderer/prefComponents/editor/index.vue @@ -39,6 +39,11 @@ :value="codeFontFamily" :onChange="value => onSelectChange('codeFontFamily', value)" > + state.preferences.textDirection, codeFontSize: state => state.preferences.codeFontSize, codeFontFamily: state => state.preferences.codeFontFamily, + codeBlockLineNumbers: state => state.preferences.codeBlockLineNumbers, trimUnnecessaryCodeBlockEmptyLines: state => state.preferences.trimUnnecessaryCodeBlockEmptyLines, hideQuickInsertHint: state => state.preferences.hideQuickInsertHint, hideLinkPopup: state => state.preferences.hideLinkPopup, diff --git a/src/renderer/store/preferences.js b/src/renderer/store/preferences.js index c0bbef20..32ab0c46 100644 --- a/src/renderer/store/preferences.js +++ b/src/renderer/store/preferences.js @@ -19,6 +19,7 @@ const state = { lineHeight: 1.6, codeFontSize: 14, codeFontFamily: 'DejaVu Sans Mono', + codeBlockLineNumbers: true, trimUnnecessaryCodeBlockEmptyLines: true, editorLineWidth: '', diff --git a/static/preference.json b/static/preference.json index 1364bf47..39a1a720 100644 --- a/static/preference.json +++ b/static/preference.json @@ -16,6 +16,7 @@ "lineHeight": 1.6, "codeFontSize": 14, "codeFontFamily": "DejaVu Sans Mono", + "codeBlockLineNumbers": true, "trimUnnecessaryCodeBlockEmptyLines": true, "editorLineWidth": "", From 7aa0d1bf4d85e83b5c05d887b05142522f862923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=86=89?= Date: Fri, 1 Nov 2019 18:43:41 +0800 Subject: [PATCH 2/5] Feat: add copy code block button --- src/muya/lib/assets/styles/index.css | 43 ++++++++++++++++++- src/muya/lib/contentState/codeBlockCtrl.js | 12 ++++++ src/muya/lib/contentState/copyCutCtrl.js | 12 ++++++ src/muya/lib/contentState/pasteCtrl.js | 3 +- src/muya/lib/eventHandler/clickEvent.js | 6 +++ src/muya/lib/eventHandler/clipboard.js | 5 ++- src/muya/lib/index.js | 2 +- .../renderBlock/renderContainerBlock.js | 4 ++ .../render/renderBlock/renderCopyButton.js | 21 +++++++++ 9 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 src/muya/lib/parser/render/renderBlock/renderCopyButton.js diff --git a/src/muya/lib/assets/styles/index.css b/src/muya/lib/assets/styles/index.css index ad9c542b..dc6acda8 100644 --- a/src/muya/lib/assets/styles/index.css +++ b/src/muya/lib/assets/styles/index.css @@ -572,7 +572,7 @@ pre.ag-indent-code > code::before, pre.ag-fence-code > code::before { content: ''; position: absolute; - top: -10px; + bottom: -1em; right: -5px; color: var(--editorColor30); font-size: 12px; @@ -1108,6 +1108,47 @@ span.ag-reference-link { padding-right: 0; } +.ag-code-copy { + position: absolute; + top: .5em; + right: .5em; + width: 20px; + height: 20px; + border-radius: 4px; + cursor: pointer; + opacity: 0; + z-index: 1; + transition: opacity .2s ease-in-out; +} + +.ag-active .ag-code-copy { + opacity: .5; +} + +pre:not(.ag-active):hover .ag-code-copy { + opacity: .5; +} + +.ag-code-copy:hover { + opacity: 1; +} + +.ag-code-copy i.icon { + position: absolute; + top: 2px; + left: 2px; + width: 16px; + height: 16px; +} + +.ag-code-copy i.icon > i[class^=icon-] { + width: 100%; + height: 100%; + filter: drop-shadow(16px 0 var(--iconColor)); + position: absolute; + left: -16px; +} + pre[class*="language-"].line-numbers { position: relative; padding-left: 2.5em; diff --git a/src/muya/lib/contentState/codeBlockCtrl.js b/src/muya/lib/contentState/codeBlockCtrl.js index 237db711..4bc23680 100644 --- a/src/muya/lib/contentState/codeBlockCtrl.js +++ b/src/muya/lib/contentState/codeBlockCtrl.js @@ -123,6 +123,18 @@ const codeBlockCtrl = ContentState => { } return false } + + /** + * Copy the code block by click right-top copy icon in code block. + */ + ContentState.prototype.copyCodeBlock = function (event) { + const { target } = event + const preEle = target.closest('pre') + const preBlock = this.getBlock(preEle.id) + const codeBlock = preBlock.children.find(c => c.type === 'code') + const codeContent = codeBlock.children[0].text + this.muya.clipboard.copy('copyCodeContent', codeContent) + } } export default codeBlockCtrl diff --git a/src/muya/lib/contentState/copyCutCtrl.js b/src/muya/lib/contentState/copyCutCtrl.js index 2f18e482..76106150 100644 --- a/src/muya/lib/contentState/copyCutCtrl.js +++ b/src/muya/lib/contentState/copyCutCtrl.js @@ -47,6 +47,9 @@ const copyCutCtrl = ContentState => { ContentState.prototype.getClipBoradData = function () { const { start, end } = selection.getCursorRange() + if (!start || !end) { + return { html: '', text: '' } + } if (start.key === end.key) { const startBlock = this.getBlock(start.key) const { type, text, functionType } = startBlock @@ -273,6 +276,15 @@ const copyCutCtrl = ContentState => { event.clipboardData.setData('text/plain', markdown) break } + + case 'copyCodeContent': { + const codeContent = copyInfo + if (typeof codeContent !== 'string') { + return + } + event.clipboardData.setData('text/html', '') + event.clipboardData.setData('text/plain', codeContent) + } } } } diff --git a/src/muya/lib/contentState/pasteCtrl.js b/src/muya/lib/contentState/pasteCtrl.js index 79fd80f3..8daa549d 100644 --- a/src/muya/lib/contentState/pasteCtrl.js +++ b/src/muya/lib/contentState/pasteCtrl.js @@ -237,7 +237,8 @@ const pasteCtrl = ContentState => { const text = rawText || event.clipboardData.getData('text/plain') let html = rawHtml || event.clipboardData.getData('text/html') - + console.log(text) + console.log(html) // Support pasted URLs from Firefox. if (URL_REG.test(text) && !/\s/.test(text) && !html) { html = `${text}` diff --git a/src/muya/lib/eventHandler/clickEvent.js b/src/muya/lib/eventHandler/clickEvent.js index 8e2d9c64..1014b1f8 100644 --- a/src/muya/lib/eventHandler/clickEvent.js +++ b/src/muya/lib/eventHandler/clickEvent.js @@ -100,6 +100,7 @@ class ClickEvent { const mathRender = target.closest(`.${CLASS_OR_ID.AG_MATH_RENDER}`) const rubyRender = target.closest(`.${CLASS_OR_ID.AG_RUBY_RENDER}`) const imageWrapper = target.closest(`.${CLASS_OR_ID.AG_INLINE_IMAGE}`) + const codeCopy = target.closest('.ag-code-copy') const imageDelete = target.closest('.ag-image-icon-delete') || target.closest('.ag-image-icon-close') const mathText = mathRender && mathRender.previousElementSibling const rubyText = rubyRender && rubyRender.previousElementSibling @@ -115,6 +116,11 @@ class ClickEvent { } else if (rubyText) { selectionText(rubyText) } + if (codeCopy) { + event.stopPropagation() + event.preventDefault() + return this.muya.contentState.copyCodeBlock(event) + } // Handle delete inline iamge by click delete icon. if (imageDelete && imageWrapper) { const imageInfo = getImageInfo(imageWrapper) diff --git a/src/muya/lib/eventHandler/clipboard.js b/src/muya/lib/eventHandler/clipboard.js index dc67c602..fdfd1026 100644 --- a/src/muya/lib/eventHandler/clipboard.js +++ b/src/muya/lib/eventHandler/clipboard.js @@ -60,10 +60,11 @@ class Clipboard { /** * Copy the anchor block(table, paragraph, math block etc) with the info + * @param {string|object} type copyBlock or copyCodeContent * @param {string|object} info is the block key if it's string, or block if it's object */ - copy (info) { - this._copyType = 'copyBlock' + copy (type, info) { + this._copyType = type this._copyInfo = info document.execCommand('copy') } diff --git a/src/muya/lib/index.js b/src/muya/lib/index.js index 93a2ef33..8ec19ff3 100644 --- a/src/muya/lib/index.js +++ b/src/muya/lib/index.js @@ -361,7 +361,7 @@ class Muya { * @param {string|object} key the block key or block */ copy (info) { - return this.clipboard.copy(info) + return this.clipboard.copy('copyBlock', info) } setOptions (options, needRender = false) { diff --git a/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js b/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js index 551980ac..30d56733 100644 --- a/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js +++ b/src/muya/lib/parser/render/renderBlock/renderContainerBlock.js @@ -2,6 +2,7 @@ import { CLASS_OR_ID } from '../../../config' import { renderTableTools } from './renderToolBar' import { renderEditIcon } from './renderContainerEditIcon' import renderLineNumberRows from './renderLineNumber' +import renderCopyButton from './renderCopyButton' import { renderLeftBar, renderBottomBar } from './renderTableDargBar' import { h } from '../snabbdom' @@ -50,6 +51,9 @@ export default function renderContainerBlock (parent, block, activeBlocks, match if (typeof lang === 'string' && !!lang) { selector += `.language-${lang.replace(/[#.]{1}/g, '')}` } + if (type === 'pre') { + children.unshift(renderCopyButton()) + } if (this.muya.options.codeBlockLineNumbers) { if (type === 'pre') { selector += '.line-numbers' diff --git a/src/muya/lib/parser/render/renderBlock/renderCopyButton.js b/src/muya/lib/parser/render/renderBlock/renderCopyButton.js new file mode 100644 index 00000000..5419f20d --- /dev/null +++ b/src/muya/lib/parser/render/renderBlock/renderCopyButton.js @@ -0,0 +1,21 @@ +import { h } from '../snabbdom' +import copyIcon from '../../../assets/pngicon/copy/2.png' + +const renderCopyButton = () => { + const selector = 'a.ag-code-copy' + const iconVnode = h('i.icon', h('i.icon-inner', { + style: { + background: `url(${copyIcon}) no-repeat`, + 'background-size': '100%' + } + }, '')) + + return h(selector, { + attrs: { + title: 'Copy', + contenteditable: 'false' + } + }, iconVnode) +} + +export default renderCopyButton From 079e654131167899c1ca66057a7e595f0b4cdc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E5=86=89?= Date: Fri, 1 Nov 2019 18:59:05 +0800 Subject: [PATCH 3/5] Fix style bug --- src/muya/lib/assets/styles/index.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/muya/lib/assets/styles/index.css b/src/muya/lib/assets/styles/index.css index dc6acda8..ec94dfe7 100644 --- a/src/muya/lib/assets/styles/index.css +++ b/src/muya/lib/assets/styles/index.css @@ -533,7 +533,7 @@ pre.ag-front-matter span.ag-code-content:first-of-type:empty::after { } pre[data-role$='code'] span.ag-language-input:empty::after { - content: 'Input Language...'; + content: 'Input Language Identifier...'; color: var(--editorColor10); } @@ -1149,18 +1149,18 @@ pre:not(.ag-active):hover .ag-code-copy { left: -16px; } -pre[class*="language-"].line-numbers { +pre.ag-paragraph.line-numbers { position: relative; padding-left: 2.5em; counter-reset: linenumber; } -pre[class*="language-"].line-numbers > code { +pre.ag-paragraph.line-numbers > code { position: relative; white-space: inherit; } -figure:not(.ag-active) pre[class*="language-"].line-numbers { +figure:not(.ag-active) pre.ag-paragraph.line-numbers { display: none; } From 239de6f34cef185ba1ceef29c34acd7556c653c0 Mon Sep 17 00:00:00 2001 From: jocs Date: Sun, 3 Nov 2019 13:44:23 +0800 Subject: [PATCH 4/5] update line number position --- src/muya/lib/assets/styles/index.css | 5 ++ src/muya/lib/contentState/codeBlockCtrl.js | 15 +++++ src/muya/lib/contentState/index.js | 2 +- src/muya/lib/contentState/pasteCtrl.js | 3 +- src/muya/lib/eventHandler/resize.js | 28 +++++++++ src/muya/lib/index.js | 2 + .../render/renderBlock/renderCopyButton.js | 2 +- src/muya/lib/utils/resizeCodeLineNumber.js | 57 +++++++++++++++++++ 8 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 src/muya/lib/eventHandler/resize.js create mode 100644 src/muya/lib/utils/resizeCodeLineNumber.js diff --git a/src/muya/lib/assets/styles/index.css b/src/muya/lib/assets/styles/index.css index c9ab6d3b..88f0a1aa 100644 --- a/src/muya/lib/assets/styles/index.css +++ b/src/muya/lib/assets/styles/index.css @@ -1226,6 +1226,11 @@ figure:not(.ag-active) pre.ag-paragraph.line-numbers { } +.line-numbers-sizer { + white-space: pre-line; + word-break: break-all; +} + .line-numbers-rows > span { pointer-events: none; display: block; diff --git a/src/muya/lib/contentState/codeBlockCtrl.js b/src/muya/lib/contentState/codeBlockCtrl.js index 4bc23680..f5b71131 100644 --- a/src/muya/lib/contentState/codeBlockCtrl.js +++ b/src/muya/lib/contentState/codeBlockCtrl.js @@ -1,4 +1,5 @@ import { loadLanguage } from '../prism/index' +import resizeCodeBlockLineNumber from '../utils/resizeCodeLineNumber' import selection from '../selection' const CODE_UPDATE_REP = /^`{3,}(.*)/ @@ -135,6 +136,20 @@ const codeBlockCtrl = ContentState => { const codeContent = codeBlock.children[0].text this.muya.clipboard.copy('copyCodeContent', codeContent) } + + ContentState.prototype.resizeLineNumber = function () { + const { codeBlockLineNumbers } = this.muya.options + if (!codeBlockLineNumbers) { + return + } + + const codeBlocks = document.querySelectorAll('pre.line-numbers') + if (codeBlocks.length) { + for (const ele of codeBlocks) { + resizeCodeBlockLineNumber(ele) + } + } + } } export default codeBlockCtrl diff --git a/src/muya/lib/contentState/index.js b/src/muya/lib/contentState/index.js index 735dd93b..67996403 100644 --- a/src/muya/lib/contentState/index.js +++ b/src/muya/lib/contentState/index.js @@ -205,7 +205,7 @@ class ContentState { } postRender () { - // do nothing. + this.resizeLineNumber() } render (isRenderCursor = true, clearCache = false) { diff --git a/src/muya/lib/contentState/pasteCtrl.js b/src/muya/lib/contentState/pasteCtrl.js index 8daa549d..79fd80f3 100644 --- a/src/muya/lib/contentState/pasteCtrl.js +++ b/src/muya/lib/contentState/pasteCtrl.js @@ -237,8 +237,7 @@ const pasteCtrl = ContentState => { const text = rawText || event.clipboardData.getData('text/plain') let html = rawHtml || event.clipboardData.getData('text/html') - console.log(text) - console.log(html) + // Support pasted URLs from Firefox. if (URL_REG.test(text) && !/\s/.test(text) && !html) { html = `${text}` diff --git a/src/muya/lib/eventHandler/resize.js b/src/muya/lib/eventHandler/resize.js new file mode 100644 index 00000000..93561056 --- /dev/null +++ b/src/muya/lib/eventHandler/resize.js @@ -0,0 +1,28 @@ +import resizeCodeBlockLineNumber from '../utils/resizeCodeLineNumber' + +class Resize { + constructor (muya) { + this.muya = muya + this.timer = null + this.listen() + } + + listen () { + window.addEventListener('resize', function () { + if (this.timer) { + clearTimeout(this.timer) + } + this.timer = setTimeout(() => { + console.log('wwww') + const codeBlocks = document.querySelectorAll('pre.line-numbers') + if (codeBlocks.length) { + for (const ele of codeBlocks) { + resizeCodeBlockLineNumber(ele) + } + } + }, 300) + }) + } +} + +export default Resize diff --git a/src/muya/lib/index.js b/src/muya/lib/index.js index 8ec19ff3..2891b480 100644 --- a/src/muya/lib/index.js +++ b/src/muya/lib/index.js @@ -4,6 +4,7 @@ import MouseEvent from './eventHandler/mouseEvent' import Clipboard from './eventHandler/clipboard' import Keyboard from './eventHandler/keyboard' import DragDrop from './eventHandler/dragDrop' +import Resize from './eventHandler/resize' import ClickEvent from './eventHandler/clickEvent' import { CLASS_OR_ID, MUYA_DEFAULT_OPTION } from './config' import { wordCount } from './utils' @@ -41,6 +42,7 @@ class Muya { this.clickEvent = new ClickEvent(this) this.keyboard = new Keyboard(this) this.dragdrop = new DragDrop(this) + this.resize = new Resize(this) this.mouseEvent = new MouseEvent(this) this.init() } diff --git a/src/muya/lib/parser/render/renderBlock/renderCopyButton.js b/src/muya/lib/parser/render/renderBlock/renderCopyButton.js index 5419f20d..b6847c0c 100644 --- a/src/muya/lib/parser/render/renderBlock/renderCopyButton.js +++ b/src/muya/lib/parser/render/renderBlock/renderCopyButton.js @@ -12,7 +12,7 @@ const renderCopyButton = () => { return h(selector, { attrs: { - title: 'Copy', + title: 'Copy content', contenteditable: 'false' } }, iconVnode) diff --git a/src/muya/lib/utils/resizeCodeLineNumber.js b/src/muya/lib/utils/resizeCodeLineNumber.js new file mode 100644 index 00000000..e125abba --- /dev/null +++ b/src/muya/lib/utils/resizeCodeLineNumber.js @@ -0,0 +1,57 @@ +/** + * This file copy from prismjs/plugins/prism-line-number + */ + +/** + * Regular expression used for determining line breaks + * @type {RegExp} + */ +const NEW_LINE_EXP = /\n(?!$)/g + +/** + * Returns style declarations for the element + * @param {Element} element + */ +const getStyles = function (element) { + if (!element) { + return null + } + + return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null) +} + +/** +* Resizes line numbers spans according to height of line of code +* @param {Element} element
 element
+*/
+const resizeCodeBlockLineNumber = function (element) {
+  const codeStyles = getStyles(element)
+  const whiteSpace = codeStyles['white-space']
+
+  if (whiteSpace === 'pre' || whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line') {
+    const codeElement = element.querySelector('code')
+    const lineNumbersWrapper = element.querySelector('.line-numbers-rows')
+    let lineNumberSizer = element.querySelector('.line-numbers-sizer')
+    const codeLines = codeElement.textContent.split(NEW_LINE_EXP)
+
+    if (!lineNumberSizer) {
+      lineNumberSizer = document.createElement('span')
+      lineNumberSizer.className = 'line-numbers-sizer'
+
+      codeElement.appendChild(lineNumberSizer)
+    }
+
+    lineNumberSizer.style.display = 'block'
+
+    codeLines.forEach(function (line, lineNumber) {
+      lineNumberSizer.textContent = line || '\n'
+      const lineSize = lineNumberSizer.getBoundingClientRect().height
+      lineNumbersWrapper.children[lineNumber].style.height = lineSize + 'px'
+    })
+
+    lineNumberSizer.textContent = ''
+    lineNumberSizer.style.display = 'none'
+  }
+}
+
+export default resizeCodeBlockLineNumber

From c3946b4da953f0570baa7f38ccdcda3f0861ee23 Mon Sep 17 00:00:00 2001
From: jocs 
Date: Sun, 3 Nov 2019 13:50:40 +0800
Subject: [PATCH 5/5] use throttle util

---
 src/muya/lib/eventHandler/resize.js | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/src/muya/lib/eventHandler/resize.js b/src/muya/lib/eventHandler/resize.js
index 93561056..872885bf 100644
--- a/src/muya/lib/eventHandler/resize.js
+++ b/src/muya/lib/eventHandler/resize.js
@@ -1,27 +1,21 @@
 import resizeCodeBlockLineNumber from '../utils/resizeCodeLineNumber'
+import { throttle } from '../utils'
 
 class Resize {
   constructor (muya) {
     this.muya = muya
-    this.timer = null
     this.listen()
   }
 
   listen () {
-    window.addEventListener('resize', function () {
-      if (this.timer) {
-        clearTimeout(this.timer)
-      }
-      this.timer = setTimeout(() => {
-        console.log('wwww')
-        const codeBlocks = document.querySelectorAll('pre.line-numbers')
-        if (codeBlocks.length) {
-          for (const ele of codeBlocks) {
-            resizeCodeBlockLineNumber(ele)
-          }
+    window.addEventListener('resize', throttle(() => {
+      const codeBlocks = document.querySelectorAll('pre.line-numbers')
+      if (codeBlocks.length) {
+        for (const ele of codeBlocks) {
+          resizeCodeBlockLineNumber(ele)
         }
-      }, 300)
-    })
+      }
+    }, 300))
   }
 }