diff --git a/apps/editor/karma.conf.js b/apps/editor/karma.conf.js index 2f53eb0e52..c68e2a55a1 100644 --- a/apps/editor/karma.conf.js +++ b/apps/editor/karma.conf.js @@ -85,7 +85,7 @@ module.exports = function(config) { frameworks: ['jasmine-ajax', 'jasmine-jquery', 'jasmine'], files: [ 'node_modules/codemirror/lib/codemirror.css', - 'src/css/toastui-editor.css', + 'src/css/editor.css', 'test/unit/fixtures/*.html', 'test/unit/index.js' ], diff --git a/apps/editor/src/css/toastui-editor-contents.css b/apps/editor/src/css/contents.css similarity index 100% rename from apps/editor/src/css/toastui-editor-contents.css rename to apps/editor/src/css/contents.css diff --git a/apps/editor/src/css/toastui-editor.css b/apps/editor/src/css/editor.css similarity index 98% rename from apps/editor/src/css/toastui-editor.css rename to apps/editor/src/css/editor.css index f3c7ac70a4..393f6fa831 100644 --- a/apps/editor/src/css/toastui-editor.css +++ b/apps/editor/src/css/editor.css @@ -929,39 +929,6 @@ border: 1px solid #ebebeb; } -.CodeMirror .cm-header { - font-weight: bold; - color: inherit; -} - -.CodeMirror .cm-header-1 { - font-size: 24px; -} - -.CodeMirror .cm-header-2 { - font-size: 22px; -} - -.CodeMirror .cm-header-3 { - font-size: 20px; -} - -.CodeMirror .cm-header-4 { - font-size: 18px; -} - -.CodeMirror .cm-header-5 { - font-size: 16px; -} - -.CodeMirror .cm-header-6 { - font-size: 14px; -} - -.CodeMirror .cm-variable-2 { - color: inherit; -} - .tui-editor-pseudo-clipboard { position: fixed; left: -1000px; diff --git a/apps/editor/src/css/md-syntax-highlighting.css b/apps/editor/src/css/md-syntax-highlighting.css new file mode 100644 index 0000000000..c7810d92df --- /dev/null +++ b/apps/editor/src/css/md-syntax-highlighting.css @@ -0,0 +1,94 @@ +.te-md-container .CodeMirror { + color: #000; + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.tui-md-heading1 { + font-size: 24px; +} + +.tui-md-heading2 { + font-size: 22px; +} + +.tui-md-heading3 { + font-size: 20px; +} + +.tui-md-heading4 { + font-size: 18px; +} + +.tui-md-heading5 { + font-size: 16px; +} + +.tui-md-heading6 { + font-size: 14px; +} + +.tui-md-strong, +.tui-md-heading, +.tui-md-list-item.tui-md-list-item-bullet, +.tui-md-list-item.tui-md-meta { + font-weight: bold; +} + +.tui-md-emph { + font-style: italic; +} + +.tui-md-strike { + text-decoration: line-through; +} + +.tui-md-strike.tui-md-delimiter { + text-decoration: none; +} + +.tui-md-delimiter, +.tui-md-thematic-break, +.tui-md-link, +.tui-md-table, +.tui-md-block-quote { + color: #ccc; +} + +.tui-md-meta, +.tui-md-link.tui-md-link-url.tui-md-marked-text { + color: #999; +} + +.tui-md-block-quote.tui-md-marked-text { + color: #555; +} + +.tui-md-table.tui-md-marked-text { + color: #000; +} + +.tui-md-link.tui-md-link-desc.tui-md-marked-text, +.tui-md-list-item-odd.tui-md-list-item-bullet { + color: #5182b6; +} + +.tui-md-code.tui-md-marked-text, +.tui-md-list-item-even.tui-md-list-item-bullet { + color: #c1788b; +} + +.tui-md-code { + background-color: #f9f2f4; +} + +.tui-md-code-block.CodeMirror-linebackground { + left: 20px; + right: 20px; + background-color: #f5f7f8; +} + +.tui-md-code.tui-md-marked-text, +.tui-md-code-block.tui-md-marked-text { + font-family: Consolas, Courier, 'Apple SD 산돌고딕 Neo', -apple-system, 'Lucida Grande', + 'Apple SD Gothic Neo', '맑은 고딕', 'Malgun Gothic', 'Segoe UI', '돋움', dotum, sans-serif; +} diff --git a/apps/editor/src/css/old/contents.css b/apps/editor/src/css/old/contents.css new file mode 100644 index 0000000000..28978d74e4 --- /dev/null +++ b/apps/editor/src/css/old/contents.css @@ -0,0 +1,256 @@ +@charset "utf-8"; +.CodeMirror { + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.tui-editor-contents *:not(table) { + line-height: 160%; + box-sizing: content-box; +} + +.tui-editor-contents i, +.tui-editor-contents cite, +.tui-editor-contents em, +.tui-editor-contents var, +.tui-editor-contents address, +.tui-editor-contents dfn { + font-style: italic; +} + +.tui-editor-contents strong { + font-weight: bold; +} + +.tui-editor-contents p { + margin: 10px 0; + color: #555; +} + +.tui-editor-contents > h1:first-of-type, +.tui-editor-contents > div > div:first-of-type h1 { + margin-top: 14px; +} + +.tui-editor-contents h1, +.tui-editor-contents h2, +.tui-editor-contents h3, +.tui-editor-contents h5 { + font-weight: bold; +} + +.tui-editor-contents h1 { + font-size: 1.6rem; + line-height: 28px; + border-bottom: 3px double #999; + margin: 52px 0 15px 0; + padding-bottom: 7px; + color: #000; +} + +.tui-editor-contents h2 { + font-size: 1.3rem; + line-height: 23px; + border-bottom: 1px solid #dbdbdb; + margin: 30px 0 13px 0; + padding-bottom: 7px; + color: #333; +} + +.tui-editor-contents h3, +.tui-editor-contents h4 { + font-size: 1.2rem; + line-height: 18px; + margin: 20px 0 2px; + color: #333; +} + +.tui-editor-contents h5, +.tui-editor-contents h6 { + font-size: 1rem; + line-height: 17px; + margin: 10px 0 -4px; + color: #333; +} + +.tui-editor-contents blockquote { + margin: 15px 0; +} + +.tui-editor-contents blockquote { + border-left: 4px solid #dddddd; + padding: 0 15px; + color: #777777; +} + +.tui-editor-contents blockquote > :first-child { + margin-top: 0; +} + +.tui-editor-contents blockquote > :last-child { + margin-bottom: 0; +} + +.tui-editor-contents pre, +.tui-editor-contents code { + font-family: Consolas, Courier, 'Apple SD 산돌고딕 Neo', -apple-system, 'Lucida Grande', + 'Apple SD Gothic Neo', '맑은 고딕', 'Malgun Gothic', 'Segoe UI', '돋움', dotum, sans-serif; + border: 0; + border-radius: 0; +} + +.tui-editor-contents pre { + margin: 2px 0 8px; + padding: 18px; + background-color: #f5f7f8; +} + +.tui-editor-contents code { + color: #c1788b; + padding: 4px 4px 2px 0; + letter-spacing: -0.3px; +} + +.tui-editor-contents pre code { + padding: 0; + color: inherit; + white-space: pre-wrap; + background-color: transparent; +} + +.tui-editor-contents pre.addon { + border: 1px solid #e8ebed; + background-color: #fff; +} + +.tui-editor-contents img { + margin: 4px 0 10px; + box-sizing: border-box; + vertical-align: top; + max-width: 100%; +} + +.tui-editor-contents table { + margin: 2px 0 14px; + color: #555; + width: auto; + border-collapse: collapse; + box-sizing: border-box; +} + +.tui-editor-contents table th, +.tui-editor-contents table td { + height: 32px; + padding: 5px 14px 5px 12px; +} + +.tui-editor-contents table td { + border: 1px solid #eaeaea; +} + +.tui-editor-contents table th { + border: 1px solid #72777b; + border-top: 0; + background-color: #7b8184; + font-weight: 300; + color: #fff; + padding-top: 6px; +} + +.tui-editor-contents ul, +.tui-editor-contents menu, +.tui-editor-contents ol, +.tui-editor-contents dir { + display: block; + list-style-type: disc; + padding-left: 17px; + margin: 6px 0 10px; + color: #555; +} + +.tui-editor-contents ol { + list-style-type: decimal; +} + +.tui-editor-contents ul ul, +.tui-editor-contents ul ol, +.tui-editor-contents ol ol, +.tui-editor-contents ol ul { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.tui-editor-contents ul li, +.tui-editor-contents ol li { + position: relative; +} + +.tui-editor-contents ul p, +ol p { + margin: 0; +} + +.tui-editor-contents ul li.task-list-item:before, +.tui-editor-contents ol li.task-list-item:before, +.tui-editor-contents pre ul li:before { + content: ''; +} + +.tui-editor-contents hr { + border-top: 1px solid #eee; + margin: 16px 0; +} + +.tui-editor-contents a { + text-decoration: underline; + color: #5286bc; +} + +.tui-editor-contents a:hover { + color: #007cff; +} + +.tui-editor-contents { + font-size: 13px; + margin: 0; + padding: 0; +} + +.tui-editor-contents .task-list-item { + border: 0; + list-style: none; + padding-left: 22px; + margin-left: -22px; + min-height: 20px; +} + +.tui-editor-contents .task-list-item:before { + background-repeat: no-repeat; + background-size: 16px 16px; + background-position: center; + content: ''; + height: 18px; + width: 18px; + position: absolute; + left: 0; + top: 1px; + cursor: pointer; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAADdJREFUKBVjvHv37n8GMgALSI+SkhJJWu/du8fARJIOJMWjGpECA505GjjoIYLEB6dVUNojFQAA/1MJUFWet/4AAAAASUVORK5CYII='); +} + +.tui-editor-contents .task-list-item.checked:before { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAMpJREFUKBVjjJ/64D8DGYCJDD1gLbTVyM3OxJDiJMzAxcYIdyALnIWDAdJU7i/OICfCxsDMxMgwc88bwk5F1vTs/W+GFUffwY2H+1FBlI2hLliCQYCbGSyJrqlzwwuGj9//YWoMtRBgUBJnZ6gMEGeQFWaFOw9kE7omkG5GWDyCPF7mJ86gIMbO8P//fwZGRkYGXJpAGuFO/fbrP0PXppcMD179JKgJRSOIA9N8/NZXrM4DqYEBjOgAaYYFOUwRNhruVGyS+MTI1ggAx8NTGcUtFVQAAAAASUVORK5CYII='); +} + +.tui-editor-contents .task-list-item input[type='checkbox'], +.tui-editor-contents .task-list-item .task-list-item-checkbox { + margin-left: -17px; + margin-right: 3.8px; + margin-top: 3px; +} + +.tui-editor-contents-placeholder:before { + content: attr(data-placeholder); + color: grey; + line-height: 160%; + position: absolute; +} diff --git a/apps/editor/src/css/old/md-syntax-highlighting.css b/apps/editor/src/css/old/md-syntax-highlighting.css new file mode 100644 index 0000000000..b09c4d22d9 --- /dev/null +++ b/apps/editor/src/css/old/md-syntax-highlighting.css @@ -0,0 +1,78 @@ +.te-md-container .CodeMirror { + color: #000; + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +.tui-md-heading1 { + font-size: 24px; +} + +.tui-md-heading2 { + font-size: 22px; +} + +.tui-md-heading3 { + font-size: 20px; +} + +.tui-md-heading4 { + font-size: 18px; +} + +.tui-md-heading5 { + font-size: 16px; +} + +.tui-md-heading6 { + font-size: 14px; +} + +.tui-md-strong, +.tui-md-heading { + font-weight: bold; +} + +.tui-md-emph { + font-style: italic; +} + +.tui-md-strike { + text-decoration: line-through; +} + +.tui-md-thematic-break { + color: #ccc; +} + +.tui-md-link.tui-md-link-desc { + color: #00c; +} + +.tui-md-link.tui-md-link-url { + color: #a11; +} + +.tui-md-block-quote { + color: #090; +} + +.tui-md-code, +.tui-md-code-block { + color: #a50; +} + +.tui-md-list-item.first { + color: #000; +} + +.tui-md-list-item.second { + color: #085; +} + +.tui-md-list-item.third { + color: #708; +} + +.tui-md-list-item.tui-md-delimiter { + color: #555; +} diff --git a/apps/editor/src/js/index.js b/apps/editor/src/js/index.js index fafbc53f61..b2eb7028d3 100644 --- a/apps/editor/src/js/index.js +++ b/apps/editor/src/js/index.js @@ -4,8 +4,9 @@ */ import Editor from './editor'; -import '../css/toastui-editor.css'; -import '../css/toastui-editor-contents.css'; +import '../css/editor.css'; +import '../css/contents.css'; +import '../css/md-syntax-highlighting.css'; import './i18n/en-us'; diff --git a/apps/editor/src/js/indexOldStyle.js b/apps/editor/src/js/indexOldStyle.js new file mode 100644 index 0000000000..0c1b95c596 --- /dev/null +++ b/apps/editor/src/js/indexOldStyle.js @@ -0,0 +1,8 @@ +/** + * @fileoverview entry point to extract old.css files + * @author NHN FE Development Lab + */ + +import '../css/editor.css'; +import '../css/contents.css'; +import '../css/old/md-syntax-highlighting.css'; diff --git a/apps/editor/src/js/indexViewer.js b/apps/editor/src/js/indexViewer.js index 0b0b04f5d2..a2add6b257 100644 --- a/apps/editor/src/js/indexViewer.js +++ b/apps/editor/src/js/indexViewer.js @@ -4,6 +4,6 @@ */ import Viewer from './viewer'; -import '../css/toastui-editor-contents.css'; +import '../css/contents.css'; export default Viewer; diff --git a/apps/editor/src/js/markTextHelper.js b/apps/editor/src/js/markTextHelper.js new file mode 100644 index 0000000000..dc142609b3 --- /dev/null +++ b/apps/editor/src/js/markTextHelper.js @@ -0,0 +1,283 @@ +import isFunction from 'tui-code-snippet/type/isFunction'; +import forEachOwnProperties from 'tui-code-snippet/collection/forEachOwnProperties'; +import { + getMdStartLine, + getMdStartCh, + getMdEndLine, + getMdEndCh, + addChPos, + setChPos +} from './utils/markdown'; + +const CLS_PREFIX = 'tui-md-'; + +const classNameMap = applyClsToValue({ + DELIM: 'delimiter', + META: 'meta', + TEXT: 'marked-text', + THEMATIC_BREAK: 'thematic-break', + CODE_BLOCK: 'code-block', + TABLE: 'table' +}); + +const delimSize = { + strong: 2, + emph: 1, + strike: 2 +}; + +function cls(...names) { + return names.map(className => `${CLS_PREFIX}${className}`).join(' '); +} + +function applyClsToValue(obj) { + forEachOwnProperties(obj, (value, key) => { + obj[key] = cls(value); + }); + + return obj; +} + +function markInfo(start, end, className) { + return { start, end, className }; +} + +function heading({ level }, start, end) { + return { + marks: [ + markInfo(start, end, cls('heading', `heading${level}`)), + markInfo(start, addChPos(start, level), classNameMap.DELIM) + ] + }; +} + +function emphasisAndStrikethrough({ type }, start, end) { + return { + marks: [ + markInfo(start, end, cls(`${type}`)), + markInfo(start, addChPos(start, delimSize[type]), classNameMap.DELIM), + markInfo(addChPos(end, -delimSize[type]), end, classNameMap.DELIM) + ] + }; +} + +function markLink(start, end, linkTextStart, lastChildCh) { + return [ + markInfo(start, end, cls('link')), + markInfo(linkTextStart, setChPos(end, lastChildCh), cls('link-desc')), + markInfo( + setChPos(start, linkTextStart.ch + 1), + setChPos(end, lastChildCh - 1), + classNameMap.TEXT + ), + markInfo(setChPos(end, lastChildCh), end, cls('link-url')), + markInfo(setChPos(end, lastChildCh + 1), addChPos(end, -1), classNameMap.TEXT) + ]; +} + +function image({ lastChild }, start, end) { + const lastChildCh = lastChild ? getMdEndCh(lastChild) + 1 : 3; // 3: length of '![]' + const linkTextEnd = addChPos(start, 1); + + return { + marks: [ + markInfo(start, linkTextEnd, classNameMap.META), + ...markLink(start, end, linkTextEnd, lastChildCh) + ] + }; +} + +function link({ lastChild }, start, end) { + const lastChildCh = lastChild ? getMdEndCh(lastChild) + 1 : 2; // 2: length of '[]' + + return { marks: markLink(start, end, start, lastChildCh) }; +} + +function code({ tickCount }, start, end) { + const openDelimEnd = addChPos(start, tickCount); + const closeDelimStart = addChPos(end, -tickCount); + + return { + marks: [ + markInfo(start, end, cls('code')), + markInfo(start, openDelimEnd, `${classNameMap.DELIM} start`), + markInfo(openDelimEnd, closeDelimStart, classNameMap.TEXT), + markInfo(closeDelimStart, end, `${classNameMap.DELIM} end`) + ] + }; +} + +function codeBlock(node, start, end, endLine) { + const { fenceOffset, fenceLength, fenceChar, info } = node; + const fenceEnd = fenceOffset + fenceLength; + let openDelimEnd = addChPos(start, fenceEnd); + + const marks = [ + markInfo(start, end, classNameMap.CODE_BLOCK), + markInfo(start, openDelimEnd, classNameMap.DELIM) + ]; + + if (info) { + openDelimEnd = setChPos(start, fenceEnd + info.length); + marks.push(markInfo(setChPos(start, fenceEnd), openDelimEnd, classNameMap.META)); + } + + const codeBlockEnd = `^(\\s{0,${fenceOffset}})(${fenceChar}{${fenceLength},})`; + const CLOSED_RX = new RegExp(codeBlockEnd); + + let closeDelimStart = end; + + if (CLOSED_RX.test(endLine)) { + closeDelimStart = setChPos(end, 0); + marks.push(markInfo(closeDelimStart, end, classNameMap.DELIM)); + } + + return { + marks: [...marks, markInfo(openDelimEnd, closeDelimStart, classNameMap.TEXT)], + lineBackground: { + start: start.line, + end: end.line, + className: classNameMap.CODE_BLOCK + } + }; +} + +function markListItemChildren(node, className) { + const marks = []; + + while (node) { + const { type } = node; + + if (type === 'paragraph' || type === 'codeBlock') { + marks.push( + markInfo( + { line: getMdStartLine(node) - 1, ch: getMdStartCh(node) - 1 }, + { line: getMdEndLine(node) - 1, ch: getMdEndCh(node) }, + className + ) + ); + } + node = node.next; + } + + return marks; +} + +function markParagraphInBlockQuote(node) { + const marks = []; + + while (node) { + marks.push( + markInfo( + { line: getMdStartLine(node) - 1, ch: getMdStartCh(node) - 1 }, + { line: getMdEndLine(node) - 1, ch: getMdEndCh(node) }, + classNameMap.TEXT + ) + ); + node = node.next; + } + + return marks; +} + +function blockQuote(node, start, end) { + let marks = + node.parent && node.parent.type !== 'blockQuote' + ? [markInfo(start, end, cls('block-quote'))] + : []; + + if (node.firstChild) { + let childMarks = []; + + if (node.firstChild.type === 'paragraph') { + childMarks = markParagraphInBlockQuote(node.firstChild.firstChild, classNameMap.TEXT); + } else if (node.firstChild.type === 'list') { + childMarks = markListItemChildren(node.firstChild, classNameMap.TEXT); + } + + marks = [...marks, ...childMarks]; + } + + return { marks }; +} + +function getClassNameOfListItem(node) { + let depth = 0; + + while (node.parent.parent && node.parent.parent.type === 'item') { + node = node.parent.parent; + depth += 1; + } + + const newClassName = ['list-item-odd', 'list-item-even'][depth % 2]; + + // @TODO remove it in the next major version + // these class names are for the legacy style 'old.css' + const oldClassName = ['fisrt', 'second', 'third'][depth % 3]; + + return `${cls('list-item', `${newClassName}`)} ${oldClassName}`; +} + +function item(node, start) { + const itemClassName = getClassNameOfListItem(node); + const { padding, task } = node.listData; + + return { + marks: [ + markInfo(start, addChPos(start, padding), `${itemClassName} ${cls('list-item-bullet')}`), + ...(task + ? [ + markInfo( + addChPos(start, padding), + addChPos(start, padding + 3), + `${itemClassName} ${classNameMap.DELIM}` + ), + markInfo(addChPos(start, padding + 1), addChPos(start, padding + 2), classNameMap.META) + ] + : []), + ...markListItemChildren(node.firstChild, `${itemClassName} ${classNameMap.TEXT}`) + ] + }; +} + +const markNodeFuncMap = { + heading, + strong: emphasisAndStrikethrough, + emph: emphasisAndStrikethrough, + strike: emphasisAndStrikethrough, + link, + image, + code, + codeBlock, + blockQuote, + item +}; + +const simpleMarkClassNameMap = { + thematicBreak: classNameMap.THEMATIC_BREAK, + table: classNameMap.TABLE, + tableCell: classNameMap.TEXT +}; + +/** + * Gets mark information to the markdown node. + * @param {Object} node - node returned from ToastMark + * @param {Object} start - start node's data + * @param {Object} end - end node's data + * @param {Object} endLine - end line's data + * @returns {?Object} mark information + * @ignore + */ +export function getMarkInfo(node, start, end, endLine) { + const { type } = node; + + if (isFunction(markNodeFuncMap[type])) { + return markNodeFuncMap[type](node, start, end, endLine); + } + + if (simpleMarkClassNameMap[type]) { + return { marks: [markInfo(start, end, simpleMarkClassNameMap[type])] }; + } + + return null; +} diff --git a/apps/editor/src/js/markdownEditor.js b/apps/editor/src/js/markdownEditor.js index d0c9ce7fdf..901fe328c0 100644 --- a/apps/editor/src/js/markdownEditor.js +++ b/apps/editor/src/js/markdownEditor.js @@ -18,19 +18,10 @@ import { getMdStartCh, getMdEndCh } from './utils/markdown'; +import { getMarkInfo } from './markTextHelper'; const keyMapper = KeyMapper.getSharedInstance(); -const tokenTypes = { - strong: 'strong', - emph: 'em', - strike: 'strikethrough', - thematicBreak: 'hr', - blockQuote: 'quote', - code: 'comment', - codeBlock: 'comment' -}; - const defaultState = { strong: false, emph: false, @@ -79,6 +70,13 @@ class MarkdownEditor extends CodeMirrorExt { */ this._latestState = null; + /** + * map of marked lines + * @type {Object. { + this.cm.removeLineClass(Number(line), 'background', 'tui-md-code-block'); + this._markedLines[line] = false; + }); } - _getClassNameOfListItem(node) { - let depth = 0; - - while (node.parent.parent && node.parent.parent.type === 'item') { - node = node.parent.parent; - depth += 1; - } - - const listItemTokens = ['variable-2', 'variable-3', 'keyword']; - const className = listItemTokens[depth % 3]; + _markNode(node) { + const from = { line: getMdStartLine(node) - 1, ch: getMdStartCh(node) - 1 }; + const to = { line: getMdEndLine(node) - 1, ch: getMdEndCh(node) }; + const markInfo = getMarkInfo(node, from, to, this.cm.getLine(to.line)); - return `cm-${className}`; - } + if (markInfo) { + const { marks = [], lineBackground = {} } = markInfo; + const { start: startLine, end: endLine, className: lineClassName } = lineBackground; - _markTextInListItemChildren(node, className) { - while (node) { - const { type, sourcepos } = node; + marks.forEach(({ start, end, className }) => { + const attributes = { [ATTR_NAME_MARK]: '' }; - if (type === 'paragraph' || type === 'codeBlock') { - const [startPosistion, endPosition] = sourcepos; - const start = { line: startPosistion[0] - 1, ch: startPosistion[1] - 1 }; - const end = { line: endPosition[0] - 1, ch: endPosition[1] }; + this.cm.markText(start, end, { className, attributes }); + }); - this._markText(start, end, className); + for (let index = startLine; index <= endLine; index += 1) { + this.cm.addLineClass(index, 'background', lineClassName); + this._markedLines[index] = true; } - node = node.next; } } - _markTextInListItem(node, start) { - const className = this._getClassNameOfListItem(node); - const { padding, task } = node.listData; - - this._markText( - { line: start.line, ch: start.ch }, - { line: start.line, ch: start.ch + padding }, - className - ); - - if (task) { - this._markText( - { line: start.line, ch: start.ch + padding }, - { line: start.line, ch: start.ch + padding + 3 }, - 'cm-meta' - ); - } - - this._markTextInListItemChildren(node.firstChild, className); - } - /** * Return whether state changed or not * @param {object} previousState - Previous state diff --git a/apps/editor/src/js/utils/markdown.js b/apps/editor/src/js/utils/markdown.js index 43539a2774..3e2371126e 100644 --- a/apps/editor/src/js/utils/markdown.js +++ b/apps/editor/src/js/utils/markdown.js @@ -83,3 +83,17 @@ export function traverseParentNodes(mdNode, iteratee) { iteratee(mdNode); } } + +export function addChPos(originPos, addedCh) { + return { + line: originPos.line, + ch: originPos.ch + addedCh + }; +} + +export function setChPos(originPos, newCh) { + return { + line: originPos.line, + ch: newCh + }; +} diff --git a/apps/editor/test/unit/codeMirrorExt.spec.js b/apps/editor/test/unit/codeMirrorExt.spec.js index 9d202db941..0affda65be 100644 --- a/apps/editor/test/unit/codeMirrorExt.spec.js +++ b/apps/editor/test/unit/codeMirrorExt.spec.js @@ -11,7 +11,7 @@ describe('CodeMirrorExt', () => { beforeEach(() => { jasmine.getStyleFixtures().fixturesPath = '/base'; - loadStyleFixtures('src/css/toastui-editor.css'); + loadStyleFixtures('src/css/editor.css'); loadStyleFixtures('node_modules/codemirror/lib/codemirror.css'); container = document.createElement('div'); diff --git a/apps/editor/test/unit/editor.spec.js b/apps/editor/test/unit/editor.spec.js index e6f2b2919a..cf08cf232c 100644 --- a/apps/editor/test/unit/editor.spec.js +++ b/apps/editor/test/unit/editor.spec.js @@ -41,7 +41,7 @@ describe('Editor', () => { describe('Api', () => { beforeEach(() => { jasmine.getStyleFixtures().fixturesPath = '/base'; - loadStyleFixtures('node_modules/codemirror/lib/codemirror.css', 'src/css/toastui-editor.css'); + loadStyleFixtures('node_modules/codemirror/lib/codemirror.css', 'src/css/editor.css'); container = document.createElement('div'); document.body.appendChild(container); diff --git a/apps/editor/test/unit/integration/editor.spec.js b/apps/editor/test/unit/integration/editor.spec.js index 43f475c692..9ebca45145 100644 --- a/apps/editor/test/unit/integration/editor.spec.js +++ b/apps/editor/test/unit/integration/editor.spec.js @@ -9,7 +9,7 @@ describe('Editor', () => { beforeEach(() => { jasmine.getStyleFixtures().fixturesPath = '/base'; - loadStyleFixtures('node_modules/codemirror/lib/codemirror.css', 'src/css/toastui-editor.css'); + loadStyleFixtures('node_modules/codemirror/lib/codemirror.css', 'src/css/editor.css'); container = document.createElement('div'); document.body.appendChild(container); }); diff --git a/apps/editor/test/unit/ui/defaultToolbar.spec.js b/apps/editor/test/unit/ui/defaultToolbar.spec.js index 94f61c3b1a..ae5a1ac9b4 100644 --- a/apps/editor/test/unit/ui/defaultToolbar.spec.js +++ b/apps/editor/test/unit/ui/defaultToolbar.spec.js @@ -37,7 +37,7 @@ describe('DefaultToolbar', () => { beforeEach(() => { jasmine.getStyleFixtures().fixturesPath = '/base'; - loadStyleFixtures('src/css/toastui-editor.css'); + loadStyleFixtures('src/css/editor.css'); $container = $('
'); $('body').append($container); diff --git a/apps/editor/test/unit/ui/scrollSyncSplit.spec.js b/apps/editor/test/unit/ui/scrollSyncSplit.spec.js index ae3051a657..3d7c35092f 100644 --- a/apps/editor/test/unit/ui/scrollSyncSplit.spec.js +++ b/apps/editor/test/unit/ui/scrollSyncSplit.spec.js @@ -10,7 +10,7 @@ describe('ScrollSyncSplit', () => { beforeEach(done => { jasmine.getStyleFixtures().fixturesPath = '/base'; - loadStyleFixtures('src/css/toastui-editor.css'); + loadStyleFixtures('src/css/editor.css'); container = document.createElement('div'); container.style.position = 'relative'; diff --git a/apps/editor/webpack.config.js b/apps/editor/webpack.config.js index 1654e9f653..356b01c4f9 100644 --- a/apps/editor/webpack.config.js +++ b/apps/editor/webpack.config.js @@ -105,9 +105,23 @@ function addFileManagerPlugin(config) { // empty JavaScript files are created. (e.g. toastui-editor-layout.js) // These files are unnecessary, so use the FileManager plugin to delete them. const options = minify - ? [{ delete: ['./dist/cdn/toastui-editor-layout.min.js'] }] + ? [ + { + delete: [ + './dist/cdn/toastui-editor-layout.min.js', + './dist/cdn/toastui-editor-old.min.js', + './dist/cdn/toastui-editor-viewer-old.min.js' + ] + } + ] : [ - { delete: ['./dist/toastui-editor-layout.js'] }, + { + delete: [ + './dist/toastui-editor-layout.js', + './dist/toastui-editor-old.js', + './dist/toastui-editor-viewer-old.js' + ] + }, { copy: [{ source: './dist/*.{js,css}', destination: './dist/cdn' }] } ]; @@ -167,7 +181,10 @@ function setProductionConfig(config) { config.entry = { editor: ENTRY_EDITOR, 'editor-viewer': ENTRY_VIEWER, - 'editor-layout': './src/css/toastui-editor.css' + 'editor-layout': './src/css/editor.css', + // legacy styles + 'editor-old': './src/js/indexOldStyle.js', + 'editor-viewer-old': './src/css/old/contents.css' }; addFileManagerPlugin(config);