Skip to content

Commit

Permalink
feat: use squire official (fix #1018)
Browse files Browse the repository at this point in the history
  • Loading branch information
최규우/FE개발랩/NE committed Dec 8, 2017
1 parent 6975c19 commit b9a7788
Show file tree
Hide file tree
Showing 16 changed files with 614 additions and 349 deletions.
2 changes: 1 addition & 1 deletion bower.json
Expand Up @@ -34,7 +34,7 @@
"markdown-it": "^8.3.1",
"toMark": "https://github.com/nhnent/toMark.git#0.0.18",
"tui-component-colorpicker": "~1.0.2",
"squire-rte": "kyuwoo-choi/Squire#tui-editor-release",
"squire-rte": "https://github.com/neilj/Squire.git#306230d0df9b38047cd06204476ddc0582569cfd",
"plantuml-encoder": "^1.2.4",
"tui-chart": "^2.9.4"
},
Expand Down
165 changes: 142 additions & 23 deletions src/js/wwListManager.js
Expand Up @@ -6,6 +6,8 @@
import domUtils from './domUtils';

const FIND_LI_ELEMENT = /<li/i;
const DIV_OR_LI = 'DIV,LI';
const UL_OR_OL = 'OL,UL';

/**
* Class WwListManager
Expand Down Expand Up @@ -48,18 +50,23 @@ class WwListManager {
* @private
*/
_initEvent() {
this.eventManager.listen('wysiwygSetValueBefore', html => this._convertToArbitraryNestingList(html));

this.eventManager.listen('wysiwygRangeChangeAfter', () => {
this._findAndRemoveEmptyList();
this._removeBranchListAll();
this._wrapDefaultBlockToListInner();
});

this.eventManager.listen('wysiwygSetValueAfter', () => {
this._removeBranchListAll();
this._wrapDefaultBlockToListInner();
});

this.eventManager.listen('wysiwygProcessHTMLText', html => this._prepareInsertBlankToBetweenSameList(html));
this.eventManager.listen('wysiwygProcessHTMLText', html => {
html = this._insertBlankToBetweenSameList(html);
html = this._convertFromArbitraryNestingList(html);

return html;
});

this.eventManager.listen('convertorAfterHtmlToMarkdownConverted',
markdown => markdown.replace(/:BLANK_LINE:\n/g, ''));
Expand Down Expand Up @@ -87,7 +94,7 @@ class WwListManager {
if (range.collapsed) {
if (this.wwe.getEditor().hasFormat('LI')) {
ev.preventDefault();
const $ul = $(range.startContainer).closest('li').children('ul, ol');
const $ul = $(range.startContainer).closest('li').children(UL_OR_OL);

this.eventManager.emit('command', 'DecreaseDepth');

Expand Down Expand Up @@ -131,7 +138,7 @@ class WwListManager {
* @private
*/
_findAndRemoveEmptyList() {
this.wwe.get$Body().find('ul,ol').each((index, node) => {
this.wwe.get$Body().find(UL_OR_OL).each((index, node) => {
if (!(FIND_LI_ELEMENT.test(node.innerHTML))) {
$(node).remove();
}
Expand Down Expand Up @@ -177,22 +184,62 @@ class WwListManager {
$firstLi.remove();
}

_insertBlankToBetweenSameList(html) {
return html.replace(/<\/(ul|ol)>(<br \/>|<br>){0,}<\1>/g, '</$1>:BLANK_LINE:<$1>');
}

/**
* _wrapDefaultBlockToListInner
* Wrap default block to list inner contents
* make arbitrary nesting list out of standard list
* `<ul><li>text<ul><li>text2</li></ul></li></ul>` to
* `<ul><li>text</li><ul><li>text2</li></ul></ul>`
* @param {string} html string to convert
* @returns {string} converted HTML text
* @private
*/
_wrapDefaultBlockToListInner() {
this.wwe.get$Body().find('li').each((index, node) => {
if ($(node).children('div, p').length <= 0) {
$(node).wrapInner('<div />');
$(node).find('div').children('ul, ol').appendTo(node);
}
});
_convertToArbitraryNestingList(html) {
const NESTED_LIST_QUERY = 'li > ul, li > ol';
const wrapper = document.createElement('div');
wrapper.innerHTML = html;

let nestedList = wrapper.querySelector(NESTED_LIST_QUERY);
while (nestedList !== null) {
const parentLI = nestedList.parentNode;
const parentList = parentLI.parentNode;

parentList.insertBefore(nestedList, parentLI.nextElementSibling);

nestedList = wrapper.querySelector(NESTED_LIST_QUERY);
}

return wrapper.innerHTML;
}

_prepareInsertBlankToBetweenSameList(html) {
return html.replace(/<\/(ul|ol)>(<br \/>|<br>){0,}<\1>/g, '</$1>:BLANK_LINE:<$1>');
/**
* make standard list out of arbitrary nesting list
* `<ul><li>text<ul><li>text2</li></ul></li></ul>` from
* `<ul><li>text</li><ul><li>text2</li></ul></ul>`
* @param {string} html string to convert
* @returns {string} converted HTML text
* @private
*/
_convertFromArbitraryNestingList(html) {
const NESTED_LIST_QUERY = 'ol > ol, ol > ul, ul > ol, ul > ul';
const wrapperDiv = document.createElement('div');
wrapperDiv.innerHTML = html;

let nestedList = wrapperDiv.querySelector(NESTED_LIST_QUERY);
while (nestedList !== null) {
let prevLI = nestedList.previousElementSibling;
while (prevLI.tagName !== 'LI') {
prevLI = prevLI.previousElementSibling;
}

prevLI.appendChild(nestedList);

nestedList = wrapperDiv.querySelector(NESTED_LIST_QUERY);
}

return wrapperDiv.innerHTML;
}

/**
Expand All @@ -205,34 +252,106 @@ class WwListManager {
*/
getLinesOfSelection(start, end) {
const lines = [];
let isEndPassed = false;
let isLastLine = false;
let needNext = true;
let nextLine;

if (domUtils.isTextNode(start)) {
start = $(start).parents('div').first().get(0);
start = $(start).parents(DIV_OR_LI).first().get(0);
}

if (domUtils.isTextNode(end)) {
end = $(end).parents('div').first().get(0);
end = $(end).parents(DIV_OR_LI).first().get(0);
}

for (let line = start; needNext; line = nextLine) {
if ($(line).is('DIV')) {
if ($(line).is(DIV_OR_LI)) {
lines.push(line);

if (line === end) {
isEndPassed = true;
isLastLine = true;
} else {
nextLine = this._getNextLine(line, end);
}
nextLine = line.nextElementSibling;
} else {
break;
}
needNext = nextLine && !isEndPassed;
needNext = nextLine && !isLastLine;
}

return lines;
}

/**
* get next line
* @param {Node} currentLine - current line node
* @param {Node} end - last node in selection
* @returns {Node} - next line node
* @private
*/
_getNextLine(currentLine, end) {
let nextLine = currentLine.nextElementSibling;

if (!nextLine) {
// current line was the last line in ul/ol
// while we have lines those has not been processed yet.
nextLine = currentLine.parentNode.nextElementSibling;
} else if ($(nextLine).is(UL_OR_OL)) {
// we don't sure firstChild is LI. arbtrary list can have another ol/ul
nextLine = nextLine.querySelector('li');
}

if ($(nextLine).is(DIV_OR_LI) || nextLine === end) {
return nextLine;
}

return this._getNextLine(nextLine);
}

/**
* merge to previous list
* consider remove this function when https://github.com/neilj/Squire/issues/294 resolved
* @param {HTMLLIElement} currentLine - current li element
* @ignore
*/
mergeList(currentLine) {
let currentList = currentLine.parentNode;
const prevList = currentList.previousElementSibling;
const nextList = currentList.nextElementSibling;

if (currentList.firstElementChild === currentLine) {
if (prevList && $(prevList).is(UL_OR_OL)) {
this._mergeList(currentList, prevList);
currentList = prevList;
}
}

if (currentList.lastElementChild === currentLine) {
if (nextList && $(nextList).is(UL_OR_OL)) {
this._mergeList(nextList, currentList);
}
}
}

/**
* merge list to targetList
* @param {HTMLOListElement|HTMLUListElement} list - list to merge
* @param {HTMLOListElement|HTMLUListElement} targetList - target list
* @ignore
*/
_mergeList(list, targetList) {
let listItem = list.firstElementChild;

if (targetList && $(targetList).is(UL_OR_OL)) {
while (listItem) {
const temp = listItem.nextElementSibling;
targetList.appendChild(listItem);
listItem = temp;
}

list.parentNode.removeChild(list);
}
}
}

module.exports = WwListManager;
74 changes: 0 additions & 74 deletions src/js/wwTaskManager.js
Expand Up @@ -3,8 +3,6 @@
* @author Sungho Kim(sungho-kim@nhnent.com) FE Development Team/NHN Ent.
*/

import domUtils from './domUtils';

const TASK_CLASS_NAME = 'task-list-item';
const TASK_ATTR_NAME = 'data-te-task';
const TASK_CHECKED_CLASS_NAME = 'checked';
Expand Down Expand Up @@ -165,78 +163,6 @@ class WwTaskManager {
$(node).removeClass('task-list');
});
}

/**
* Return lines in selection
* @param {Node} start Start element
* @param {Node} end End element
* @param {HTMLElement} body Editor body element
* @returns {Array.<HTMLElement>}
* @private
*/
getLinesOfSelection(start, end) {
const divOrLi = 'DIV,LI';
const lines = [];
let isEndPassed = false;
let needNext = true;
let nextLine;

if (domUtils.isTextNode(start)) {
start = $(start).parents('div').first().get(0);
}

if (domUtils.isTextNode(end)) {
end = $(end).parents('div').first().get(0);
}

for (let line = start; needNext; line = nextLine) {
if ($(line).is(divOrLi)) {
lines.push(line);

if (line === end || line.parentNode === end) {
isEndPassed = true;
}

const isStartInList = $(start).is('li') || ($(start).parent('li').length !== 0);
nextLine = this._getNextLine(line, isStartInList, isEndPassed);
} else {
break;
}

needNext = nextLine && !isEndPassed;
}

return lines;
}

/**
* Get next line element
* @param {HTMLElement} line Current line element
* @param {boolean} isStartInList Boolean value of start in list
* @param {boolean} isEndPassed Boolean value of end element passed
* @returns {HTMLElement|undefined}
* @private
*/
_getNextLine(line, isStartInList, isEndPassed) {
let nextLine;
if (isStartInList && line.parentNode.tagName === 'LI') {
const $nextLI = $(line).parent().next();

nextLine = $nextLI.children('div').first().get(0);

const hasNextLiHaveDivChild = $nextLI[0] && !nextLine;
const isLastLiInList = !$nextLI[0] && !nextLine;
if (hasNextLiHaveDivChild) {
nextLine = $nextLI.get(0);
} else if (isLastLiInList && !isEndPassed) {
nextLine = $(line).parents('ol,ul').first().next().get(0);
}
} else {
nextLine = line.nextElementSibling;
}

return nextLine;
}
}

module.exports = WwTaskManager;
20 changes: 17 additions & 3 deletions src/js/wysiwygCommands/decreaseDepth.js
Expand Up @@ -15,14 +15,15 @@ const CommandManager = require('../commandManager');
*/
const DecreaseDepth = CommandManager.command('wysiwyg', /** @lends HR */{
name: 'DecreaseDepth',

/**
* 커맨드 핸들러
* @param {WysiwygEditor} wwe WysiwygEditor instance
* Command Handler
* @param {WysiwygEditor} wwe WysiwygEditor instance
*/
exec(wwe) {
let $node = getCurrent$Li(wwe);

if ($node.length) {
if ($node.length && isExecutable($node)) {
wwe.getEditor().saveUndoState();

const nodeClasses = $node.attr('class');
Expand All @@ -34,10 +35,23 @@ const DecreaseDepth = CommandManager.command('wysiwyg', /** @lends HR */{
}
});

/**
* test if decrease the depth of given list item
* arbitrary list allows list item to be in any position
* while markdown spec does not
* @param {jQuery} $currentLiNode - jQuery list item element
* @returns {boolean} - true to executable
* @ignore
*/
function isExecutable($currentLiNode) {
return !($currentLiNode.next().is('OL,UL'));
}

/**
* Get list item element of current selection
* @param {object} wwe Wysiwyg editor instance
* @returns {jQuery}
* @ignore
*/
function getCurrent$Li(wwe) {
const range = wwe.getEditor().getSelection();
Expand Down

0 comments on commit b9a7788

Please sign in to comment.