diff --git a/public/resources/css/_translate.scss b/public/resources/css/_translate.scss index 8e51b7527d..f23032597f 100644 --- a/public/resources/css/_translate.scss +++ b/public/resources/css/_translate.scss @@ -1,8 +1,42 @@ -.original-english { - border-top: 1px dashed $regal; - &.hidden { - display: none !important; +.docs-content { + display: none; + .original-english { + border-top: 1px dashed $regal; + + &.hidden { + display: none !important; + } } + + h1.original-english { + margin-top: -($unit * 2); + } + + h2.original-english { + margin-top: -($unit * 1); + } + + h3.original-english { + margin-top: -($unit * 0); + } + + h3.original-english { + margin-top: -($unit * 0); + } + + p.original-english { + margin-top: -($unit * 3); + } + + li { + p { + margin: 0; + } + } +} + +.main-footer { + display: none; } td, th { diff --git a/public/translate/cn/translate.js b/public/translate/cn/translate.js index 1e6aef4720..31a455497d 100644 --- a/public/translate/cn/translate.js +++ b/public/translate/cn/translate.js @@ -1,150 +1,119 @@ // TODO: refactor me! var sourceVisible = localStorage.getItem('source-visible') === 'true'; - (function ($) { - addOriginalToggler(); - addSpacingBetweenCnAndEn(); + var content = document.querySelector('article.docs-content'); + var footer = document.querySelector('.main-footer'); - function addOriginalToggler() { - var nodes = document.querySelectorAll('p, li, h1, h2, h3, h4, h5, h6, header, a, button, small'); - _.each(nodes, function (node) { - var $node = $(node); + processContainer(content); - if (isLink(node) || isButton(node)) { - $node.on('click', function (event) { - event.stopPropagation(); + if (!sourceVisible) { + var nodes = document.querySelectorAll('.original-english'); + _.each(nodes, function (node) { + $(node).addClass('hidden'); }); - - if (/^http?s:\/\//.test($node.attr('href')) && !$node.attr('target')) { - $node.attr('target', '_blank'); - } - } - - var prevNode = node.previousElementSibling; - var $prevNode = $(prevNode); - - if (!prevNode) { - return; - } - - if (isTranslationResult(node, prevNode)) { - if ($prevNode.hasClass('nav-list-item')) { - return; - } - if (isPureEnglish($node.text()) && $node.text() !== $prevNode.text()) { - return; - } - - if (isPureEnglish($prevNode.text())) { - $node.attr('id', prevNode.id); - $node.addClass('translated'); - $node.addClass('translated-cn'); - $prevNode.removeAttr('id'); - $prevNode.addClass('original-english'); - if (!sourceVisible) { - $prevNode.addClass('hidden'); - } - if (!isLink(node) && !isButton(node)) { - var isDragging = false; - $node.on('mousedown', function(){ - $(window).on('mousemove', function(){ - isDragging = true; - $(window).unbind('mousemove'); - }); - }); - $prevNode.on('mousedown', function(){ - $(window).on('mousemove', function(){ - isDragging = true; - $(window).unbind('mousemove'); - }); - }); - $node.on('mouseup', function () { - var wasDragging = isDragging; - isDragging = false; - $(window).unbind('mousemove'); - if(!wasDragging){ - $prevNode.toggleClass('hidden'); - } - }); - $prevNode.on('mouseup', function () { - var wasDragging = isDragging; - isDragging = false; - $(window).unbind('mousemove'); - if(!wasDragging){ - $prevNode.addClass('hidden'); - } - }); - } - $node.after($prevNode); - } - } - }); - } - - function addSpacingBetweenCnAndEn($node) { - var nodes = document.querySelectorAll('.translated-cn'); - _.each(nodes, function (node) { - var text = node.innerHTML; - text = text.replace(/([\x20-\xff]+)/g, function (word) { - if (!word.replace(/\s/, '')) { - return ''; - } else if (/<[^>]*>/.test(word)) { - return ' ' + word + ' '; - } else { - return ' ' + word + ' '; - } - }); - node.innerHTML = text; - }); - } - - function isLink(node) { - return node.tagName.toUpperCase() === 'A'; - } - - function isButton(node) { - return node.tagName.toUpperCase() === 'BUTTON'; - } - - function isPureEnglish(text) { - // accept — , quotes, ® and façade too. - text = text.replace('在线例子', ''); - return /^[\1-\255—’“”ç®…à\u200B]*$/.test(text); - } - - function attributesToString(node) { - return _.chain(node.attributes) - .map(function (value) { - if (value.name === 'id') { - return ''; - } else { - return value.name + '=' + value.value; - } - }) - .sortBy() - .value() - .join(';'); - } - - function isClonedNode(node1, node2) { - return node1.tagName === node2.tagName && - attributesToString(node1) === attributesToString(node2); - } - - function indexOfSameType(node) { - var i = 0; - var aNode = node.parentNode.firstChild; - while (aNode !== node) { - ++i; - if (aNode.tagName !== node.tagName) { - i = 0; - } - aNode = aNode.nextElementSibling; } - return i; - } - function isTranslationResult(node, prevNode) { - return indexOfSameType(node) % 2 === 1 && isClonedNode(node, prevNode) && isPureEnglish(prevNode.innerText); - } + // restore + content.style.display = 'block'; + footer.style.display = 'block'; + + /** + * Process container recursively. + * @param container + */ + function processContainer(container) { + for (var i = 0; i < container.children.length; i++) { + var node = container.children[i]; + + // ignore example code. + if (node.classList.contains('code-example') || + node.tagName === 'CODE-EXAMPLE') { + continue; + } + + switch (node.tagName) { + case 'P': + case 'H1': + case 'H2': + case 'H3': + case 'H4': + case 'H5': + case 'H6': + case 'HEADER': + if (processBlock(node)) { + i++; + } + break; + case 'TD': + case 'TH': + processContainer(node); + return; // stop + default: + if (node.children.length > 0) { + processContainer(node); + // For
  • ...

  • , processes it as block. + if (node.children.length === 1) { + if (processBlock(node)) { + i++; + } + } + } + break; + } + } + } + + /** + * Process block elements. The first element is original english, the + * second element is translated one. + * @param current the first element. + * @returns {boolean} Is success? + */ + function processBlock(current) { + var sibling = current.nextElementSibling; + var $current = $(current); + var $sibling = $(sibling); + + if (sibling) { + if (isClonedNode(current, sibling)) { + if (isPureEnglish(current.textContent)) { + $current.addClass('original-english'); + $sibling.addClass('translated'); + $sibling.addClass('translated-cn'); + $sibling.after($current); + $sibling.on('click', function() { + $current.toggleClass('hidden'); + }); + return true; + } + + console.error('Error: ' + current.innerText); + } + } + + return false; + } + + function isPureEnglish(text) { + return !/\p{Han}/.test(text); + } + + function attributesToString(node) { + return _.chain(node.attributes) + .map(function (value) { + if (value.name === 'id' || value.name === 'class') { + return ''; + } else { + return value.name + '=' + value.value; + } + }) + .sortBy() + .value() + .join(';'); + } + + function isClonedNode(node1, node2) { + return node1.tagName === node2.tagName && + attributesToString(node1) === attributesToString(node2); + } })(angular.element);